WordPress 7.0 has officially dropped, and it is bringing the Client-Side Abilities API to the front line. If you have been wrestling with custom AJAX handlers or messy REST endpoints just to trigger simple UI actions, this update is for you. Specifically, this API creates a unified bridge between browser agents, AI tools, and your WordPress site.
I have spent 14 years watching WordPress evolve from a blogging tool to a complex application framework. Honestly, we have needed a standardized way for JavaScript to “talk” to server-registered logic without the overhead of custom endpoints. This is not just a shiny new toy; it is a fundamental shift for WebMCP and browser agent integration.
The Two-Package Architecture
The Client-Side Abilities API is split into two distinct packages. This modularity is a win for performance-focused developers who do not want to load the entire core stack for a small project.
- @wordpress/abilities: This is the pure state management layer. It handles the store, registration, and logic. Furthermore, it has no server dependencies. You can actually use this in non-WordPress projects if you just need an ability store.
- @wordpress/core-abilities: This is the “magic” layer. It automatically fetches abilities registered on the server via the
/wp-abilities/v1/REST endpoint and hydrates the client store.
This update is specifically huge for anyone building with WordPress and AI agents because it allows these agents to discover what a site can actually do.
Enqueuing with Script Modules
In WordPress 7.0, we are leaning heavily into script modules. To use the API, you must use wp_enqueue_script_module. If you need access to core server-side abilities, you should enqueue the core integration package.
add_action( 'admin_enqueue_scripts', 'bbioon_enqueue_abilities' );
function bbioon_enqueue_abilities() {
// Enqueue the core integration for server-registered abilities
wp_enqueue_script_module( '@wordpress/core-abilities' );
}
If you missed my earlier deep dive into the server-side foundations, check out why the Abilities API ends integration headaches.
Registering and Validating Abilities
Before you register an ability, you must have a category. Think of categories as namespaces. Consequently, it keeps the global store from becoming a graveyard of naming collisions. For instance, here is how you register a client-side ability with strict validation.
import { registerAbility, registerAbilityCategory } from '@wordpress/abilities';
// 1. Register the Category
registerAbilityCategory( 'my-plugin-tools', {
label: 'Plugin Tools',
description: 'Custom UI actions for my plugin',
} );
// 2. Register the Ability with Schema Validation
registerAbility( {
name: 'my-plugin/update-layout',
label: 'Update Layout',
category: 'my-plugin-tools',
input_schema: {
type: 'object',
properties: {
layoutType: { type: 'string', enum: [ 'grid', 'list' ] },
},
required: [ 'layoutType' ],
},
callback: async ( { layoutType } ) => {
console.log( `Switching to ${layoutType} view...` );
return { success: true };
},
} );
The API uses JSON Schema (Draft-04). This is critical. If your callback receives junk data, the API throws an ability_invalid_input error before the code even runs. This prevents the “state pollution” we often see in older React-based plugins.
Handling Execution and Permissions
Executing an ability is simple, but handling errors is where senior devs separate themselves. You must account for permissions and validation failures. Therefore, always wrap your executeAbility calls in a try-catch block.
import { executeAbility } from '@wordpress/abilities';
async function handleUIAction() {
try {
const result = await executeAbility( 'my-plugin/update-layout', {
layoutType: 'grid'
} );
console.log( 'Action complete:', result.success );
} catch ( error ) {
if ( error.code === 'ability_permission_denied' ) {
alert( 'You do not have permission for this.' );
} else {
console.error( 'Execution failed:', error.message );
}
}
}
For server-side abilities, the Client-Side Abilities API is smart enough to map requests to the correct HTTP method. If an ability is marked as readonly: true in its metadata, the API uses a GET request. Conversely, destructive actions default to POST or DELETE if marked as idempotent.
Look, if this Client-Side Abilities API stuff is eating up your dev hours, let me handle it. I have been wrestling with WordPress since the 4.x days, and I can help you refactor your legacy code into this modern architecture.
Pragmatic Takeaway
The shift in WordPress 7.0 toward script modules and formalized “Abilities” is a massive upgrade for stability. Specifically, the separation between @wordpress/abilities and @wordpress/core-abilities allows us to build cleaner, more testable interfaces. Stop building custom AJAX silos and start registering your actions. Your future self (and your site’s performance) will thank you.