WordPress Abilities API: Register Custom Abilities in 7.0
Register custom abilities in WordPress 7.0 plugins. Covers wp_register_ability(), error handling, multi-plugin interoperability, and MCP integration.
WordPress Abilities API: Register Custom Abilities in 7.0
API documentation based on WordPress 7.0 RC1. Endpoints and parameters may change before the stable release on April 9, 2026.
WordPress Abilities API Custom Abilities in 7.0
This guide builds on our WordPress Abilities API foundations article. If you registered your first ability in 6.9, here is what changed in 7.0 and the patterns you need for production plugins: complete parameter reference, error handling, multi-plugin interoperability, and MCP exposure.
What Changed Between 6.9 and 7.0
WordPress 7.0 (Beta 1: February 20; RC1: March 19; GA: April 9 at WordCamp Asia) expands where registered abilities can be consumed. The PHP API (wp_register_ability()) has no breaking changes from 6.9. Here is what is new:
- Repository archived. The
abilities-apiGitHub repo was archived February 5, 2026. The API now lives in WordPress core — no separate Composer package needed. @wordpress/abilitiesJS package. Client-side ability registration and execution ships in core.- Abilities Explorer. New admin screen for viewing and testing registered abilities. Currently available via the AI Experiments plugin; expected in core.
- Hybrid abilities. Introduced in 7.0 Beta, combining multiple abilities into workflows. Full documentation expected in the March 19 Field Guide.
- WP AI Client. Provider-agnostic AI model API, proposed for core merge. Abilities become tool-callable by AI models natively.
For testing these features, see our WordPress 7.0 beta testing playbook.
Complete wp_register_ability() Parameter Reference
wp_register_ability( string $name, array $args ): ?WP_Ability
Returns a WP_Ability on success, null on failure. Call within the wp_abilities_api_init hook. The $name uses the format plugin-slug/ability-name.
Required $args
| Parameter | Type | Description |
|---|---|---|
label | string | Human-readable ability name |
description | string | Explanation of functionality |
category | string | Registered category slug (must exist) |
output_schema | array | JSON Schema defining return structure |
execute_callback | callable | Returns result or WP_Error |
permission_callback | callable | Returns true or WP_Error |
Optional $args
| Parameter | Type | Default | Description |
|---|---|---|---|
input_schema | array | null | JSON Schema for input validation |
meta | array | array() | REST, MCP, and annotation config |
ability_class | string | 'WP_Ability' | Custom class extending WP_Ability |
meta Sub-Keys
'meta' => array(
'show_in_rest' => true, // REST visibility (default: false)
'mcp' => array(
'public' => true, // MCP visibility (default: false)
),
'annotations' => array(
'readonly' => false, // MCP readOnlyHint
'destructive' => false, // MCP destructiveHint
'idempotent' => true, // MCP idempotentHint
'instructions' => '', // AI agent guidance
),
),
show_in_rest and mcp.public are independent. An ability can have REST without MCP, MCP without REST, both, or neither.
Registering Categories First
Categories must exist before any ability references them. Use the wp_abilities_api_categories_init hook, which fires before wp_abilities_api_init:
add_action( 'wp_abilities_api_categories_init', function() {
wp_register_ability_category( 'analytics', array(
'label' => __( 'Analytics', 'my-plugin' ),
'description' => __( 'Analytics and reporting abilities.', 'my-plugin' ),
) );
} );
If the category slug passed to wp_register_ability() does not exist, registration fails and returns null.
Registering with wp_register_ability() and Error Handling
To register a custom WordPress Abilities API ability, call wp_register_ability() inside the wp_abilities_api_init action hook, passing a namespaced name in plugin-slug/ability-name format and an $args array containing at minimum label, description, category, output_schema, execute_callback, and permission_callback.
The API enforces a validation chain: input schema, then permission_callback, then execute_callback, then output schema. If any step fails, a WP_Error propagates to the caller.
add_action( 'wp_abilities_api_init', function() {
wp_register_ability( 'my-plugin/get-page-views', array(
'label' => __( 'Get Page Views', 'my-plugin' ),
'description' => __( 'Returns page views for a URL path.', 'my-plugin' ),
'category' => 'analytics',
'input_schema' => array(
'type' => 'object',
'properties' => array(
'path' => array( 'type' => 'string' ),
),
'required' => array( 'path' ),
),
'output_schema' => array(
'type' => 'object',
'properties' => array(
'path' => array( 'type' => 'string' ),
'views' => array( 'type' => 'integer' ),
),
),
'execute_callback' => function( $input ) {
$views = My_Analytics::query( $input['path'] );
if ( is_wp_error( $views ) ) {
return $views; // Propagate upstream errors.
}
return array(
'path' => $input['path'],
'views' => $views['total'],
);
},
'permission_callback' => function() {
return current_user_can( 'view_site_analytics' );
},
'meta' => array(
'show_in_rest' => true,
'mcp' => array( 'public' => true ),
'annotations' => array(
'readonly' => true, 'idempotent' => true,
),
),
) );
} );
When exposed via REST, the WordPress Abilities API returns these error codes:
| Error Code | HTTP | Trigger |
|---|---|---|
ability_missing_input_schema | 400 | Required input not provided |
ability_invalid_input | 400 | Input fails schema validation |
ability_invalid_permissions | 403 | Permission denied |
ability_invalid_output | 500 | Output fails schema validation |
ability_invalid_execute_callback | 500 | Callback error |
rest_ability_not_found | 404 | Ability not registered |
rest_ability_category_not_found | 404 | Category not registered |
The same WP_Error propagation convention applies when abilities trigger background tasks — see Action Scheduler error handling patterns for the complementary pattern.
Multi-Plugin Interoperability
The WordPress Abilities API lets plugins call each other’s abilities without tight coupling. Use plugin-slug/ability-name namespacing to prevent collisions. Without the existence check below, a missing plugin produces a PHP fatal error that crashes the calling code instead of degrading gracefully. Always check existence before calling across plugin boundaries:
if ( wp_has_ability( 'notifier/send-slack' ) ) {
$ability = wp_get_ability( 'notifier/send-slack' );
$result = $ability->execute( array(
'message' => sprintf( 'Post %d published.', $post_id ),
) );
if ( is_wp_error( $result ) ) {
error_log( $result->get_error_message() );
}
} else {
// Graceful degradation: plugin not active.
}
This check-execute-handle pattern is the foundation for composable plugins. The WordPress Abilities API’s uniform schema means cross-plugin workflows work without custom integration code.
MCP Exposure for AI Agents
The WordPress Abilities API exposes any registered ability to AI agents via the MCP Adapter when you set meta.mcp.public to true. The adapter maps annotations to MCP hints that control AI agent behavior: readonly to readOnlyHint (prevents write operations), destructive to destructiveHint (triggers agent confirmation prompts), idempotent to idempotentHint (tells the agent safe retries are possible). Use the instructions annotation to give AI agents natural-language usage guidance about when and how to call your ability.
For abilities registered without MCP exposure, add it retroactively via filter:
add_filter( 'wp_register_ability_args', function( $args, $name ) {
if ( 'woocommerce/get-order-total' === $name ) {
$args['meta']['mcp']['public'] = true;
}
return $args;
}, 10, 2 );
For MCP Adapter installation and client configuration, see our Abilities API foundations article.
Verifying Your Registration
Confirm your WordPress Abilities API custom ability is correctly registered and visible to its intended consumers using any of these methods:
- Abilities Explorer. Open the admin screen (currently via the AI Experiments plugin) to browse registered abilities, view their schemas, and confirm metadata. This is the fastest visual check during development.
- REST endpoint. Visit
/wp-json/wp-abilities/v1/your-plugin/your-abilityto inspect the schema programmatically. Use this when validating input/output contracts match your expectations. - MCP discovery. Run
tools/listfrom your MCP client to confirm your ability appears with correct schemas and hints. This is the end-to-end integration test for AI agent visibility.
Each method catches different failure modes: the Explorer confirms registration, REST validates schema structure, and MCP discovery verifies the full exposure chain including annotation mapping.
For a complete WordPress 7.0 testing workflow, see our RC1 testing playbook. If you are also preparing your site for the WordPress 7.0 upgrade, the WordPress 7.0 preparation guide covers the broader plugin and theme compatibility checklist.
Frequently Asked Questions
What hook registers custom abilities?
Use wp_abilities_api_init. For categories, use wp_abilities_api_categories_init, which fires first. Both run during init, but categories must be registered before abilities that reference them.
How do I return errors from an ability?
Return a WP_Error from execute_callback. The WordPress Abilities API serializes it as a structured error response. The permission_callback can also return WP_Error for descriptive access-denied messages.
What is the naming convention?
Use plugin-slug/ability-name — for example, my-plugin/get-page-views. Lowercase alphanumeric, dashes, and forward slashes only. The slug namespace prevents collisions across plugins.
Can I call another plugin’s ability?
Yes. Check with wp_has_ability(), then call wp_get_ability()->execute( $input ). Always handle the WP_Error case — the other plugin may not be active on every site.
Is output_schema required?
Yes. It defines the JSON Schema for your return value, enabling both validation and AI agent discoverability through structured output contracts.
What changed in the Abilities API from 6.9 to 7.0?
The WordPress Abilities API PHP registration interface is unchanged. WordPress 7.0 adds @wordpress/abilities in core, the Abilities Explorer, hybrid abilities, and the WP AI Client (proposed for core merge). The GitHub repository was archived February 5, 2026 as the API moved into core.