Skip to content

Abilities API: Allow abilities to declare required capabilities - #14335

Closed
gziolo wants to merge 8 commits into
WordPress:trunkfrom
gziolo:add/abilities-required-capabilities
Closed

gziolo wants to merge 8 commits into
WordPress:trunkfrom
gziolo:add/abilities-required-capabilities

Conversation

@gziolo

@gziolo gziolo commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

What

Abilities can now declare the capabilities a user needs to run them:

wp_register_ability(
	'core/get-site-info',
	array(
		'label'                 => __( 'Get Site Information' ),
		'description'           => __( 'Returns basic information about the site.' ),
		'category'              => 'site',
		'required_capabilities' => array( 'manage_options' ),
		'execute_callback'      => 'wp_abilities_get_site_info',
	)
);

Today wp_get_abilities() lists every ability, even the ones the current user can't run. With this change, callers like AI agents and MCP adapters can ask for only the abilities the current user can use. No permission callbacks need to run for that.

How it works

Registration

  • required_capabilities is a top-level argument, like permission_callback. It must be a list of non-empty strings.
  • permission_callback is required unless required_capabilities lists at least one capability.
  • An empty list doesn't replace permission_callback. To let everyone run an ability, use 'permission_callback' => '__return_true'. The public meta flag doesn't affect this. It only controls where the ability is shown.
  • A permission_callback that is set must be callable, even when capabilities are listed.

Execution

check_permissions( $input ) combines both checks with AND:

  1. Each required capability is checked with current_user_can(). If one is missing, the check fails and the callback doesn't run.
  2. If all capabilities pass and there is a permission_callback, it runs with $input, as it does today.
  3. The wp_ability_permission_result filter runs on the final result, including a failure from step 1.

If only one of the two is set, that one decides. Custom ability_class subclasses skip the registration checks. For them, check_permissions() returns the ability_invalid_permission_callback error when the callback is set but not callable, or when both the callback and the capabilities are missing.

Listing

  • wp_get_abilities() accepts 'has_required_capabilities' => true. It leaves out abilities whose required capabilities the current user doesn't have.
  • Abilities without required_capabilities stay in the result, because their permission may depend on the input.
  • Permission callbacks and filters don't run here, so an included ability can still deny execution.
  • It runs after the category, namespace, and meta filters and before item_include_callback.
  • The wp-abilities/v1/abilities route accepts a matching has_required_capabilities query parameter.
  • The REST response includes required_capabilities, so JavaScript clients can hide UI for abilities the user can't run.

Core abilities

core/get-site-info, core/get-environment-info, and core/settings-get only checked manage_options. They now use required_capabilities instead of a closure.

New public API

  • required_capabilities registration argument.
  • WP_Ability::get_required_capabilities(): array.
  • has_required_capabilities argument for wp_get_abilities() and the REST list route.
  • required_capabilities field in the REST response.

Testing

npm run test:php -- --group 66325
npm run test:php -- --group abilities-api

Follow-ups

  • The JavaScript packages (@wordpress/abilities and @wordpress/core-abilities) live in the Gutenberg repository and will follow separately.

Trac ticket: https://core.trac.wordpress.org/ticket/66325

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: Implementation and tests, based on the design in the Trac ticket. I reviewed and adjusted the code and tests.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props gziolo.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@gziolo
gziolo force-pushed the add/abilities-required-capabilities branch from 19e7314 to d8e0ffe Compare October 16, 2026 09:47
@gziolo gziolo self-assigned this Oct 19, 2026
gziolo and others added 8 commits October 19, 2026 11:48
Adds a `required_capabilities` argument to `wp_register_ability()`. It is a
list of capabilities the current user must have to run the ability.

`WP_Ability::check_permissions()` checks these capabilities first. The
`permission_callback` only runs when they all pass. The callback is optional
when the list is not empty.

`wp_get_abilities()` accepts a new `current_user_can` argument. It leaves out
abilities that declare capabilities the current user doesn't have, without
calling any permission callbacks. The REST list route gets a matching query
parameter and includes `required_capabilities` in the response.

Core abilities that only check `manage_options` now use the new argument.

See #66325.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lity filter.

See #66325.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Uses shorter and more consistent wording for `permission_callback`,
`required_capabilities`, and the `has_required_capabilities` filter.
Removes reasoning that was repeated in several places.

See #66325.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merges similar tests into data providers and groups the helpers.
Keeps the ticket reference only on newly added tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gziolo
gziolo force-pushed the add/abilities-required-capabilities branch from d8e0ffe to 8f7d992 Compare October 19, 2026 09:49
wporg-sync pushed a commit that referenced this pull request Oct 19, 2026
Add `required_capabilities` to ability registration and expose it in REST responses. Check these capabilities before permission callbacks, allowing the callback to be omitted when capabilities are declared. Add `has_required_capabilities` filtering to `wp_get_abilities()` and the REST collection endpoint without running permission callbacks.

Developed in: #14335

Props ovidiu-galatan.
Fixes #66325.




git-svn-id: https://develop.svn.wordpress.org/trunk@64500 602fd350-edb4-49c9-b593-d223f7449a82
@github-actions

Copy link
Copy Markdown

A commit was made that fixes the Trac ticket referenced in the description of this pull request.

SVN changeset: 64500
GitHub commit: 1881d63

This PR will be closed, but please confirm the accuracy of this and reopen if there is more work to be done.

@github-actions github-actions Bot closed this Oct 19, 2026
@gziolo
gziolo deleted the add/abilities-required-capabilities branch October 19, 2026 11:15
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Oct 19, 2026
Add `required_capabilities` to ability registration and expose it in REST responses. Check these capabilities before permission callbacks, allowing the callback to be omitted when capabilities are declared. Add `has_required_capabilities` filtering to `wp_get_abilities()` and the REST collection endpoint without running permission callbacks.

Developed in: WordPress/wordpress-develop#14335

Props ovidiu-galatan.
Fixes #66325.



Built from https://develop.svn.wordpress.org/trunk@64500


git-svn-id: http://core.svn.wordpress.org/trunk@63650 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant