Skip to main content

v0.4.0

Released on the main branch as Composer tag v0.4.0.

Upgrade summary

{
"require": {
"better-route/better-route": "^0.4.0"
}
}

The single behavioral change is write routes registered on the raw Router deny by default unless intent is declared. GET is unchanged. Resource and Woo endpoints are unaffected — they already enforce their own policies.

Security and route intent

  • Write methods deny-by-default. POST, PUT, PATCH, and DELETE routes registered on the raw Router without an explicit permission callback now fail with 403 at the WordPress permission layer. GET stays public by default.
  • Explicit route-intent helpers on RouteBuilder:
    • protectedByMiddleware(string|array|null $security = null) — defer authorization to better-route middleware (e.g. JwtAuthMiddleware, BearerTokenAuthMiddleware). The optional argument is propagated as the operation-level OpenAPI security (string scheme name or [['scheme' => [...scopes]]] array).
    • publicRoute() — mark a route as intentionally public; also clears the operation-level OpenAPI security so it overrides any global scheme.

OpenAPI

  • Per-operation security: [] overrides globalSecurity. Setting an empty security array on a route's meta drops it from the document's global security requirement (useful for public health checks, webhooks, or auth endpoints inside an otherwise authenticated API). RouteBuilder::publicRoute() writes this automatically.

CI / packaging

  • CI Composer cache key now hashes composer.json. composer.lock is export-ignored in .gitattributes, so it is no longer present in dist archives.
  • .gitignore is also excluded from the dist archive.

Migration

If you have raw Router write routes that previously relied on the implicit "allow all" default, set explicit intent on each:

$r->post('/articles', $handler)
->permission(static fn () => current_user_can('edit_posts'));

$r->post('/secure/articles', $handler)
->protectedByMiddleware('bearerAuth');

$r->post('/webhooks/intake', $handler)
->publicRoute();

Resource-backed endpoints already enforce policies via ResourcePolicy and need no change.

Breaking change checklist

ChangeAction
Raw Router write routes deny-by-defaultAdd ->permission(), ->protectedByMiddleware(), or ->publicRoute() to every POST/PUT/PATCH/DELETE route registered without an explicit permission callback