WordPress Abilities API

WordPress Abilities API

5.00/5 - (17 votes)
11 min read
Guide
500+ WP projects
Full-stack developer

The WordPress Abilities API is a registry of operations that a plugin, a theme or core itself declares in one predictable format: a name, a category, an input and output schema, a permission check and an execute function. This page is a reference: what the API is, how to register an ability, which REST endpoints exist, how permissions work, what versions 7.0 and 7.1 added and where the MCP Adapter fits in. For examples of workflows built on abilities, see WordPress AI workflows with the Abilities API.

#What is the WordPress Abilities API

The dev note on make.wordpress.org defines a single ability like this:

“An ability is a self-contained unit of functionality with defined inputs, outputs, permissions, and execution logic.”

Jonathan Bossenger, Make WordPress Core, Abilities API in WordPress 6.9

Every registered ability goes into a central registry. That registry is read by PHP code on the server, the JavaScript client in the admin, the REST API and AI agents connected through the MCP Adapter. A plugin describes an operation once, and each of those channels sees it in the same shape, with the same schema and the same permission check.

The 6.9 release announcement puts it in terms of permissions:

“The new Abilities API provides a standardized, machine-readable permissions system that opens the door for next generation AI-powered and automated workflows.”

WordPress News, WordPress 6.9 “Gene”

Every ability belongs to exactly one category:

“Each ability must belong to exactly one category. Categories have a slug, label, and description.”

Common APIs Handbook, Abilities API

#Which WordPress version has the Abilities API

The Abilities API landed in core in WordPress 6.9, released on 2 December 2025. The handbook says so in a notice at the top of the page:

“The Abilities API is only available for WordPress 6.9 and above.”

Common APIs Handbook, Abilities API

Later releases extended the API without changing its foundations:

VersionDateWhat was added
6.9 “Gene”2 December 2025registry, categories, schemas, permissions, wp-abilities/v1 endpoints
7.0dev note of 24 March 2026JavaScript client: @wordpress/abilities and @wordpress/core-abilities
7.1 “Mary Lou”19 August 2026meta.public flag, four execution lifecycle filters

A plugin that also has to run on installs older than 6.9 checks for the function before registering: the make.wordpress.org dev note recommends a function_exists( 'wp_register_ability' ) check, which is also how the example below opens.

For the wider context of the 7.0 release, including the rest of the AI-related changes, see our guide to WordPress 7.0 and AI integration.

#How to register an ability in WordPress

Registration has two steps: the category first, then the ability. Each step has its own hook, and the order matters.

#Registering an ability category

“Categories must be registered before the abilities that reference them using the wp_abilities_api_categories_init hook.”

Make WordPress Core, Abilities API in WordPress 6.9

A category has a slug, a label and a description. The category argument is required when registering an ability and must point to the slug of a category that already exists in the registry.

#The wp_abilities_api_init hook

The ability itself is registered on a separate action. Registering it anywhere else fails:

“Abilities must be registered on the wp_abilities_api_init action hook. Attempting to register abilities outside of this hook will trigger a _doing_it_wrong() notice, and the Ability registration will fail.”

Make WordPress Core, Abilities API in WordPress 6.9

#wp_register_ability example

The function signature according to the Code Reference:

