Skip to content

Conversation

@jorgefilipecosta
Copy link
Member

This PR Expands ability name validation from exactly 2 segments (namespace/ability) to 2-4 segments, enabling names like my-plugin/resource/find and my-plugin/resource/sub/find.

Details

The current ability naming convention only allows a single namespace separator (my-plugin/my-ability). This is too restrictive for organizing abilities into logical resource groups. With this change, plugins can register abilities like core/posts/find, core/posts/create, or my-plugin/resource/sub/action.

The validation regex in WP_Abilities_Registry::register() changes from:

/^[a-z0-9-]+\/[a-z0-9-]+$/

to:

/^[a-z0-9-]+(?:\/[a-z0-9-]+){1,3}$/

This allows the first segment plus 1-3 additional slash-delimited segments (2-4 total). The REST API route patterns in both controllers already accepted multiple slashes, so no route changes were needed.

This PR comes from a suggestion from @justlevine at #10665 (comment) :

Necessary caveats out of the way, I'd recommend we solve the naming issue holistically with nested namespaces, a pattern that because it's good for human cognitive overload, which just so happens to mean that it aligns with inference best practices too. (related: core.trac.wordpress.org/ticket/64345#comment:5).

Which would turn these into:

core/posts/find or get (As noted inline, I think getting a single post is superfluous, and both use cases can be more intuitively handled with an improved input shape, e.g. by ).
core/posts/create
core/posts/update

And we plan to use this new type of naming for post abilities.

cc: @justlevine, @JasonTheAdams

Test plan

  • Run npm run test:php -- --group abilities-api and verify all tests pass
  • Verify existing 2-segment ability names (core/get-site-info, etc.) continue to work
  • Verify 3-segment names like test/math/add can be registered and executed via REST
  • Verify 5-segment names are rejected with a clear error message

Expand ability name validation from exactly 2 segments (namespace/ability)
to 2-4 segments, enabling names like my-plugin/resource/find and
my-plugin/resource/sub/find. Update the validation regex, error messages,
docblocks, and add corresponding unit and REST API tests.
*/
public function register( string $name, array $args ): ?WP_Ability {
if ( ! preg_match( '/^[a-z0-9-]+\/[a-z0-9-]+$/', $name ) ) {
if ( ! preg_match( '/^[a-z0-9-]+(?:\/[a-z0-9-]+){1,3}$/', $name ) ) {
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if we should limit to 4 segments or just allow unlimited segments, but I fear unlimited segments may endup being overused, and it better ti be more restrictive than than the oposite. In the future we can always go from 4 to unlimited but we can not go from unlimited to 4.

Choose a reason for hiding this comment

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

@jorgefilipecosta I tend to agree with you (especially re the directionality of future compat) but just to follow the thought through: what is the concern of "too many" nested segments? Are there hypothetical scenarios you can think of where we would benefit from implementing a fixed limit now or as things evolve?

(PS: If there's a limit, I think 4 is a good number and practical guardrail. More than 3 layers of nesting and you likely want to recheck your assumptions about using Abilities; 2 semantic levels for folks who want to experiment with a versioning antipattern also seems fair).

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

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

  • The Plugin and Theme Directories cannot be accessed within Playground.
  • 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.

Comment on lines +229 to +231
* @param string $name The name of the ability. Must contain 2 to 4 segments separated
* by forward slashes, e.g., `my-plugin/my-ability` or
* `my-plugin/resource/my-ability`. Can only contain lowercase

Choose a reason for hiding this comment

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

I would keep the number of segments here as an implementation detail, and out of the param description. E.g. Must be the fully-namespaced string identifier, e.g. my-plugin/my-abilityormy-plugin/resource/my-ability`. (and then also drop the lowercase etc, this function is unregistering an existing ability the requirement is that an ability exists with that identical identifier. )

$result = $this->registry->register( 'test/add-numbers/', self::$test_ability_args );
$this->assertNull( $result );
}

Choose a reason for hiding this comment

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

Do we also need to test deregistering?

(IMO no since it's just string matching to something in the registry, no coersion. Related: https://github.com/WordPress/wordpress-develop/pull/10848/files#r2756209961 )

Copy link

@justlevine justlevine left a comment

Choose a reason for hiding this comment

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

LGTM - left some comments to confirm no implicit assumptions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants