API routes
Modules expose SDK-native API endpoints by implementing HasApiRoutes.
- A module returns
ApiRouteDefinition[]fromgetApiRoutes(). - Each route path is local to the module.
- The runtime mounts those routes under
/api/modules/{slug}/....
This keeps route declarations portable across runtimes and avoids hard-coding full WordPress REST paths inside modules.
Prefer the durable portable contract shape first. Host runtimes own the final mount path, auth middleware, and request-routing behavior.
UI routes
Modules expose admin pages by implementing HasUiRoutes.
- A module returns
UiRouteDefinition[]fromgetUiRoutes(). - The runtime maps those definitions into admin-side entrypoints.
- Page-level request policy can also declare read-freshness defaults so modules express semantics rather than database topology.
Legacy bridge
The runtime still carries a compatibility bridge for legacy modules that rely on HasRestRoutes / raw WordPress REST patterns.
Treat that bridge as transitional. New module work should target HasApiRoutes and HasUiRoutes first.
Param rules and middleware
ApiRouteDefinition can declare:
- request methods
- middleware
- capability requirements
- parameter rules
The WordPress router adapts those definitions into WP REST registrations. Keep route paths local to the module and let the runtime add the canonical prefix.
Read freshness
When a route or page has stronger read-after-write requirements, prefer the portable readFreshness policy on the route or page declaration instead of leaking writer/replica flags into module code.