function wp_register_ability( string $name, array $args ): ?WP_Ability {

Source: Code Reference, wp_register_ability().

On success the function returns the registered WP_Ability instance, on failure null. A minimal example: a category and one read-only ability that returns the number of published posts.

if ( function_exists( 'wp_register_ability' ) ) {

	add_action( 'wp_abilities_api_categories_init', function () {
		wp_register_ability_category( 'my-plugin', array(
			'label'       => 'My plugin',
			'description' => 'Operations exposed by My plugin.',
		) );
	} );

	add_action( 'wp_abilities_api_init', function () {
		wp_register_ability( 'my-plugin/post-count', array(
			'label'               => 'Published post count',
			'description'         => 'Returns the number of published posts.',
			'category'            => 'my-plugin',
			'output_schema'       => array( 'type' => 'integer' ),
			'permission_callback' => function () {
				return current_user_can( 'edit_posts' );
			},
			'execute_callback'    => function () {
				return (int) wp_count_posts()->publish;
			},
			'meta'                => array(
				'show_in_rest' => true,
				'annotations'  => array( 'readonly' => true ),
			),
		) );
	} );
}

This ability takes no input, so it has no input_schema. It returns a value, so output_schema is mandatory.

#Ability name format and namespace

“The format should be namespace/ability-name”

Make WordPress Core, Abilities API in WordPress 6.9

The name uses lowercase letters, digits, hyphens and a slash. The namespace is usually the plugin slug, which prevents collisions between plugins that register similar operations.

#input_schema and output_schema

Schemas are not there just for documentation. Core validates input against them before execution and output after it.

“Defining schemas is mandatory when there is a value to pass or return.”

Make WordPress Core, Abilities API in WordPress 6.9

The validator does not support the full JSON Schema specification:

“WordPress implements a validator based on a subset of JSON Schema Version 4.”

Make WordPress Core, Abilities API in WordPress 6.9

In practice that means writing schemas in draft 4 syntax and being careful with keywords outside that subset.

#permission_callback and execute_callback

Both callbacks are required. The Code Reference describes them like this:

“Required. A callback function to check permissions before execution.”

Code Reference, wp_register_ability()

“Required. A callback function to execute when the ability is invoked.”

Code Reference, wp_register_ability()

The permission callback sees the same data as the execute callback, so it can make a decision based on the specific input, for example allowing edits only to a post the user wrote:

“It receives the same input as the execute callback and must return a boolean or WP_Error”

Code Reference, wp_register_ability()

#Error handling in execute_callback

An error is returned as an object, not thrown as an exception or signalled with an empty result:

“Abilities should handle errors gracefully by returning WP_Error objects:”

Make WordPress Core, Abilities API in WordPress 6.9

#readonly, destructive and idempotent annotations

Annotations in meta.annotations describe what kind of operation an ability is. readonly marks an ability that changes nothing:

“Optional. If true, the ability does not modify its environment.”

Code Reference, wp_register_ability()

The other two annotations are destructive and idempotent. They are not decoration: they decide the HTTP method for REST calls, and a client such as an AI agent can use them to judge whether an operation is safe to repeat.

This site runs its own MCP server, described in /.well-known/mcp/server-card.json, and it exposes read-only tools only. The same approach works for abilities: the first version of an agent integration uses abilities with readonly: true, called over GET. Write operations come later, each with its own permission_callback.

#Abilities API REST endpoints

In WordPress 6.9 an ability does not show up in the REST API automatically. You have to declare it:

“This is possible by setting the meta.show_in_rest argument to true when registering an ability.”

Make WordPress Core, Abilities API in WordPress 6.9

The endpoints live in the wp-abilities/v1 namespace: the list of abilities, a single ability and execution. The execution route looks like this:

GET|POST|DELETE /wp-abilities/v1/abilities/{name}/run

Source: Make WordPress Core, Abilities API in WordPress 6.9.

#Abilities API authentication

“Access to all Abilities REST API endpoints requires an authenticated user.”

Make WordPress Core, Abilities API in WordPress 6.9

This applies to the list of abilities as well. A session cookie, application passwords or your own authentication mechanism all work. An anonymous client cannot even see which abilities exist on the site.

#How to run an ability via the REST API

The annotations decide the HTTP method for the run endpoint. A readonly ability runs over GET, an ability that is both destructive and idempotent over DELETE, and in every other case:

“All other cases: uses POST”

Jorge Costa, Make WordPress Core, Client-Side Abilities API in WordPress 7.0

The REST documentation in the project repository stresses that for read-only abilities this is a requirement, not a recommendation:

”- Read-only abilities must use GET (readonly: true)”

GitHub, WordPress/abilities-api, docs/rest-api.md

With GET and DELETE the input does not go in the request body but in the input query parameter as URL-encoded JSON.

#Abilities API in JavaScript

WordPress 7.0 added a browser-side client in two packages. @wordpress/abilities is the abilities store itself, and @wordpress/core-abilities loads the abilities registered on the server through REST:

“This will load both @wordpress/core-abilities and its dependency @wordpress/abilities, and automatically fetch and register all server-side abilities.”

Jorge Costa, Make WordPress Core, Client-Side Abilities API in WordPress 7.0

Errors in the JS client have fixed codes. Failed validation gives ability_invalid_input or ability_invalid_output, and a permission denial:

“If the permission callback returns false, an error with code ability_permission_denied is thrown.”

Jorge Costa, Make WordPress Core, Client-Side Abilities API in WordPress 7.0

#Abilities API changes in WordPress 7.1

The 7.1 release announcement sums up the changes in one sentence:

“The Abilities API builds on the infrastructure introduced in WordPress 6.9 with a filterable execution lifecycle, custom validation, and shared discovery.”

WordPress News, WordPress 7.1 “Mary Lou”

#The meta.public flag

WordPress 7.1 introduced meta.public, a shared client exposure flag. It fills show_in_rest, but an explicitly set show_in_rest takes precedence, and the default stays false:

$show_in_rest = $meta['show_in_rest'] ?? $meta['public'] ?? false;

Source: Milana Cap, Make WordPress Core, A unified public exposure flag for Abilities in WordPress 7.1.

The flag controls visibility, not access:

“The public flag controls discoverability and client exposure.”

Milana Cap, Make WordPress Core, A unified public exposure flag for Abilities in WordPress 7.1

An ability marked as public still goes through permission_callback. The public flag does not replace it.

#Ability execution lifecycle filters

“The Abilities API previously provided the wp_before_execute_ability and wp_after_execute_ability actions.”

Make WordPress Core, New execution lifecycle filters for the Abilities API in WordPress 7.1

On top of those two actions from 6.9, version 7.1 added four filters:

FilterExecution stage
wp_pre_execute_abilitybefore execution
wp_ability_normalize_inputinput normalization
wp_ability_permission_resultpermission check result
wp_ability_execute_resultexecution result

The actions only let you observe execution. The filters let you change it, for example to normalize the input or alter the result of the permission check.

#Abilities API and the MCP Adapter

The Abilities API does not include a Model Context Protocol server. A separate package does that job:

“The official WordPress package for MCP integration that exposes WordPress abilities as Model Context Protocol (MCP) tools, resources, and prompts for AI agents.”

GitHub, WordPress/mcp-adapter, README

The default is conservative:

“WordPress abilities are private by default.”

GitHub, WordPress/mcp-adapter, README

For an ability to be visible to an MCP client, set meta.public (or meta.mcp.public) to true. The adapter’s default server exposes three meta tools that the agent uses to discover and run abilities. Connecting:

“Connect via WP-CLI over STDIO, or point an HTTP client at /wp-json/mcp/mcp-adapter-default-server.”

GitHub, WordPress/mcp-adapter, README

STDIO through WP-CLI suits local work and staging, HTTP suits an agent running off the server. Either way, what the agent can do is decided by the same permission_callback and annotations described above.

For more on connecting WordPress to AI agents over MCP, see our guide to MCP and AI integration in WordPress. If you need your own MCP server or a set of abilities designed around a specific store or site, that is covered on the WordPress MCP server development page.

#How to check if WordPress supports the Abilities API

The simplest check is in code: function_exists( 'wp_register_ability' ) returns true from version 6.9. From the outside, with an account that has an application password, query the wp-abilities/v1 namespace in the site’s REST API. If it is missing, the site runs a version older than 6.9 or something is blocking the REST API. The list only returns abilities with show_in_rest or public set to true, so an empty list does not mean plugins register no abilities.

Sources last verified: 6 October 2026.

Recommendations from LinkedIn

Recommendations and reviews of working with WPPoland

Selected recommendations from WordPress, WordCamp and e-commerce leaders - with a focus on delivery on time, technical depth, and a business-driven approach to WordPress development.

Karolina Czapla

Karolina Czapla

Marketing Strategist, Performance & Digital Strategy

“Working with Mariusz on WordCamp has shown me how rare it is to combine deep technical skill with genuine leadership. He plans, coordinates and delivers with precision, while giving the team space to grow and contribute....”

Co‑organiser, WordCamp Gdynia 2024 & 2025

Anna Kamińska

Anna Kamińska

Talent Acquisition Specialist / HR People Partner

“Mariusz's portfolio speaks for itself. It reflects his precision, versatility and sense of responsibility. You can trust him to guide a project from idea to delivery, keep stakeholders informed and make sure things are d...”

Worked on the same team

Sarah‑Luisa Kwolek

Sarah‑Luisa Kwolek

IT Project Management & Product Owner, Web/App

“For over two years I could always rely on Mariusz to handle WordPress tasks calmly and professionally, from styling and templating to third‑party integrations. He brings steadiness to the team and keeps the frontend side...”

Mariusz was her client for WordPress work

Argert Boja

Argert Boja

Senior Full‑Stack Developer

“Mariusz is the teammate everyone hopes for: strong full‑stack WordPress skills, clear explanations and a positive attitude even under pressure. He moves easily between custom plugins, performance work and Gutenberg layou...”

Worked alongside Mariusz on WordPress projects

Varun Patil

Varun Patil

Growth & CRM Lead

“Beyond development, Mariusz understands SEO, analytics and growth. He talks directly with stakeholders, asks the right questions and ships solutions that move business metrics, from AMP to tracking to performance.”

Managed Mariusz on growth initiatives

Rafał Osiński

Rafał Osiński

Founder @ EasyTrips.pl, Senior WordPress Dev

“I've known Mariusz through the WordPress community for many years. He's reliable, deeply involved and consistently shows up, at meetups, WordCamps and in projects. If you care about long‑term collaboration and someone wh...”

WordPress community co‑organiser

Daniel Blossfeld

Daniel Blossfeld

Process Optimization & Digitalization Consultant

“I had the pleasure of working with Mariusz for almost three years. During that time, his WordPress development skills proved invaluable across a range of projects, from website builds to online member areas and even Shop...”

Mariusz was his client for WordPress work

Natalie Wiszczor

Natalie Wiszczor

CRM & E-Mail Marketing Manager

“I had the great pleasure of working with Mariusz for over 4 years in the technical field. During this time, he proved to be a competent and reliable colleague. What stood out in particular was his friendly nature and his...”

Worked with Mariusz on different teams

Mark Chalklen

Mark Chalklen

Head of Design & Build at Itineris Limited

“Mariusz is a great member of the team, always happy to get stuck into any task and happy to learn new things. A great communicator and all round nice guy to work with. Hard to beat on our weekly Strava leader board thoug...”

Managed Mariusz directly

Jessica Di Pasquale

Jessica Di Pasquale

Leading SEO initiatives with data-driven growth strategies.

“Mariusz is a very skilled, patient and expert guy. Always ready to help and to fix errors, I really appreciated working with him. He is such a great colleague!”

Managed Mariusz directly

Biki John

Biki John

Content Marketing Aficionado & SEO Enthusiast

“It was great to work with Mariusz. I really appreciated his extensive knowledge of WordPress and how that came in handy whenever I needed support navigating the CMS. I commend Mariusz totally for his patience, good natur...”

Worked with Mariusz on different teams

Rafal Borowiec

Rafal Borowiec

Software Developer, Consultant, Manager and Lecturer

“I had an opportunity to work with Mariusz for 7 months. He excels in technical optimization for search engines (SEO). Mariusz has also strong expertise in AMP development, GTM, and GA. Mariusz feels very comfortable with...”

Managed Mariusz directly

Belinda Koch

Belinda Koch

Web-Tracking Analyst at TUI

“Mariusz is a great person to work with. He is extremely motivated to learn new things and share his knowledge, and is very knowledgeable on a wide range of topics. We worked together on digital analytics and tracking top...”

Worked with Mariusz on digital analytics and tracking topics

Ali Nezamolmaleki

Ali Nezamolmaleki

Growth, SEO, Analytical thinking, AMP

“Mariusz is an extremely talented person in his field of work. He is always capable of giving a new perspective to solve problems and to think out of the box in situations where everything seems to be locked. Working with...”

Worked with Mariusz on the same team

Karol Jakubcewicz

Karol Jakubcewicz

Front-end / JavaScript Developer

“Mariusz is an incredibly experienced WordPress developer and SEO/SEM specialist I've had the pleasure to work with for almost two years. As a pilot of the team responsible for AirHelp's website development, he's been one...”

Worked with Mariusz on the same team

Paweł Lewczuk

Paweł Lewczuk

Front-end developer, WordPress developer

“I collaborated with Mariusz on several projects and our cooperation was always exemplary. I believe there are many more joint projects ahead of us. Highly recommended!”

Mariusz was Paweł's client

Przemek Wroblewski

Przemek Wroblewski

Software Developer with 20+ years of experience

“I found Mariusz as someone with great expertise and profound knowledge of frontend solutions. Powerful, knowledgeable and accountable WordPress developer. Has an easiness to build interpersonal relations with others. He ...”

Worked with Mariusz on different teams

Service FAQ

Frequently asked questions

Questions about scope, delivery, pricing, and execution quality.

SEO-readyGEO-readyAEO-ready5 Q&A
What is the WordPress Abilities API?#
It is a registry of operations that a plugin, theme or core exposes in a standard shape. Each ability has a namespaced name, a category, an input and output schema, a permission callback and an execute callback. That way PHP, JavaScript, the REST API and AI agents connected through the MCP Adapter all see the same operations in the same shape.
Which WordPress version introduced the Abilities API?#
WordPress 6.9, released on 2 December 2025. WordPress 7.0 added a JavaScript client, and WordPress 7.1 added the public flag and execution lifecycle filters. A plugin that also has to run on older installs should wrap registration in a function_exists( 'wp_register_ability' ) check.
Is an ability automatically available in the REST API?#
No. In WordPress 6.9 you set meta.show_in_rest to true. From 7.1 you can also set meta.public, which fills show_in_rest unless show_in_rest is given explicitly. Both are off by default, and every call to a wp-abilities/v1 endpoint requires a logged-in user.
How do I run an ability through the REST API?#
Through the /wp-abilities/v1/abilities/{name}/run endpoint. The annotations decide the method: a readonly ability runs over GET, an ability that is both destructive and idempotent over DELETE, everything else over POST. With GET and DELETE the input goes in the input query parameter as URL-encoded JSON.
Is the Abilities API the same as MCP?#
No. The Abilities API is a registry in WordPress core. The Model Context Protocol is handled by the separate, official MCP Adapter package, which exposes abilities as MCP tools, resources and prompts. Abilities are private by default there and have to be marked public.

Need an FAQ tailored to your industry and market? We can build one aligned with your business goals.

Let’s discuss

Related Articles