wp-rest-api

WordPress REST endpoint development and debugging. Always-active rules when working with REST routes, API authentication, or data exposure via JSON.

25 stars

Best use case

wp-rest-api is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

WordPress REST endpoint development and debugging. Always-active rules when working with REST routes, API authentication, or data exposure via JSON.

Teams using wp-rest-api should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/wp-rest-api/SKILL.md --create-dirs "https://raw.githubusercontent.com/ComeOnOliver/skillshub/main/skills/alessioarzenton/claude-code-wp-toolkit/wp-rest-api/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/wp-rest-api/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How wp-rest-api Compares

Feature / Agentwp-rest-apiStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

WordPress REST endpoint development and debugging. Always-active rules when working with REST routes, API authentication, or data exposure via JSON.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# WordPress REST API

Skill for creating, managing, and debugging REST endpoints in WordPress 6.x+. Covers route registration, authentication, input validation, security, and integration with CPTs/taxonomies.

## When to use

Apply this skill when the task involves:

- Creating or modifying custom REST routes and endpoints
- Exposing Custom Post Types or taxonomies via REST
- Resolving authentication/authorization errors (401, 403, 404)
- Adding custom fields to REST responses
- Defining validation rules and JSON schemas
- Customizing response structure, pagination, links

## Prerequisites

Before starting, verify:

- Path of the plugin/theme/mu-plugin where routes will be registered
- Desired namespace and version (e.g., `{{TEXT_DOMAIN}}/v1`)
- Authentication strategy (cookie+nonce for admin, application passwords for external clients)
- Minimum WordPress version of the project

## Procedure

### 1) Detecting existing implementations

Before creating new endpoints, search the codebase:

```
register_rest_route    → custom routes already registered
WP_REST_Controller     → extended controllers
rest_api_init          → registration hooks
show_in_rest           → exposed CPTs/taxonomies
register_rest_field    → custom fields added
```

Check for namespace conflicts and registration patterns already in use.

### 2) Choosing the approach

| Scenario | Approach |
|----------|----------|
| Expose a CPT or taxonomy | `'show_in_rest' => true` in the CPT registration |
| Add fields to existing endpoints | `register_rest_field()` or `register_meta()` with `show_in_rest` |
| Custom logic (calculations, aggregations, actions) | `register_rest_route()` with a dedicated handler |
| Full CRUD endpoint | Extend `WP_REST_Controller` |

### 3) Secure endpoint registration

**Mandatory rules**:

```php
add_action('rest_api_init', function () {
    register_rest_route('{{TEXT_DOMAIN}}/v1', '/items', [
        'methods'             => WP_REST_Server::READABLE,  // Use constants, not strings
        'callback'            => 'handle_get_items',
        'permission_callback' => 'check_items_permission',  // MANDATORY — never '__return_true' in production if data is sensitive
        'args'                => get_items_args_schema(),
    ]);
});
```

- **Unique namespace**: `{{TEXT_DOMAIN}}/v1` — never register under `wp/v2`
- **`permission_callback` always present**: WordPress 5.5+ logs a `_doing_it_wrong` if missing
- **HTTP constants**: `WP_REST_Server::READABLE`, `::CREATABLE`, `::EDITABLE`, `::DELETABLE`
- **Response**: always return `rest_ensure_response()` or `new WP_REST_Response($data, $status)`

### 4) Argument validation and sanitization

Define the schema for every argument — never access `$_GET`/`$_POST` directly:

```php
function get_items_args_schema(): array {
    return [
        'per_page' => [
            'type'              => 'integer',
            'default'           => 10,
            'minimum'           => 1,
            'maximum'           => 100,
            'sanitize_callback' => 'absint',
            'validate_callback' => 'rest_validate_request_arg',
        ],
        'search' => [
            'type'              => 'string',
            'sanitize_callback' => 'sanitize_text_field',
        ],
        'status' => [
            'type'              => 'string',
            'enum'              => ['aperto', 'chiuso', 'in_arrivo'],
            'default'           => 'aperto',
        ],
    ];
}
```

- Use JSON Schema `type`: `string`, `integer`, `boolean`, `array`, `object`
- Add `enum` for allowed values, `minimum`/`maximum` for ranges
- `sanitize_callback` cleans the data, `validate_callback` rejects it if invalid

### 5) Adding custom fields to responses

**For ACF/post meta metadata** — expose via `register_meta()`:

```php
register_meta('post', 'importo_bando', [
    'object_subtype' => 'bando',
    'type'           => 'number',
    'single'         => true,
    'show_in_rest'   => true,
    'auth_callback'  => function () {
        return current_user_can('edit_posts');
    },
]);
```

**For computed values** — use `register_rest_field()`:

```php
register_rest_field('bando', 'stato_calcolato', [
    'get_callback' => function ($object) {
        return calcola_stato_bando($object['id']);
    },
    'schema' => [
        'type'        => 'string',
        'description' => 'Automatically calculated bando status',
        'context'     => ['view', 'edit'],
    ],
]);
```

- Extend existing responses, do not remove fields
- Set `context` to control where the field appears (`view`, `edit`, `embed`)

### 6) Authentication and authorization

| Context | Method | Notes |
|---------|--------|-------|
| JavaScript in wp-admin | Cookie + `X-WP-Nonce` | `wp_create_nonce('wp_rest')` — automatic with `wp.apiFetch` |
| External apps / CI | Application Passwords | Dedicated WP user with minimal capabilities |
| Authentication plugins | JWT / OAuth | Use established plugins, do not reinvent |

**`permission_callback`** — always check capabilities, not roles:

