Skip to content

fix(router): match StaticRouter root route on the page root - #21

Merged
csemazharul merged 3 commits into
mainfrom
fix/static-router-root-route
Oct 28, 2026
Merged

csemazharul merged 3 commits into
mainfrom
fix/static-router-root-route

Conversation

@abdul-kaioum

@abdul-kaioum abdul-kaioum commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Fixes #20 (regression from 2.4.0, introduced in 851a497).

Problem

requestPath() trims slashes off WP::$request, so /portal/ arrives as /portal. isRouteMatched() still built portal/ for a / route, compiling to ~^/portal//?$~, which requires a slash after the page name. Root routes stopped matching and plugins lost their SSR output (title, meta, prerendered content) on the page root, e.g. the Bit Connect portal home. Empty-path routes inside a prefix group (prefix('account')->get('/')) broke the same way.

Fix

Route paths are joined by a private joinPath() helper that skips empty segments, used by both routePath() and isRouteMatched(). A root route now compiles to ~^/portal/?$~ and matches with or without the trailing slash. Rewrite rules are unchanged (RewriteRuleSet::addPath() already trims).

Tests

8 new cases in StaticRoutingTest:

  • Regression (fail on main): root via parsed WP::$request, root on a subdirectory install (/blog), root via the REQUEST_URI fallback, empty path inside a prefix group.
  • Guards: trailing-slash root URI (2.4.0 behaviour), root does not match deeper paths, root does not match a page sharing its name prefix (landing-archive), root does not shadow sibling routes.

Full suite: 313 tests pass; lint and compat pass.

CI fix (also red on main)

main fails the composer rector step since #19 landed after the rector 2.7 bump (#18). Two chore commits add the return/param types rector 2.7 + phpstan 2.3 require: InteractsWithHeaders (unreleased, BC-safe) and private RouteRegister::processParameters(). Merging this PR turns main green again.

🤖 Generated with Claude Code

851a497 made requestPath() trim slashes off WP::$request, so /portal/
arrives as /portal. isRouteMatched() still built "portal/" for a root
route, compiling to ~^/portal//?$~, which needs a slash after the page
name. Root routes, and empty paths inside a prefix group, stopped
matching and SSR content was lost on the page root.

Route paths are now joined by joinPath(), which skips empty segments,
so a root route compiles to ~^/portal/?$~ and matches with or without
the trailing slash.

Fixes #20

Assisted-By: AI
InteractsWithHeaders landed (#19) after the rector 2.7 bump (#18), so
the CI rector dry-run has failed on main since. The types are safe to
add: the trait is unreleased, so no consumer overrides exist yet.

Assisted-By: AI
Rector 2.7 with phpstan 2.3 on PHP 8.4+ infers the array type from the
getParameters() callers and fails the CI dry-run. The method is
private, so the type is BC-safe.

Assisted-By: AI
@csemazharul
csemazharul merged commit 44d2e7f into main Oct 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StaticRouter: the root route (/) does not match on main

2 participants