Generated banner for Wp Abilities API
Generated logo for Wp Abilities API

Wp Abilities API

WordPressOfficialPublished by WordPress

  • Skill
  • Tool integration
  • Software development
  • GPL-2.0-or-later
  • No issues found

From the author

Use when working with the WordPress Abilities API (wp_register_ability, wp_register_ability_category, /wp-json/wp-abilities/v1/*, @wordpress/abilities) including defining abilities, categories, meta, REST exposure, and permissions checks for clients.
— the description by WordPress

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured approach to working with the WordPress Abilities API. It covers the registration of abilities and categories in PHP, exposing them via the REST API, and consuming them in JavaScript using @wordpress/abilities. The documentation emphasizes a layered architecture—distinguishing between domain capabilities and their projections—to ensure stable, transport-neutral plugin contracts that remain maintainable as consumer requirements evolve.

What it does

  • Registers abilities and categories using the WordPress Abilities API.
  • Exposes domain capabilities through the REST API for client consumption.
  • Provides patterns for delegating ability execution to existing REST controllers.
  • Offers guidance on grouping heuristics to avoid atomic-ability bloat.
  • Defines standard error vocabulary for consistent agent-based error handling.
  • Facilitates client-side ability consumption via @wordpress/abilities.

When to use it

  • When adding new capabilities that should be discoverable by agents or external clients.
  • When refactoring existing REST endpoints into a more stable, action-oriented ability contract.
  • When building features that require consistent permission checks across different transport layers.
  • When debugging issues where abilities are not appearing in REST responses or client-side registries.

Advantages

  • Promotes a stable, transport-neutral domain layer that survives UI or consumer changes.
  • Reduces boilerplate by providing patterns for delegating to existing controller logic.
  • Ensures consistent error handling and input validation across the plugin ecosystem.
  • Improves discoverability of plugin actions for AI agents and automated workflows.

Usage examples

“Register a new ability for listing user orders in my plugin.”
The agent will guide you through defining the ability ID, category, and meta, ensuring it is registered via the correct hooks and exposed in the REST API.
“My ability is not showing up in the REST API; how do I debug this?”
The agent will help you verify the registration hook, check for the show_in_rest meta flag, and confirm the namespace and route configuration.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/wordpress/wp-abilities-api/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip wp-abilities-api.zip -d .agents/skills

Documentation by WordPress

WP Abilities API

When to use

Use this skill when the task involves:

  • registering abilities or ability categories in PHP,

  • exposing abilities to clients via REST (wp-abilities/v1),

  • consuming abilities in JS (notably @wordpress/abilities),

  • diagnosing “ability doesn’t show up” / “client can’t see ability” / “REST returns empty”.

Inputs required

  • Repo root (run wp-project-triage first if you haven’t).

  • Target WordPress version(s) and whether this is WP core or a plugin/theme.

  • Where the change should live (plugin vs theme vs mu-plugin).

Procedure

Before deciding what to register, read references/domain-vs-projection.md — abilities live at the domain capability layer; MCP / Command Palette / REST exposure is a projection. Registration shape and exposure shape are different decisions, and conflating them forces re-registration every time a consumer's constraints change.

1) Confirm availability and version constraints
  • If this is WP core work, check signals.isWpCoreCheckout and versions.wordpress.core.

  • If the project targets WP < 6.9, you may need the Abilities API plugin/package rather than relying on core.

2) Find existing Abilities usage

Search for these in the repo:

  • wp_register_ability(

  • wp_register_ability_category(

  • wp_abilities_api_init

  • wp_abilities_api_categories_init

  • wp-abilities/v1

  • @wordpress/abilities

If none exist, decide whether you’re introducing Abilities API fresh (new registrations + client consumption) or only consuming.

3) Register categories (optional)

If you need a logical grouping, register an ability category early (see references/php-registration.md).

4) Register abilities (PHP)

For grouping decisions (how many abilities to register, and where to put filters vs. new ability names), read references/grouping-heuristic.md first — it keeps you from shipping one atomic ability per REST operation.

To avoid drift between the ability and the existing UI / REST code path, see references/shared-core-service.md — abilities, REST handlers, CLI commands, and UI controllers should be thin adapters over a shared service. The reference also covers the metric trap (REST handlers that emit usage telemetry) and the AGENTS.md rule for keeping registrations in sync when underlying code paths change.

For shared helper patterns when multiple execute callbacks delegate to existing REST controllers, see references/plugin-family-patterns.md (identify the shared-API-client vs zero-arg-controllers shape) and references/delegate-helper-pattern.md (one helper shape that works, and when not to use it).

For standardized WP_Error codes that let agents reason about retry vs. escalation, see references/error-code-vocabulary.md.

Implement the ability in PHP registration with:

  • stable id (namespaced),

  • label/description,

  • category,

  • meta:

    • add readonly: true when the ability is informational,

    • set show_in_rest: true for abilities you want visible to clients.

Use the documented init hooks for Abilities API registration so they load at the right time (see references/php-registration.md).

5) Confirm REST exposure
  • Verify the REST endpoints exist and return expected results (see references/rest-api.md).

  • If the client still can’t see the ability, confirm meta.show_in_rest is enabled and you’re querying the right endpoint.

6) Consume from JS (if needed)
  • Prefer @wordpress/abilities APIs for client-side access and checks.

  • Ensure build tooling includes the dependency and the project’s build pipeline bundles it.

Verification

  • wp-project-triage indicates signals.usesAbilitiesApi: true after your change (if applicable).

  • REST check (in a WP environment): endpoints under wp-abilities/v1 return your ability and category when expected.

  • If the repo has tests, add/update coverage near:

    • PHP: ability registration and meta exposure

    • JS: ability consumption and UI gating

Failure modes / debugging

  • Ability never appears:

    • registration code not running (wrong hook / file not loaded),

    • missing meta.show_in_rest,

    • incorrect category/ID mismatch.

  • REST shows ability but JS doesn’t:

    • wrong REST base/namespace,

    • JS dependency not bundled,

    • caching (object/page caches) masking changes.

  • Execute callback returns unexpected errors or silently ignores input:

    • input_schema defaults aren't being applied, pagination key drift between the ability and the backing, or empty()-based ID validation — see references/input-schema-gotchas.md.

Escalation

  • If you’re uncertain about version support, confirm target WP core versions and whether Abilities API is expected from core or as a plugin.

  • For canonical details, consult:

    • references/rest-api.md

    • references/php-registration.md

Files

references/error-code-vocabulary.md

Error code vocabulary

Every WP_Error returned from an ability's execute callback should use a code drawn from this small vocabulary. A consistent vocabulary lets the agent (or the caller in your automation) build retry and recovery logic that matches on codes instead of parsing error messages.

Why standardized codes matter

Agents that orchestrate multiple abilities need to know: "did this fail because of my input, or because something downstream is unreachable?" The answer drives retry strategy:

  • Bootstrap failures → surface to the human, don't retry.

  • Input shape errors → fix the input and retry the same call.

  • Transient backend errors → retry with backoff; may succeed on its own.

  • Upstream third-party errors → may need a different strategy entirely.

Without a convention, every plugin invents its own codes and agents can't reason uniformly across them. The categories below cover 95% of real-world ability errors; sticking to them means an agent that learned the retry logic for one plugin can reuse it for the next.

Vocabulary

Substitute <plugin> with the plugin's slug in lowercase, underscores only. This matches WordPress error-code conventions. If the plugin already has a house style — for example, a single-word slug that deliberately omits underscores between elided words — mirror that. Consistency within a plugin trumps consistency across the vocabulary.

CodeWhen to useAgent behavior
<plugin>_not_initializedPlugin class missing, shared service accessor returns null, required dependency isn't resolvable.Not retriable from the agent side. Usually a config or bootstrap-ordering problem. Escalate.
<plugin>_missing_<field>A required input field is missing or empty (your execute callback's own check, not the schema-validator's).Agent should add the field and retry.
<plugin>_invalid_<field>Field is present but semantically wrong (bad enum value, malformed date, wrong type).Agent should correct the value and retry.
<plugin>_<resource>_data_unavailableBacking service returned a transient error (cache miss + remote failure, upstream 5xx, stale-while-revalidate failed).Agent can retry, probably with backoff.
ability_invalid_inputThe Abilities API's own schema-validator rejected the input before the execute callback ran.Equivalent to <plugin>_missing_<field> or <plugin>_invalid_<field>, just thrown earlier in the pipeline. Agent should fix input.
ability_invalid_input — the earlier path

When an ability is invoked via the Abilities API REST bridge, the registered input_schema runs first. Missing required fields or type mismatches produce WP_Error( 'ability_invalid_input' ) BEFORE the execute callback fires. Direct invocation (unit tests, non-REST wrappers) bypasses schema validation and hits your execute callback's own checks instead, producing <plugin>_missing_<field> / <plugin>_invalid_<field>.

Both paths are acceptable — end-agent-facing behavior is equivalent (deterministic validation error, no side effects). Document the observation in the ability's PR description or "notes for reviewers" so reviewers know both codes are expected in different harness runs.

Worked examples

// Bootstrap incomplete — plugin class missing or accessor returned null.
return new \WP_Error(
    '<plugin>_not_initialized',
    __( '<Plugin> is not initialized.', '<text-domain>' )
);

// Required field missing (execute-callback check, schema was bypassed).
return new \WP_Error(
    '<plugin>_missing_<field>',
    __( 'A <field> is required to <do the thing>.', '<text-domain>' )
);

// Field present but malformed.
return new \WP_Error(
    '<plugin>_invalid_<field>',
    sprintf(
        /* translators: %s: input parameter name. */
        __( 'The "%s" parameter must be an ISO 8601 date-time string.', '<text-domain>' ),
        $key
    )
);

