WordPress 7.1 expands wp_get_abilities() with category, namespace, metadata, item callback, result callback, and global filtering. Because these stages run in a defined order and REST requests add show_in_rest constraints, a plugin can return a different set in PHP and over REST if its fixtures are incomplete.
Use this for plugins that expose abilities to administration screens, REST clients, automation, AI tools, or integration platforms.
Quick answer
Register a small fixture registry with public and private abilities across two namespaces and categories. Test each declarative argument alone, combinations, the item callback, result callback, and global filters in order. Repeat through REST, where show_in_rest must be true, and treat filtering as discovery only. Execute permission checks separately.
What to check first
- Register known abilities across at least two categories, namespaces, REST visibility states, and metadata values.
- Test strict category, namespace, and metadata matching separately before combining them.
- Log the set after declarative filters, item_include_callback, result_callback, and global filters.
- Repeat equivalent queries through REST and confirm show_in_rest behavior.
- Run the selected ability's permission callback before execution because filtering is not authorization.
Diagnostic table
Use this table to connect the observed behavior to evidence and a verification step.
| Action | Evidence to collect | How to verify |
| Build a fixture registry | Register known abilities across at least two categories, namespaces, REST visibility states, and metadata values. | Each declarative filter returns the expected exact IDs. |
| Assert declarative matches | Test strict category, namespace, and metadata matching separately before combining them. | Item, result, and global filters run in the documented order. |
| Trace callback order | Log the set after declarative filters, item_include_callback, result_callback, and global filters. | REST results include only abilities intentionally exposed through show_in_rest. |
| Repeat through REST | Repeat equivalent queries through REST and confirm show_in_rest behavior. | Every execution path performs its own permission and input checks. |
Why this usually happens
- The same callback can appear correct when tested against a registry with only one category.
- REST discovery adds a visibility requirement that a direct PHP registry lookup does not.
- Custom metadata needs a REST schema when clients expect reliable value coercion.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
$abilities = wp_get_abilities( array(
'category' => 'analytics',
'namespace' => 'acme',
'meta' => array( 'risk' => 'read' ),
'item_include_callback' => function ( $ability ) {
return 'acme/private-report' !== $ability->get_name();
},
) );
Test scenarios to run
Run the same controlled fixture across these branches. Write down the expected result before testing so a surprising response is easy to identify.
| Scenario | Fixture | Expected result |
| Declarative | Filter one category, namespace, and exact metadata key | Only exact registered matches remain |
| Item callback | Reject one ability by ID after declarative matching | Rejected item never reaches the result callback |
| Result callback | Sort or cap the filtered collection | Result changes after item-level inclusion |
| REST | Request the same namespace through the REST endpoint | Only abilities with show_in_rest true are exposed |
Safe fix order
Use a sequence that makes each result easy to prove. Stop when new evidence changes the scope or owner of the problem.
- Build a fixture registry
- Assert declarative matches
- Trace callback order
- Repeat through REST
- Test permission before execution
Decision rule
Hold the integration when PHP and REST discovery differ without an intentional visibility rule, metadata values coerce unpredictably, callback order changes results, or a client mistakes discovery for permission.
Production verification checklist
- Each declarative filter returns the expected exact IDs.
- Item, result, and global filters run in the documented order.
- REST results include only abilities intentionally exposed through show_in_rest.
- Every execution path performs its own permission and input checks.
Field notes
- Use synthetic abilities that cannot mutate production state.
- Log IDs after every stage so ordering failures are visible.
- Keep discovery, permission, validation, and execution assertions separate.
Questions teams ask during testing
Is filtering an authorization layer?
No. The Core dev note explicitly separates discovery filtering from permission checks.
Why can REST return fewer abilities than PHP?
The REST controller requires abilities to expose show_in_rest metadata.
When is direct registry access appropriate?
Use it only when the code truly needs unfiltered internal registry data and that choice is documented.
Mistakes to avoid
- Do not use raw registry access as the default discovery path.
- Do not treat a returned ability as authorization to run it.
- Do not test metadata coercion without a REST schema.
- Do not combine every filter before each stage passes alone.
What to tell the client or owner
Provide the ability ID, category, namespace, metadata, show_in_rest value, request arguments, stage-by-stage IDs, REST response, permission result, and WordPress build.
When HandL WP should help
HandL WP can build an Abilities API fixture, trace each filtering stage, compare PHP and REST results, define metadata schemas, and verify permission boundaries.
If this is active on a production site, test a WordPress Abilities API integration.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Helpful references