Skip to content
This repository was archived by the owner on Feb 1, 2026. It is now read-only.

Commit 0253fb3

Browse files
committed
Add wp-rest-api skill
1 parent 534e72b commit 0253fb3

File tree

11 files changed

+284
-2
lines changed

11 files changed

+284
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Agent Skills solve this by giving AI assistants **expert-level WordPress knowled
2525
| **wp-block-development** | Gutenberg blocks: `block.json`, attributes, rendering, deprecations |
2626
| **wp-block-themes** | Block themes: `theme.json`, templates, patterns, style variations |
2727
| **wp-plugin-development** | Plugin architecture, hooks, settings API, security |
28+
| **wp-rest-api** | REST API routes/endpoints, schema, auth, and response shaping |
2829
| **wp-interactivity-api** | Frontend interactivity with `data-wp-*` directives and stores |
2930
| **wp-abilities-api** | Capability-based permissions and REST API authentication |
3031
| **wp-wpcli-and-ops** | WP-CLI commands, automation, multisite, search-replace |

docs/skill-set-v1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This repo currently includes:
77
- `wp-block-development`
88
- `wp-block-themes`
99
- `wp-plugin-development`
10+
- `wp-rest-api`
1011
- `wp-interactivity-api`
1112
- `wp-abilities-api`
1213
- `wp-wpcli-and-ops`
@@ -15,7 +16,6 @@ This repo currently includes:
1516

1617
Planned next skills (not yet implemented):
1718

18-
- `wp-rest-api`
1919
- `wp-build-tooling`
2020
- `wp-testing`
2121
- `wp-security`
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "Add a custom REST endpoint with permissions and schema",
3+
"skills": ["wordpress-router", "wp-project-triage", "wp-rest-api"],
4+
"query": "Add a REST endpoint /my-plugin/v1/reports that returns JSON data, requires manage_options, and validates a days query param (1-30).",
5+
"expected_behavior": [
6+
"Step 1: Run wordpress-router to classify repo kind",
7+
"Step 2: Run wp-project-triage for tooling",
8+
"Step 3: Register route on rest_api_init with namespace my-plugin/v1",
9+
"Step 4: Provide permission_callback using current_user_can('manage_options')",
10+
"Step 5: Define args with type/validate/sanitize for days param",
11+
"Step 6: Return data via rest_ensure_response or WP_REST_Response",
12+
"Step 7: Avoid wp_send_json and direct $_GET usage"
13+
],
14+
"success_criteria": [
15+
"Uses register_rest_route with a unique namespace",
16+
"Includes permission_callback (not missing)",
17+
"Validates and sanitizes days parameter",
18+
"Returns WP_REST_Response or rest_ensure_response",
19+
"Mentions authentication or nonce if needed"
20+
]
21+
}

skills/wordpress-router/references/decision-tree.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Route by intent even if repo kind is broad (like `wp-site`):
3434
- **Plugins / hooks / activation hook / uninstall / Settings API / admin pages**
3535
- Route → `wp-plugin-development`.
3636
- **REST endpoint / register_rest_route / permission_callback**
37-
- Route → `wp-rest-api` (planned).
37+
- Route → `wp-rest-api`.
3838
- **WP-CLI / wp-cli.yml / commands**
3939
- Route → `wp-wpcli-and-ops`.
4040
- **Build tooling / @wordpress/scripts / webpack / Vite / npm scripts**

