Repository navigation
feat(router): per-route and group REST permission callbacks - #17
Merged
Merged
Conversation
APIRouter registered every REST route with permission_callback => '__return_true', leaving middleware as the only gate. WordPress.org reviewers reject that for privileged routes, and WordPress cannot answer 401/403 before the callback runs. RouteBase::permission() sets a callback for a whole group and RouteRegister::permission() overrides it per route. Routes without one keep '__return_true', so existing consumers are unchanged. Assisted-By: AI
Route attributes declared inside a group (permission, middleware) were dropped, nested groups ignored their parent and reset the outer group on close, and a throwing group callback leaked its state. Assisted-By: AI
Each RouteBase now records the group it was declared in and resolves prefix, middleware, permission, noAuth and ignoreToken through that parent at read time. Routes register against their own RouteBase, so attributes set inside a group are kept, and group() restores the enclosing group in a finally block. Nested prefixes now join (admin/inner) instead of the inner one replacing the outer. Assisted-By: AI
csemazharul
approved these changes
Oct 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
APIRouterregisters every REST route withpermission_callback => '__return_true', so middleware is the only gate on privileged routes. WordPress.org plugin reviewers reject that pattern, and WordPress can't answer 401/403 before the callback runs.What
RouteBase::permission(callable)sets a permission callback for a whole group (Route::group(...)->permission(...)).RouteRegister::permission(callable)overrides it for a single route.APIRouterregisters$route->getPermissionCallback(): the route's own, then the group's, then'__return_true'. Routes that don't opt in behave exactly as before.Group inheritance fix
Permission inside groups exposed a pre-existing
RouteBasebug that affected prefix and middleware too:Route::permission(...)->get(...)(or->middleware(...)) declared inside a group was dropped: the route registered against the group instead of its ownRouteBase.null, so later routes in the outer group became ungrouped. A throwing group callback leaked its group.Each
RouteBasenow records the group it was declared in and resolves prefix, middleware, permission,noAuthandignoreTokenthrough that parent when read;group()restores the enclosing group in afinally. Behaviour change: nested prefixes join (admin/inner) instead of the inner one replacing the outer, and a prefix set on a route inside a group is no longer lost.Tests
TransportRegistrationTestcovers the public default, group propagation to every method, and per-route override.RouteDefinitionTestcovers attributes on routes inside a group, nested inheritance with sibling restore, and a throwing group callback.composer test(268), php-cs-fixer andcomposer compatpass.Needed by the PaymentForm plugin's WordPress.org submission; it will move from
^2.4to the release that carries this.🤖 Generated with Claude Code