Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion docs/4.using-abilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ To get an array of all registered abilities:
/**
* Retrieves all registered abilities using Abilities API.
*
* @param array $args Optional. Arguments to filter abilities.
* @return WP_Ability[] The array of registered abilities.
*/
function wp_get_abilities(): array
function wp_get_abilities( array $args = array() ): array

// Example: Get all registered abilities
$all_abilities = wp_get_abilities();
Expand All @@ -56,6 +57,30 @@ foreach ( $all_abilities as $name => $ability ) {
}
```

### Filtering Abilities

`wp_get_abilities()` accepts optional filter arguments. For detailed filtering documentation, see [Querying and Filtering Abilities](8.querying-filtering-abilities.md).

Quick example:

```php
// Get abilities in a specific category
$abilities = wp_get_abilities( array( 'category' => 'data-retrieval' ) );

// Search for abilities
$abilities = wp_get_abilities( array( 'search' => 'email' ) );

// Filter by namespace and meta
$abilities = wp_get_abilities( array(
'namespace' => 'my-plugin',
'meta' => array(
'show_in_rest' => true,
),
) );
```

See [Querying and Filtering Abilities](8.querying-filtering-abilities.md) for complete filtering documentation, including meta filters, ordering, and pagination.

## Executing an Ability (`$ability->execute()`)

Once you have a `WP_Ability` object (usually from `wp_get_ability`), you execute it using the `execute()` method.
Expand Down
213 changes: 213 additions & 0 deletions docs/8.querying-filtering-abilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
# 8. Querying and Filtering Abilities

The Abilities API provides powerful filtering capabilities through the `WP_Abilities_Query` class and the `wp_get_abilities()` function. This allows you to efficiently find and retrieve specific abilities from potentially thousands of registered abilities.

`wp_get_abilities()` returns an array of `WP_Ability` objects, keyed by ability name.

When no abilities match the query, an empty array is returned.

Invalid query parameters are normalized to safe defaults.

## Overview

When working with large numbers of abilities registered by core and various plugins, the query system provides optimized server-side filtering. You can pass query arguments to `wp_get_abilities()` to filter abilities by category, namespace, meta properties, and more.

```php
// Get all abilities
$abilities = wp_get_abilities();

// Filter by category
$abilities = wp_get_abilities( array( 'category' => 'data-retrieval' ) );

// Combine multiple filters
$abilities = wp_get_abilities( array(
'namespace' => 'my-plugin',
'category' => 'communication',
'orderby' => 'label',
) );
```

## Quick Reference: Query Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `category` | string\|array | `''` | Filter by category slug. Accepts single value or array for multiple categories (OR logic) |
| `namespace` | string\|array | `''` | Filter by namespace. Accepts single value or array for multiple namespaces (OR logic) |
| `search` | string | `''` | Search in name, label, and description (case-insensitive) |
| `meta` | array | `array()` | Filter by meta properties using nested arrays (AND logic between multiple meta filters) |
| `orderby` | string | `''` | Sort by: `'name'`, `'label'`, or `'category'`. Empty = no sorting |
| `order` | string | `'ASC'` | Sort direction: `'ASC'` or `'DESC'` |
| `limit` | int | `-1` | Maximum results to return. `-1` = unlimited |
| `offset` | int | `0` | Number of results to skip |

## Basic Filtering

### Filter by Category

```php
// Get all data retrieval abilities
$abilities = wp_get_abilities( array( 'category' => 'data-retrieval' ) );

// Get all communication abilities
$abilities = wp_get_abilities( array( 'category' => 'communication' ) );

// Get abilities from multiple categories (OR logic)
$abilities = wp_get_abilities( array(
'category' => array( 'math', 'communication', 'data-retrieval' ),
) );
```

### Filter by Namespace

Namespace is the part before the `/` in the ability name (e.g., `my-plugin` in `my-plugin/send-email`).

```php
// Get all abilities from your plugin
$abilities = wp_get_abilities( array( 'namespace' => 'my-plugin' ) );

// Get all WooCommerce abilities
$abilities = wp_get_abilities( array( 'namespace' => 'woocommerce' ) );

// Get abilities from multiple namespaces (OR logic)
$abilities = wp_get_abilities( array(
'namespace' => array( 'my-plugin', 'woocommerce', 'jetpack' ),
) );
```

### Search Abilities

Search is case-insensitive and searches in name, label, and description:

```php
// Find all abilities related to email
$abilities = wp_get_abilities( array( 'search' => 'email' ) );

// Find payment-related abilities
$abilities = wp_get_abilities( array( 'search' => 'payment' ) );
```

### Combine Multiple Filters

Filters are cumulative (AND logic):

```php
// Get communication abilities from my-plugin only
$abilities = wp_get_abilities( array(
'category' => 'communication',
'namespace' => 'my-plugin',
) );

