For developers
Developer reference
Where a rule can be overridden in PHP, what the CSV and server-config exports look like, and why matching is not pluggable.
Overriding a match
One filter, at the moment a request has been matched and before the redirect is
sent. It receives the match and may change the destination, change the status code,
or cancel the redirect entirely by returning null.
<?php
// PLACEHOLDER — filter name and match array shape are not final.
add_filter(
'subset_redirector_match',
function ( ?array $match, string $request_path ): ?array {
// Logged-in editors see the real 404, so broken links get noticed.
if ( current_user_can( 'edit_posts' ) ) {
return null;
}
return $match;
},
10,
2
);
That example is the integration people actually want, and it is worth spelling out why: a site with a thousand redirects hides its own rot. Letting editors see the 404 is how the rot stays visible to the people who can fix it.
Planned for 1.0.0Changelog
A match filter is in the free version. Automatic redirects on slug change, and the chain and loop health check, are Pro.
CSV import and export
The import format is the export format, so a round trip is lossless and a spreadsheet is a legitimate editing tool.
source,destination,status,match_type,notes
/old-page,/new-page,301,exact,
/blog/2019/(.*),/archive/$1,301,regex,Old dated permalinks
/discontinued-widget,,410,exact,No replacement
A 410 row has an empty destination, which is the one thing about the format worth
knowing in advance: 410 is not a redirect, so there is nowhere to go.
Exporting to the web server
Rules that fire constantly should not fire in PHP. Hot rules render as server configuration so they are handled before WordPress boots:
# PLACEHOLDER — the exact generated form is not final.
# nginx
rewrite ^/old-page$ /new-page permanent;
# Apache
RewriteRule ^old-page$ /new-page [R=301,L]
The generated block is meant to be copied into your own configuration, not written
there by the plugin. A plugin that edits .htaccess in place is a plugin that can
take a site down from a settings screen, and WordPress core’s own experience of
doing exactly that is the argument.
What will deliberately not be extensible
Matching is not pluggable. The order in which exact, prefix and regex rules are tried is fixed, and there is no filter for it. Redirect matching is on the request path for every 404 on the site, and a hook there is a hook in the hot path — plus a site where the match order is custom is a site where nobody can reason about which rule won.
The 404 log is not a public table. It is aggregated, pruned and will change shape. Read it through an export endpoint (placeholder — not final) when one exists, and if you need an event when a miss is recorded, that is a reasonable request — open an issue.
Testing redirects
The test that catches real regressions asserts the status code as well as the
destination, because a rule that silently becomes a 302 still passes a test that
only looks at where it ended up:
curl -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' https://example.com/old-page
Expect 301 https://example.com/new-page. Note -o /dev/null and no -L: following
the redirect is how you miss the fact that there were three of them.