@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix content: <http://purl.org/rss/1.0/modules/content/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://lhero.org/portfolio/lh-url-redirects/>
  a sioc:Post ;
  dc:title "How it works" ;
  dcterms:identifier 152497 ;
  dc:modified "2026-10-25T18:35:41Z"^^xsd:dateTime ;
  dc:created "2026-10-25T18:35:41Z"^^xsd:dateTime ;
  sioc:link <https://lhero.org/portfolio/lh-url-redirects/how-it-works/> ;
  sioc:has_creator <https://lhero.org/author/1/#account> ;
  sioc:has_container <https://lhero.org/#posts> ;
  content:encoded """<ul class="lh_portfolio-meta"><li><strong>Part of:</strong> <a href="https://lhero.org/portfolio/lh-url-redirects/">LH URL Redirects</a></li></ul>
<h2 class="wp-block-heading">Where rules live</h2>



<p class="wp-block-paragraph">Every rule for every site is a row in one table on the main site, <code>{base_prefix}lh_url_redirects</code>. A rule is keyed on host and path rather than on a site ID, so a rule can belong to a domain no site is mapped to. Each row also records the network site its source belongs to (<code>blog_id</code>, 0 for an unmapped domain), purely for listing and filtering.</p>



<p class="wp-block-paragraph">The table is created on network activation, and on the next admin request if it is missing. Upgrades are keyed on <code>LH_Url_Redirects_Table::schema_version()</code>, stored in the network option <code>lh_url_redirects_schema_version</code>, never on the plugin version.</p>



<h2 class="wp-block-heading">When a rule fires</h2>



<ul class="wp-block-list">
<li><strong>404s on any site.</strong> On <code>template_redirect</code> at priority 9, so an explicit rule wins over WordPress&#8217;s own URL guessing in <code>redirect_canonical()</code>. A URL that resolves to real content is never redirected.</li>



<li><strong>Unmapped domains.</strong> Multisite sends a request for a domain with no site to the main site&#8217;s <code>wp-signup.php?new=&lt;host&gt;</code>. On <code>before_signup_header</code> the plugin looks up that host&#8217;s root rule. Only the host survives the bounce, so the path of the original request is lost: point a whole old domain at a new one with an exact <code>/</code> rule or a <code>/</code> prefix rule.</li>
</ul>



<h2 class="wp-block-heading">Matching</h2>



<ul class="wp-block-list">
<li>Scheme, port, query string, host case and trailing slashes are ignored, and the path is percent-decoded, so <code>https://Example.org/a%2Cb/</code> and <code>http://example.org/a,b</code> are the same source.</li>



<li>An <strong>exact</strong> rule matches one path. A <strong>prefix</strong> rule matches its path and everything below it (<code>/blog</code> matches <code>/blog/post</code> but not <code>/blogroll</code>); the prefix <code>/</code> matches the whole host.</li>



<li>An exact rule beats any prefix rule, and among prefix rules the longest wins.</li>
</ul>



<h2 class="wp-block-heading">Responses</h2>



<p class="wp-block-paragraph">301, 302, 303, 307 and 308 redirect to the rule&#8217;s target, which may be on any domain; the target&#8217;s host is allowed for that one redirect only, through <code>wp_safe_redirect()</code>. 410 keeps the theme&#8217;s 404 page but sends the Gone status, except on an unmapped domain, where there is no page to show and a minimal Gone page is sent instead. Each fired rule increments its hit count and records the time.</p>



<h2 class="wp-block-heading">Managing rules</h2>



<p class="wp-block-paragraph">There is no settings or admin screen. Rules are managed through the MCP abilities, which exist on the main site only and require <code>install_plugins</code>. Lookups are cached in a global object-cache group, cleared whenever a rule changes.</p>
"""^^rdf:XMLLiteral ;
  sioc:content """Part of: LH URL Redirects
Where rules live



Every rule for every site is a row in one table on the main site, {base_prefix}lh_url_redirects. A rule is keyed on host and path rather than on a site ID, so a rule can belong to a domain no site is mapped to. Each row also records the network site its source belongs to (blog_id, 0 for an unmapped domain), purely for listing and filtering.



The table is created on network activation, and on the next admin request if it is missing. Upgrades are keyed on LH_Url_Redirects_Table::schema_version(), stored in the network option lh_url_redirects_schema_version, never on the plugin version.



When a rule fires




404s on any site. On template_redirect at priority 9, so an explicit rule wins over WordPress&#8217;s own URL guessing in redirect_canonical(). A URL that resolves to real content is never redirected.



Unmapped domains. Multisite sends a request for a domain with no site to the main site&#8217;s wp-signup.php?new=&lt;host&gt;. On before_signup_header the plugin looks up that host&#8217;s root rule. Only the host survives the bounce, so the path of the original request is lost: point a whole old domain at a new one with an exact / rule or a / prefix rule.




Matching




Scheme, port, query string, host case and trailing slashes are ignored, and the path is percent-decoded, so https://Example.org/a%2Cb/ and http://example.org/a,b are the same source.



An exact rule matches one path. A prefix rule matches its path and everything below it (/blog matches /blog/post but not /blogroll); the prefix / matches the whole host.



An exact rule beats any prefix rule, and among prefix rules the longest wins.




Responses



301, 302, 303, 307 and 308 redirect to the rule&#8217;s target, which may be on any domain; the target&#8217;s host is allowed for that one redirect only, through wp_safe_redirect(). 410 keeps the theme&#8217;s 404 page but sends the Gone status, except on an unmapped domain, where there is no page to show and a minimal Gone page is sent instead. Each fired rule increments its hit count and records the time.



Managing rules



There is no settings or admin screen. Rules are managed through the MCP abilities, which exist on the main site only and require install_plugins. Lookups are cached in a global object-cache group, cleared whenever a rule changes.
""" ;
  sioc:topic <https://lhero.org/?taxonomy=author&term=cap-1> .

<https://lhero.org/author/1/#account> rdfs:seeAlso <https://lhero.org/author/1/?feed=lhrdf&format=turtle> .
<https://lhero.org/?taxonomy=author&term=cap-1> rdfs:seeAlso <https://lhero.org/?taxonomy=author&term=cap-1&feed=lhrdf&format=turtle> .