// Transient backend error.
return new \WP_Error(
    '<plugin>_<resource>_data_unavailable',
    __( 'Unable to retrieve <resource> data. The cache may be stale or the remote service returned an error.', '<text-domain>' )
);

Upstream codes can bubble through — and usually should

If the backing controller talks to a third-party API (Stripe, WPCOM, another SaaS), its own error codes may surface verbatim in WP_Error::get_error_code() the ability returns. Typical examples:

  • resource_missing — Stripe's "object ID not found" code. Tells an agent the specific ID was wrong.

  • rate_limited — upstream throttling. Tells an agent to slow down.

Let these through rather than re-wrapping. A re-wrapped <plugin>_<resource>_not_found loses the information that would help the agent act. Document the upstream codes you've observed in the ability's description or PR notes so reviewers know they're expected.

Code naming rules

  1. Lowercase, underscores only. <plugin>_missing_order_id, not <plugin>-missingOrderId or <Plugin>-MissingOrderId.

  2. Plugin prefix first. Multi-word slugs should normalize to a single-word prefix where the plugin already does (e.g. woopayments rather than woo_payments).

  3. Action second. Use one of missing, invalid, not_initialized, <resource>_data_unavailable.

  4. Field or resource name last. <plugin>_missing_dispute_id, not <plugin>_dispute_id_missing. This matches English phrasing ("a dispute_id is required") and is faster to skim in error logs.

