This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Implement server-side registry for Abilities API - #3

Merged
gziolo merged 6 commits into
trunkfrom
add/server-side-registry
Aug 13, 2025
Merged

Implement server-side registry for Abilities API #3
gziolo merged 6 commits into
trunkfrom
add/server-side-registry

Conversation

@gziolo

@gziologziolo commented Aug 8, 2025

Copy link
Copy Markdown
Member

Closes#1.

PR in WordPress core, which validates compatibility and whether tests pass:

Proposed API

Registering an ability

functionexample_register_add_numbers_ability() {
wp_register_ability(
'example/add-numbers',
[
'label' => 'Add numbers',
'description' => 'Calculates the result of adding two numbers.',
'input_schema' => [
'type' => 'object',
'properties' => [
'a' => [
'type' => 'number',
'description' => 'First number.',
'required' => true,
],
'b' => [
'type' => 'number',
'description' => 'Second number.',
'required' => true,
],
],
'additionalProperties' => false,
],
'output_schema' => [
'type' => 'number',
'description' => 'The result of adding the two numbers.',
'required' => true,
],
'execute_callback' => function ( array$input ): int {
return$input['a'] + $input['b'];
},
'permission_callback' => function (): bool {
returntrue;
},
'meta' => [
'category' => 'math',
],
]
);
}
add_action( 'abilities_api_init', 'example_register_add_numbers_ability' );

Unregistering an ability

wp_unregister_ability( 'example/add-numbers' );

Retrieving a specific ability

$ability = wp_get_ability( 'example/add-numbers' );

Retrieving all abilities

$abilities = wp_get_abilities();

Operations on abilities

$ability = wp_get_ability( 'example/add-numbers' );
$ability->has_permission( [ 'a' => 2, 'b' => 3 ] ); // trueecho$ability->execute( [ 'a' => 2, 'b' => 3 ] ); // 5

@gziologziolo self-assigned this Aug 8, 2025
@gziologziolo added [Status] In Progress Assigned work scheduled [Type] Task Issues or PRs that have been broken down into an individual action to take labels Aug 8, 2025
@gziolo

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a server-side registry for the WordPress Abilities API, introducing the core infrastructure for registering and managing abilities with validation, permissions, and execution capabilities.

  • Introduces a complete abilities registry system with registration, validation, and management functionality
  • Implements ability classes with input/output schema validation and permission handling
  • Provides global functions for registering, unregistering, and retrieving abilities

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/abilities-api.phpMain API functions for registering, unregistering, and retrieving abilities
src/class-wp-abilities-registry.phpRegistry class for managing ability registration and lookup with validation
src/class-wp-ability.phpCore ability class with validation, permission checking, and execution methods
tests/unit/AbilitiesAPITest.phpComprehensive unit tests for the global API functions
tests/unit/WPAbilitiesRegistryTest.phpUnit tests for registry validation and management functionality
phpunit.xml.distPHPUnit configuration for running unit tests
.editorconfigEditor configuration for consistent code formatting

Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadsrc/class-wp-abilities-registry.php Outdated
Comment threadtests/unit/WPAbilitiesRegistryTest.php Outdated
gzioloand others added 3 commits August 8, 2025 13:38
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gziolo

gziolo commented Aug 8, 2025

Copy link
Copy Markdown
MemberAuthor

The proposed initial implementation for server-side registry with testing code coverage is ready to receive the initial feedback. What's still missing is the unit tests configuration in a standalone repository, as I developed and tested everything with the WordPress core testing infrastructure available.

To better illustrate that I opened a PR in WordPress Core to ensure all the CI checks pass and all unit tests work:

CI for WP core still validates against PHP 7.2 and 7.3, so that might enforce some syntax changes as these jobs fail ... It looks like unit tests pass on 7.4 and higher as expected.

PHPCS doesn't like the followign things:

  • Typed properties are not supported in PHP 7.3 or earlier
  • Short array syntax is not allowed
  • Trailing comma's are not allowed in function calls in PHP 7.2 or earlier

I'm inclined to address these issues to avoid a compatibility mismatch.

@justlevine

Copy link
Copy Markdown
Contributor

I'm inclined to address these issues to avoid a compatibility mismatch.

IMHO dont waste the time rn

PHP 7.4 is coming to core in either 6.9 or 7.0, so either way in time for this to be merged, but more important once I set up vipcs locally most these code standard fails will autofix.

