From superpowers-sage
Guides WordPress REST API endpoint creation with register_rest_route, WP_REST_Controller, authentication (JWT, Application Passwords), permissions, schema validation, debugging, and Acorn Routes comparison.
npx claudepluginhub codigodoleo/superpowers-sage --plugin superpowers-sageThis skill uses the workspace's default tool permissions.
Use this skill when the task involves creating, modifying, or debugging WordPress REST API endpoints, or when deciding between native REST and Acorn Routes for an API surface.
Builds, extends, and debugs WordPress REST API endpoints/routes using register_rest_route, WP_REST_Controller, schema/argument validation, permissions, response shaping, and custom fields/meta.
Guides WordPress capabilities, roles, and authorization in Sage/Acorn projects: add/remove roles/caps, custom CPTs, meta caps, current_user_can checks, ACF visibility.
Develops WordPress plugins with structure patterns, hooks, security (nonces, sanitization, prepared $wpdb queries), REST API, custom post types, and Settings API.
Share bugs, ideas, or general feedback.
Use this skill when the task involves creating, modifying, or debugging WordPress REST API endpoints, or when deciding between native REST and Acorn Routes for an API surface.
routes/web.php or routes/api.php)See references/acorn-coexistence.md for the full decision matrix.
Quick rule: use native REST for WordPress-ecosystem integration and Acorn Routes for application logic. Both can coexist in the same project.
Always use register_rest_route() inside a rest_api_init action. Never omit permission_callback.
See references/custom-endpoints.md for full examples including WP_REST_Controller pattern and JSON schema validation.
public function boot(): void
{
add_action('rest_api_init', [$this, 'registerRoutes']);
}
public function registerRoutes(): void
{
register_rest_route('myapp/v1', '/posts', [
'methods' => 'GET',
'callback' => [$this, 'getPosts'],
'permission_callback' => '__return_true',
]);
register_rest_route('myapp/v1', '/posts', [
'methods' => 'POST',
'callback' => [$this, 'createPost'],
'permission_callback' => fn() => current_user_can('edit_posts'),
'args' => $this->getCreatePostArgs(),
]);
}
See references/authentication.md for Application Passwords, cookie/nonce auth, and JWT patterns.
Quick reference:
X-WP-Nonce headerwp_set_current_user()// Expose a CPT in the REST API
register_post_type('event', [
'show_in_rest' => true,
'rest_base' => 'events',
]);
// Register a custom field on an existing endpoint
add_action('rest_api_init', function () {
register_rest_field('post', 'reading_time', [
'get_callback' => fn($post) => (int) get_post_meta($post['id'], '_reading_time', true),
'schema' => ['type' => 'integer', 'description' => 'Reading time in minutes'],
]);
});
| Anti-pattern | Problem | Correct approach |
|---|---|---|
| Closure in route callback | Cannot be cached; breaks serialization | Use class method reference [$this, 'method'] |
Missing permission_callback | Emits _doing_it_wrong; endpoint unprotected | Always include permission_callback |
| Returning raw arrays | Missing REST response headers | Use rest_ensure_response() |
| Hardcoded namespace version | Version changes require find-and-replace | Define as class constants |
| No schema definition | Clients cannot discover endpoint shape | Define get_item_schema() on the controller |
| Duplicating endpoint in both systems | Confusing and harder to maintain | One canonical endpoint per resource |
register_rest_route() call includes a permission_callbacktype, required, and sanitize_callback where applicableshow_in_rest => trueX-WP-Total, X-WP-TotalPages) are set on collection endpointsSee references/troubleshooting.md for detailed diagnosis of 401, CORS, rest_no_route, schema validation failures, and 404 on custom namespace.
Quick reference:
| Symptom | Cause | Fix |
|---|---|---|
| 404 on REST endpoint | Missing rest_api_init hook or permalink flush needed | Flush permalinks: lando wp rewrite flush |
rest_no_route error | Typo in namespace or route path | Check namespace and path match |
| 401 on authenticated endpoint | Nonce not sent or expired | Send X-WP-Nonce header |
CPT not in /wp/v2/ | show_in_rest not set | Add 'show_in_rest' => true |
rest_authentication_errors filters or rest_enabled overrides.