// Search for email abilities in the communication category
$abilities = wp_get_abilities( array(
'category' => 'communication',
'search' => 'email',
) );
```

## Meta Filtering

Filter abilities by their meta properties, including `show_in_rest`, `annotations`, and custom meta keys. All meta filters use AND logic — abilities must match all specified criteria.

### Filter by REST API Visibility

```php
// Get abilities exposed in REST API
$abilities = wp_get_abilities( array(
'meta' => array(
'show_in_rest' => true,
),
) );

// Get abilities hidden from REST API
$abilities = wp_get_abilities( array(
'meta' => array(
'show_in_rest' => false,
),
) );
```

### Filter by Annotations

```php
// Get readonly abilities
$abilities = wp_get_abilities( array(
'meta' => array(
'annotations' => array(
'readonly' => true,
),
),
) );

// Get non-destructive, idempotent abilities
$abilities = wp_get_abilities( array(
'meta' => array(
'annotations' => array(
'destructive' => false,
'idempotent' => true,
),
),
) );
```

### Combine Multiple Meta Filters

When you specify multiple meta conditions, abilities must match all of them (AND logic):

```php
// Get readonly abilities that are exposed in REST API
$abilities = wp_get_abilities( array(
'meta' => array(
'show_in_rest' => true,
'annotations' => array(
'readonly' => true,
),
),
) );

// Get REST-enabled, readonly, idempotent abilities
$abilities = wp_get_abilities( array(
'meta' => array(
'show_in_rest' => true,
'annotations' => array(
'readonly' => true,
'idempotent' => true,
),
),
) );
```

### Filter by Custom Meta

You can filter by any custom meta keys you've added to abilities:

```php
$abilities = wp_get_abilities( array(
'meta' => array(
'custom_key' => 'custom_value',
'another_meta' => 'another_value',
),
) );
```

## Ordering and Pagination

```php
// Order by name, label, or category
$abilities = wp_get_abilities( array(
'orderby' => 'label',
'order' => 'ASC', // or 'DESC'
) );

// Paginate results
$abilities = wp_get_abilities( array(
'limit' => 10,
'offset' => 0,
) );
```
Comment on lines +201 to +206
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific need for pagination?

I see that you're trying to mirror WP_Query et al (versus adding sorting/filtering as registry methods) but abilities are in a PHP array, not a database. Do we really need a shortcut for what's essentially an array_slice()?

Copy link
Member

@gziolo gziolo Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filtering abilities are the most crucial aspect from my perspective. Ordering and pagination are nice-to-haves, but I want to acknowledge that they fit well together in the proposed implementation, as they allow easy selection of a precise number of abilities that meet specific criteria, which might be useful when passing data to an LLM with limited context. @galatanovidiu might have a better overview of the real needs based on the work he has done for the MCP Adapter.


## See Also

- [Registering Abilities](3.registering-abilities.md) - How to register abilities with proper metadata
- [Using Abilities](4.using-abilities.md) - Basic ability usage, execution, and permissions
- [Registering Categories](7.registering-categories.md) - How to register ability categories
- [REST API](5.rest-api.md) - REST API endpoints for abilities
28 changes: 25 additions & 3 deletions includes/abilities-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,36 @@ function wp_get_ability( string $name ): ?WP_Ability {
/**
* Retrieves all registered abilities using Abilities API.
*
* Uses WP_Abilities_Query to retrieve abilities from the registry with optional filtering.
*
* @since 0.1.0
* @since n.e.x.t Added optional $args parameter for filtering abilities.
*
* @see WP_Abilities_Registry::get_all_registered()
* @see WP_Abilities_Query
* @see WP_Abilities_Query::AbilityQueryArgs for the full type definition.
*
* @param array<string,mixed> $args Optional. Arguments to filter abilities. Default empty array.
* Accepts 'category', 'namespace', 'search', 'meta', 'orderby',
* 'order', 'limit', and 'offset'.
* 'category' and 'namespace' accept string or array for multi-value filtering.
* All filters use AND logic between different filter types and meta properties.
* @return \WP_Ability[] The array of registered abilities.
*
* @phpstan-param array{
* category?: string|array<string>,
* namespace?: string|array<string>,
* search?: string,
* meta?: array<string,mixed>,
* orderby?: string,
* order?: string,
* limit?: int,
* offset?: int,
* ...<string, mixed>
* } $args
*/
function wp_get_abilities(): array {
return WP_Abilities_Registry::get_instance()->get_all_registered();
function wp_get_abilities( array $args = array() ): array {
$query = new WP_Abilities_Query( $args );
return $query->get_abilities();
}

/**
Expand Down
Loading