---
title: A very particular set of skills
date: 2025-11-18T10:44:42Z
modified: 2025-11-18T11:42:04Z
permalink: "https://dgw.ltd/2025/11/18/a-very-particular-set-of-skills/"
type: post
status: publish
excerpt: ""
wpid: 613
categories:
  - AI
featured_image: "https://dgw.ltd/wp-content/uploads/2025/11/CleanShot-2025-11-18-at-10.20.28@2x.jpg"
featured_image_alt: A vintage box of Lego
---

Another thing coming to WordPress 6.9 – something I’ve been following with interest since it was announced – is the new [Abilities API](https://developer.wordpress.org/news/2025/11/introducing-the-wordpress-abilities-api/), part of the wider effort to develop [AI tooling within WordPress](https://wordpress.org/news/2025/05/announcing-the-formation-of-the-wordpress-ai-team/). Led by the WordPress AI Team, this API is expected to ship alongside an [MCP adapter](https://github.com/WordPress/mcp-adapter), standardising how WordPress tools connect to AI agents by giving them context and a structured registry of how to interact with a site.

As the announcement describes, the Abilities API enables a:

> discoverable, and secure approach to how WordPress core, plugins, and themes define and expose their capabilities

The increasingly excellent WordPress Developer Blog provides a working example of an ability in action. When registering an ability, most arguments are optional, but the required ones are:

- `label`: A human-readable name for the Ability.
- `description`: A brief description of what the Ability does.
- `category`: The category under which the Ability is grouped. You can register your own Ability Categories, but in this case, I’m using the available `site` category
- `output_schema`: The schema that defines the structure of the data returned by the Ability.
- `execute_callback`: The function that will be called when the Ability is executed.
- `permission_callback`: A function that determines whether the current user has permission to execute the Ability.

Every registered ability is also automatically exposed through REST, meaning you can discover abilities at `/wp-json/wp-abilities/v1/abilities`

I’ll be honest: some of this is still a bit mysterious to me, and with the pace of technical change it’s impossible to know whether this will fully stick. But the idea of standardising how we expose functionality _does_ make a lot of sense.

As with [other](https://dgw.ltd/2025/11/12/automattic-excerpts/) [recent](https://dgw.ltd/2025/11/10/6-9/) posts, I wanted to explore some of these features ahead of the 6.9 release. I looked through the custom plugins I’ve built for this site:

- The theme [companion plugin](https://github.com/dogwonder/dgwltd-plugin) (core functionality, custom blocks, utilities)
- An experimental calendar/booking system
- A WordPress exporter to multiple file formats
- A [content filter](https://dgw.ltd/content-filter/) – powered by the Interactivity API and REST endpoints

The obvious candidate was the Content Filter, because it maps naturally to a structured ability: define inputs, define outputs, define what can be filtered. The ability then becomes self-describing.

I decided to create a new plugin to handle all of the site’s abilities – rather than bolting abilities onto existing plugins – because it’s likely we’ll want to expose functionality from multiple parts of the codebase over time.

e.g.

**Input Parameters:**

- `post_type` (string, default: “post”) – Post type to query
- `keyword` (string, optional) – Search keyword
- `date` (string, optional) – Date filter slug (e.g., “last-30-days”)
- `page` (integer, default: 1) – Page number
- `per_page` (integer, default: 10, max: 50) – Posts per page
- `include_acf` (boolean, default: false) – Include ACF fields (whitelisted only)
- Taxonomy filters (dynamic):
- `category` (string, optional) – Category term IDs (comma-separated)
- `tag` (string, optional) – Tag term IDs (comma-separated)

**Output:**

- `posts` (array) – Filtered posts with metadata
- `pagination` (object) – Pagination information
- `query` (object) – Query parameters used

After registering the ability via the function `wp_register_ability` we can start executing it, via the simple method `$ability->execute`


```php
$ability = wp_get_ability( 'dgw/filter-posts' );

if ( $ability ) {
    // Execute with input
    $result = $ability->execute( array(
        'post_type' => 'post',
        'keyword'   => 'wordpress',
        'category'  => '1,5',
        'per_page'  => 20,
    ) );

    if ( ! is_wp_error( $result ) ) {
        echo 'Found ' . $result['pagination']['total_posts'] . ' posts';
        foreach ( $result['posts'] as $post ) {
            echo $post['title'] . ': ' . $post['permalink'];
        }
    }
}
```

As the Developer Blog notes:

> Now, what I really like about this implementation is how extendable this is. If I want to allow other plugin or theme developers to utilize this functionality, all I have to do is document the ability identifier, the input schema, and the output schema.

It _is_ a fair amount of code simply to wrap existing functionality. If I update any REST endpoints, I’ll need to update the ability too. And yes, you could ask: why not use the REST API directly? If this was purely internal – or even external – that would be a very fair point. REST is still the main stable interface to document.

Where this truly becomes valuable is **AI integration**, especially via MCP. As [Jonathan Bossenger](https://jonathanbossenger.com/the-wordpress-abilities-api/) explains:

> MCP avoids the limitations of statelessness by maintaining a persistent, real-time connection that allows for rich, context-aware

and

> WordPress doesn’t have a low-level system that allows developers to use a systematic approach when registering any functionalities

Abilities aim to fill that gap. And because they’re discoverable, you can introspect a site’s capabilities simply with:


```php
$abilities = wp_get_abilities();
```

Overall, the Abilities API feels like a promising step toward a more structured, discoverable, and AI connected WordPress. Whether it becomes central to day-to-day development is unclear, but the direction is encouraging – and worth exploring ahead of the 6.9 release.