Internationalization

Error MESSAGES are translatable via __() or sprintf(__()). Error CODES are not — they're stable machine identifiers.

// WRONG — don't translate the code.
return new \WP_Error( __( '<plugin>_missing_order_id', '<text-domain>' ), ... );

// RIGHT — code is a literal, message is translatable.
return new \WP_Error(
    '<plugin>_missing_order_id',
    __( 'An order_id is required.', '<text-domain>' )
);

When a message interpolates a parameter name or value, include a translator comment:

return new \WP_Error(
    '<plugin>_invalid_date',
    sprintf(
        /* translators: %s: input parameter name. */
        __( 'The "%s" parameter must be an ISO 8601 date-time string.', '<text-domain>' ),
        $key
    )
);

Don't over-specify

The goal is consistent codes across all of a plugin's abilities, not ultra-fine granularity. <plugin>_missing_dispute_id is the right level. <plugin>_missing_dispute_id_in_submit_evidence_context is not — the ability name belongs in WP_Error::get_error_data() or in the agent's calling context, not in the code.

Summary — the four questions

When writing an execute callback, ask in order:

  1. Can the plugin even service this call? → <plugin>_not_initialized.

  2. Is the required input present? → <plugin>_missing_<field>.

  3. Is the required input the right shape? → <plugin>_invalid_<field>.

  4. Did the backing service choke? → <plugin>_<resource>_data_unavailable, or let the upstream code bubble through.

Four categories, one consistent code vocabulary per plugin. That's enough for agents to build reliable retry logic on top.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

The author says: Targets WordPress 7.0+ (PHP 7.4.0+). Filesystem-based agent with bash + node. Some workflows require WP-CLI.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
WordPress
Publisher
WordPress (Official)
Source
WordPress/agent-skills · skills/wp-abilities-api · commit 7374e6f
Licence
GNU General Public License v2.0 or later (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by WordPress.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download wp-abilities-api.zip