Comment threadsrc/abilities-api.php

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would recommend using inc/ instead of src/. I've got a feeling we're gonna need use some @wordpress/* packages that need to be built down the road.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Initially, I wanted to replicate https://github.com/WordPress/php-ai-client and went with src for PHP, but I agree that it's hard to use one pattern because we expect both PHP and JS code in this repo. Gutenberg uses packages and lib. Here we also need to take into account a need for a composer package, and an npm package. It isn't so simple to pick right folder names 😅

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Naming things is always the hardest part 😬

I don’t think GB (JS-first monorepo) or php-ai-client (standalone Composer lib) are quite the right references for a feature (or canonical) plugin.

FWIW, heres what other official WordPress/* projects are doing:

  • WordPress/TwoFactor and Performance Plugins (e.g. use includes for PHP and scatter JS (assets, root-level css/js folders, src)
  • Health Check: PHP in HealthCheck namespace, build-step assets in src.
  • PCP uses includes for PHP and assets for JS/CSS`.
  • WordPress Importer uses src for PHP but it's legacy and has no js/css.

Semantically it seems the general pattern is

  • includes (or inc but that might be more of an a8c thing, havn't seen it in WordPress/*) = core PHP (no build step)
  • src are plugin assets that need a build step. OR sometimes they're co-located assets. (OR sometimes non-buildable PHP)
  • packages reusable (and usually releasable) JS/TS libraries.
  • havnt found any consistent use of lib in the org.

tl;dr I think includes or inc is best for clarity (unlike src we know PHP is expected to be there). Then, if/when we need buildable assets for the admin we can see whether assets vs buildable src (or a ts package, but that seems unlikely in this repo) make sense without being boxed in by semantics.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting find is that there are best practices for WP plugins at https://developer.wordpress.org/plugins/plugin-basics/best-practices/#folder-structure. I see includes there. src for JavaScript code makes sense, too. The remaining question is where we locate the composer package and npm package that we will need here allowing early access to server-side registry, REST API controller, and the client-side package with the client-side registry that also integrates the server-side registry through REST API call.

@gziologzioloAug 11, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I implemented previously wp-scripts plugin-zip command and this is what I found there today:

https://github.com/WordPress/gutenberg/blob/fc937dccee20e7b0e6dfa671f6afac03f4bf6ef5/packages/scripts/scripts/plugin-zip.js#L32-L46

Let's go with includes to have an easy way to integrate that. For JS output, we can use either build or public.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I figured out it's best to tackle it in #4 after we land the initial code. This way it's going to be much easier to handle every code change while the CI is running.

@justlevine

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core. (Unlike individual performance plugins which arent meant to be extended or rly used in 3rd-party code

@gziolo

Copy link
Copy Markdown
MemberAuthor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.

My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

Overall, in WP core you can find some libs like SimplePie, PhpMailer, Sodium that use namespaces, but they were forked from preexisting projects. I don't know whether there is enough support to use namespaces for other parts of codebase in WP core. From the composer package perspective, using namespaces would only help, but there is the backward compatibility question as part of that once this code gets included in WP core.

@justlevine

justlevine commented Aug 9, 2025

Copy link
Copy Markdown
Contributor

Should we use a namespace WordPress/Abilities instead of the root WP_* ? Gutenberg doesnt, Performance does.
My gut says we should, because like GB our goal here is for experimentation/extenders and we don't want to have to worry about breaking back-compat when we merge into core.

Gutenberg doesn't use namespaces, so I'm a little bit confused. Did you mean we shouldn't?

FML This is why I shouldn't do code review after midnight 🤦 I meant to ask if we want to prefix or suffix.

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

Although I guess my subconscious mind was suggesting that namespaces could solve the same problem, but make the eventual migration even easier, e.g:

// If the final API doesnt change, then the user only needs to remove the `use` statement
- use SomeNamespace\wp_get_ability;
...
wp_get_ability( ...$args );
/// versus search-replace in the code logic
- some_prefix_get_ability( ...$args );+ wp_get_ability( ...$args );

@gziolo

Copy link
Copy Markdown
MemberAuthor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

@gziolo

Copy link
Copy Markdown
MemberAuthor

For the sake of illustration, I fixed all issues reported in WordPress/wordpress-develop#9410 regarding PHP 7.2 and coding standards compatibility with 1975276. In particular, the changes around types might need to be reverted when we opt to go with PHP 7.4 as the minimum required version, but the rest might be fine to leave as is.

@justlevine

Copy link
Copy Markdown
Contributor

For example: WP_Duotone_Gutenberg becomes WP_Duotone in core.

This is used that way only when Gutenberg wants to override the preexisting class in WP Core. If the class or function doesn't exist then in Gutenberg the strategy is to polyfiil the functionality using check if such thing exists to prevent double declaration.

I know better than to attempt to Gutenberg-splain to you 🙇 Thanks for the correction, I must be having some mandela effect moment about not needing to worry about my Fonts API or Interactivity API experiments clashing on merge until I renamed them 🤦

So with absolutely 0 WordPress prior art the question becomes more generically: "do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem (both of which I think we can agree do have prior art in WordPress 😅).

@gziolo

Copy link
Copy Markdown
MemberAuthor

do we want to take some preventative measures (prefixing or namespacing) to allow for immediate 3rd party adoption/use of the Abilities API without worrying about carrying tech-debt into core with us or breaking the early-ecosystem

We definitely should provide some recommendations on how to safely use the package in a way that will eventually get replaced by the version that ships in WP core. I'm not entirely sure what that will be, but that's part of the story we need to design. @jonathanbossenger plans to work on the documentation as outlined in #5, so we definitely need to coordinate with him.

@gziolo
gziolo marked this pull request as ready for review August 13, 2025 04:45
@gziolo

Copy link
Copy Markdown
MemberAuthor

Both #4 and #6 depend on this PR, so let's land it first. I tested everything against WordPress core CI, see WordPress/wordpress-develop#9410. We can follow up with the tooling afterwards, while in parallel extend the logic with REST API controllers.

@gziolo
gziolo merged commit e7249f2 into trunkAug 13, 2025
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 04:58
@gziolo
gziolo restored the add/server-side-registry branch August 13, 2025 04:59
@gziolo
gziolo deleted the add/server-side-registry branch August 13, 2025 05:15
@gziologziolo removed the [Status] In Progress Assigned work scheduled label Aug 14, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

[Type] TaskIssues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement server-side registry for Abilities API

3 participants

@gziolo@justlevine