skills/wp-rest-api/SKILL.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
name: wp-rest-api
3+
description: "Use when building, extending, or debugging WordPress REST API endpoints/routes: register_rest_route, WP_REST_Controller/controller classes, schema/argument validation, permission_callback/authentication, response shaping, register_rest_field/register_meta, or exposing CPTs/taxonomies via show_in_rest."
4+
compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Filesystem-based agent with bash + node. Some workflows require WP-CLI."
5+
---
6+
7+
# WP REST API
8+
9+
## When to use
10+
11+
Use this skill when you need to:
12+
13+
- create or update REST routes/endpoints
14+
- debug 401/403/404 errors or permission/nonce issues
15+
- add custom fields/meta to REST responses
16+
- expose custom post types or taxonomies via REST
17+
- implement schema + argument validation
18+
- adjust response links/embedding/pagination
19+
20+
## Inputs required
21+
22+
- Repo root + target plugin/theme/mu-plugin (path to entrypoint).
23+
- Desired namespace + version (e.g. `my-plugin/v1`) and routes.
24+
- Authentication mode (cookie + nonce vs application passwords vs auth plugin).
25+
- Target WordPress version constraints (if below 6.9, call out).
26+
27+
## Procedure
28+
29+
### 0) Triage and locate REST usage
30+
31+
1. Run triage:
32+
- `node skills/wp-project-triage/scripts/detect_wp_project.mjs`
33+
2. Search for existing REST usage:
34+
- `register_rest_route`
35+
- `WP_REST_Controller`
36+
- `rest_api_init`
37+
- `show_in_rest`, `rest_base`, `rest_controller_class`
38+
39+
If this is a full site repo, pick the specific plugin/theme before changing code.
40+
41+
### 1) Choose the right approach
42+
43+
- **Expose CPT/taxonomy in `wp/v2`:**
44+
- Use `show_in_rest => true` + `rest_base` if needed.
45+
- Optionally provide `rest_controller_class`.
46+
- Read `references/custom-content-types.md`.
47+
- **Custom endpoints:**
48+
- Use `register_rest_route()` on `rest_api_init`.
49+
- Prefer a controller class (`WP_REST_Controller` subclass) for anything non-trivial.
50+
- Read `references/routes-and-endpoints.md` and `references/schema.md`.
51+
52+
### 2) Register routes safely (namespaces, methods, permissions)
53+
54+
- Use a unique namespace `vendor/v1`; avoid `wp/*` unless core.
55+
- Always provide `permission_callback` (use `__return_true` for public endpoints).
56+
- Use `WP_REST_Server::READABLE/CREATABLE/EDITABLE/DELETABLE` constants.
57+
- Return data via `rest_ensure_response()` or `WP_REST_Response`.
58+
- Return errors via `WP_Error` with an explicit `status`.
59+
60+
Read `references/routes-and-endpoints.md`.
61+
62+
### 3) Validate/sanitize request args
63+
64+
- Define `args` with `type`, `default`, `required`, `validate_callback`, `sanitize_callback`.
65+
- Prefer JSON Schema validation with `rest_validate_value_from_schema` then `rest_sanitize_value_from_schema`.
66+
- Never read `$_GET`/`$_POST` directly inside endpoints; use `WP_REST_Request`.
67+
68+
Read `references/schema.md`.
69+
70+
### 4) Responses, fields, and links
71+
72+
- Do **not** remove core fields from default endpoints; add fields instead.
73+
- Use `register_rest_field` for computed fields; `register_meta` with `show_in_rest` for meta.
74+
- For `object`/`array` meta, define schema in `show_in_rest.schema`.
75+
- If you need unfiltered post content (e.g., ToC plugins injecting HTML), request `?context=edit` to access `content.raw` (auth required). Pair with `_fields=content.raw` to keep responses small.
76+
- Add related resource links via `WP_REST_Response::add_link()`.
77+
78+
Read `references/responses-and-fields.md`.
79+
80+
### 5) Authentication and authorization
81+
82+
- For wp-admin/JS: cookie auth + `X-WP-Nonce` (action `wp_rest`).
83+
- For external clients: application passwords (basic auth) or an auth plugin.
84+
- Use capability checks in `permission_callback` (authorization), not just “logged in”.
85+
86+
Read `references/authentication.md`.
87+
88+
### 6) Client-facing behavior (discovery, pagination, embeds)
89+
90+
- Ensure discovery works (`Link` header or `<link rel="https://api.w.org/">`).
91+
- Support `_fields`, `_embed`, `_method`, `_envelope`, pagination headers.
92+
- Remember `per_page` is capped at 100.
93+
94+
Read `references/discovery-and-params.md`.
95+
96+
## Verification
97+
98+
- `/wp-json/` index includes your namespace.
99+
- `OPTIONS` on your route returns schema (when provided).
100+
- Endpoint returns expected data; permission failures return 401/403 as appropriate.
101+
- CPT/taxonomy routes appear under `wp/v2` when `show_in_rest` is true.
102+
- Run repo lint/tests and any PHP/JS build steps.
103+
104+
## Failure modes / debugging
105+
106+
- 404: `rest_api_init` not firing, route typo, or permalinks off (use `?rest_route=`).
107+
- 401/403: missing nonce/auth, or `permission_callback` too strict.
108+
- `_doing_it_wrong` for missing `permission_callback`: add it (use `__return_true` if public).
109+
- Invalid params: missing/incorrect `args` schema or validation callbacks.
110+
- Fields missing: `show_in_rest` false, meta not registered, or CPT lacks `custom-fields` support.
111+
112+
## Escalation
113+
114+
If version support or behavior is unclear, consult the REST API Handbook and core docs before inventing patterns.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Authentication (summary)
2+
3+
## Cookie authentication (in-dashboard / same-site)
4+
5+
- Standard for wp-admin and theme/plugin JS.
6+
- Requires a REST nonce (`wp_rest`) sent as `X-WP-Nonce` header or `_wpnonce` param.
7+
- If the nonce is missing, the request is treated as unauthenticated even if cookies exist.
8+
9+
## Application Passwords (external clients)
10+
11+
- Available in WordPress 5.6+.
12+
- Use HTTPS + Basic Auth with the application password.
13+
- Recommended over the legacy Basic Auth plugin.
14+
15+
## Auth plugins
16+
17+
- OAuth 1.0a or JWT plugins are common for external apps.
18+
- Use only if required; follow plugin docs and security guidance.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Custom Content Types (summary)
2+
3+
## Custom post types
4+
5+
- Set `show_in_rest => true` in `register_post_type()` to expose in `wp/v2`.
6+
- Use `rest_base` to change the route slug.
7+
- Optionally set `rest_controller_class` (must extend `WP_REST_Controller`).
8+
9+
## Custom taxonomies
10+
11+
- Set `show_in_rest => true` in `register_taxonomy()`.
12+
- Use `rest_base` and optional `rest_controller_class` (default `WP_REST_Terms_Controller`).
13+
14+
## Adding REST support to existing types
15+
16+
- Use `register_post_type_args` or `register_taxonomy_args` filters to enable `show_in_rest` for types you do not control.
17+
18+
## Discovery links for custom controllers
19+
20+
- If you use a custom controller class, use `rest_route_for_post` or `rest_route_for_term` filters to map objects to routes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Discovery and Global Parameters (summary)
2+
3+
## API discovery
4+
5+
- REST API root is discovered via the `Link` header: `rel="https://api.w.org/"`.
6+
- HTML pages also include a `<link rel="https://api.w.org/" href="...">` element.
7+
- For non-pretty permalinks, use `?rest_route=/`.
8+
9+
## Global parameters
10+
11+
- `_fields` limits response fields (supports nested meta keys).
12+
- `_embed` includes linked resources in `_embedded`.
13+
- `_method` or `X-HTTP-Method-Override` allows POST to simulate PUT/DELETE.
14+
- `_envelope` puts headers/status in the response body.
15+
- `_jsonp` enables JSONP for legacy clients.
16+
17+
## Pagination
18+
19+
- Collections accept `page`, `per_page` (1-100), and `offset`.
20+
- Pagination headers: `X-WP-Total` and `X-WP-TotalPages`.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Responses and Fields (summary)
2+
3+
## Do not remove core fields
4+
5+
- Removing or changing core fields breaks clients (including wp-admin).
6+
- Prefer adding new fields or using `_fields` to limit response size.
7+
8+
## register_rest_field
9+
10+
- Use for computed or custom fields.
11+
- Provide `get_callback`, optional `update_callback`, and `schema`.
12+
- Register on `rest_api_init`.
13+
14+
## Raw vs rendered content
15+
16+
- For posts, `content.rendered` reflects filters (plugins like ToC inject HTML).
17+
- Use `?context=edit` (authenticated) to access `content.raw`.
18+
- Combine with `_fields=content.raw` when you only need the editable body.
19+
20+
## register_meta / register_post_meta / register_term_meta
21+
22+
- Use when the data is stored as meta.
23+
- Set `show_in_rest => true` to expose under `.meta`.
24+
- For `object` or `array` types, provide a JSON schema in `show_in_rest.schema`.
25+
26+
## Links and embedding
27+
28+
- Add links with `WP_REST_Response::add_link( $rel, $href, $attrs )`.
29+
- Use `embeddable => true` to allow `_embed`.
30+
- Use IANA rels or a custom URI relation; CURIEs can be registered via `rest_response_link_curies`.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Routes and Endpoints (summary)
2+
3+
## Registering routes
4+
5+
- Register routes on the `rest_api_init` hook with `register_rest_route( $namespace, $route, $args )`.
6+
- A **route** is the URL pattern; an **endpoint** is the method + callback bound to that route.
7+
- For non-pretty permalinks, the route is accessed via `?rest_route=/namespace/route`.
8+
9+
## Namespacing
10+
11+
- Always namespace routes (`vendor/v1`).
12+
- **Do not** use the `wp/*` namespace unless you are targeting core.
13+
14+
## Methods
15+
16+
- Use `WP_REST_Server::READABLE` (GET), `CREATABLE` (POST), `EDITABLE` (PUT/PATCH), `DELETABLE` (DELETE).
17+
- Multiple endpoints can share a route, one per method.
18+
19+
## permission_callback (required)
20+
21+
- Always provide `permission_callback`.
22+
- Public endpoints should use `__return_true`.
23+
- For restricted endpoints, use capability checks (`current_user_can`) or object-level authorization.
24+
- Missing `permission_callback` emits a `_doing_it_wrong` notice in modern WP.
25+
26+
## Arguments
27+
28+
- Register `args` to validate and sanitize inputs.
29+
- Use `type`, `required`, `default`, `validate_callback`, `sanitize_callback`.
30+
- Access params via the `WP_REST_Request` object, not `$_GET`/`$_POST`.
31+
32+
## Return values
33+
34+
- Return data via `rest_ensure_response()` or a `WP_REST_Response`.
35+
- Return `WP_Error` with a `status` in `data` for error responses.
36+
- Do not call `wp_send_json()` in REST callbacks.

0 commit comments

Comments
 (0)