```php
function check_items_permission(WP_REST_Request $request): bool|WP_Error {
    if (!current_user_can('edit_posts')) {
        return new WP_Error(
            'rest_forbidden',
            __('Permesso negato.', '{{TEXT_DOMAIN}}'),
            ['status' => 403]
        );
    }
    return true;
}
```

- Public endpoints (reading bandi, FAQ): `'permission_callback' => '__return_true'`
- Write endpoints: **always** capability check
- Never trust the user role alone — use `current_user_can()`

### 7) Client experience

- **Discovery**: your endpoints appear in `/wp-json/{{TEXT_DOMAIN}}/v1`
- **Field filtering**: support `?_fields=id,title,stato` to reduce payload
- **Embed**: support `?_embed` to include related resources inline
- **Pagination**: respect `X-WP-Total`, `X-WP-TotalPages` headers; maximum 100 per page
- **Cache**: add `Cache-Control` headers for high-traffic public endpoints

## Verification checklist

- [ ] The REST index (`/wp-json/`) shows your namespace
- [ ] `OPTIONS` on routes returns the schema
- [ ] Responses follow the expected format (data, HTTP codes, headers)
- [ ] Unauthenticated requests return `401` on protected endpoints
- [ ] Requests from users without permissions return `403`
- [ ] Invalid parameters return `400` with a clear message
- [ ] CPTs with `show_in_rest` appear under `wp/v2`
- [ ] The project build succeeds after changes

## Common errors and solutions

| Problem | Likely cause | Solution |
|---------|-------------|----------|
| 404 on the endpoint | `rest_api_init` hook not executed, wrong route name, permalinks not enabled | Verify the code is loaded; enable pretty permalinks; check the namespace |
| 401 / Cookie nonce mismatch | Nonce missing or expired in the JS request | Use `wp.apiFetch` which handles the nonce automatically, or pass `X-WP-Nonce` in the header |
| 403 Forbidden | `permission_callback` rejects; user without capability | Verify the required capability and user role |
| Custom field missing | `show_in_rest` not set, `register_meta` without `object_subtype` | Add `show_in_rest => true` and specify the subtype |
| Schema not validated | `validate_callback` not defined or not used | Use `rest_validate_request_arg` as callback |
| Corrupted serialized data | `register_meta` of type `array`/`object` without `show_in_rest.schema` | Define the full schema in `show_in_rest['schema']` |

## What NOT to do

- **Do not** register routes under the `wp/v2` namespace — it is reserved for core
- **Do not** access `$_GET`, `$_POST`, `$_REQUEST` — use `$request->get_param()` or `$request->get_json_params()`
- **Do not** return `echo`/`die()` — always return a `WP_REST_Response` or `WP_Error` object
- **Do not** omit `permission_callback` — even if the endpoint is public, use `'__return_true'`
- **Do not** build SQL manually — use `$wpdb->prepare()` if you need direct queries
- **Do not** expose sensitive data (user emails, password hashes) without authorization checks

Related Skills

rest-endpoint-designer

25
from ComeOnOliver/skillshub

Rest Endpoint Designer - Auto-activating skill for API Development. Triggers on: rest endpoint designer, rest endpoint designer Part of the API Development skill category.

generating-rest-apis

25
from ComeOnOliver/skillshub

Generate complete REST API implementations from OpenAPI specifications or database schemas. Use when generating RESTful API implementations. Trigger with phrases like "generate REST API", "create RESTful API", or "build REST endpoints".

firestore-operations-manager

25
from ComeOnOliver/skillshub

Manage Firebase/Firestore operations including CRUD, queries, batch processing, and index/rule guidance. Use when you need to create/update/query Firestore documents, run batch writes, troubleshoot missing indexes, or plan migrations. Trigger with phrases like "firestore operations", "create firestore document", "batch write", "missing index", or "fix firestore query".

firestore-index-creator

25
from ComeOnOliver/skillshub

Firestore Index Creator - Auto-activating skill for GCP Skills. Triggers on: firestore index creator, firestore index creator Part of the GCP Skills skill category.

encryption-at-rest-checker

25
from ComeOnOliver/skillshub

Encryption At Rest Checker - Auto-activating skill for Security Advanced. Triggers on: encryption at rest checker, encryption at rest checker Part of the Security Advanced skill category.

context-management-context-restore

25
from ComeOnOliver/skillshub

Use when working with context management context restore

code-refactoring-context-restore

25
from ComeOnOliver/skillshub

Use when working with code refactoring context restore

azure-speech-to-text-rest-py

25
from ComeOnOliver/skillshub

Azure Speech to Text REST API for short audio (Python). Use for simple speech recognition of audio files up to 60 seconds without the Speech SDK. Triggers: "speech to text REST", "short audio transcription", "speech recognition REST API", "STT REST", "recognize speech REST". DO NOT USE FOR: Long audio (>60 seconds), real-time streaming, batch transcription, custom speech models, speech translation. Use Speech SDK or Batch Transcription API instead.

rest-patterns

25
from ComeOnOliver/skillshub

Quick reference for RESTful API design patterns, HTTP semantics, caching, and rate limiting. Triggers on: rest api, http methods, status codes, api design, endpoint design, api versioning, rate limiting, caching headers.

Restic

25
from ComeOnOliver/skillshub

## Overview

Restate

25
from ComeOnOliver/skillshub

## Overview

GCP Firestore

25
from ComeOnOliver/skillshub

Cloud Firestore is a flexible, scalable NoSQL document database. It supports real-time synchronization, offline access, and scales automatically. Available in Native mode (real-time + offline) and Datastore mode (server-only, higher throughput).