Skip to content

feat: add AbstractAbility and AbstractAbilityRegistrar - #76

Open
Adi-ty wants to merge 2 commits into
mainfrom
feat/ability-abstracts
Open

feat: add AbstractAbility and AbstractAbilityRegistrar#76
Adi-ty wants to merge 2 commits into
mainfrom
feat/ability-abstracts

Conversation

@Adi-ty

@Adi-ty Adi-ty commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Add AbstractAbility and AbstractAbilityRegistrar — telemetry-agnostic base classes for the WordPress 6.9+ Abilities API. The telemetry-shaped AbstractAbility from wp-dev-tools is decomposed: registration timing and category ownership live on the registrar, the ability stays a plain describable object. Both are hook-guarded, so the package's 6.5 floor is unchanged.

Closes

Part of rtcamp/wp-devtools#12

Changes

  • inc/Contracts/Abstracts/AbstractAbility.php — declarative base with name(), label(), description(), category(), input_schema(), output_schema(), execute(); overridable permission() (default: manage_options, fail-closed) and meta() (default: [], exposure opt-in); args() maps to wp_register_ability() shape, omitting empty schemas/meta
  • inc/Contracts/Abstracts/AbstractAbilityRegistrar.php — implements Registrable; attaches to wp_abilities_api_categories_init (category) and wp_abilities_api_init (abilities); abstract category_slug(), category_description(), abilities(); overridable category_label() (title-cases slug), before_register() hook; category registration idempotent across registrars
  • tests/Contracts/Abstracts/AbstractAbilityTest.php — 10 tests covering arg mapping, schema omission, meta default/propagation, permission tiers, permission override, input pass-through; pure logic, runs on all WP versions
  • Docs — README (10→12 abstracts), docs/abstracts.md (new "Abilities" cookbook with full example), docs/index.md (twelve)
  • AI instructions — ai/framework-php.instructions.md: add Feature/Ability/AbilityRegistrar to abstracts brace list, add wp_register_ability to direct-call rule 5; .github/instructions/php.instructions.md: add all three to abstracts list; AGENTS.md: note Abilities API guard

How I verified

❯ composer lint
DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4.0.
The WordPressVIPMinimum.JS.Window sniff is listening for JS.
DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4.0.
The WordPressVIPMinimum.JS.DangerouslySetInnerHTML sniff is listening for JS.
DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4.0.
The WordPressVIPMinimum.JS.InnerHTML sniff is listening for JS.
DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4.0.
The WordPressVIPMinimum.JS.StrippingTags sniff is listening for JS.
DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4.0.
The WordPressVIPMinimum.JS.StringConcat sniff is listening for JS.
DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4.0.
The WordPressVIPMinimum.JS.HTMLExecutingFunctions sniff is listening for JS.

........ 8 / 8 (100%)


Time: 582ms; Memory: 16MB

❯ composer analyse
Note: Using configuration file /Users/adi/rtproj/wp-php-toolkit/phpstan.neon.dist.
 30/30 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%


                                                                                                                        
 [OK] No errors                                                                                                         
                                                                                                                        

❯ npm run test:php

> wp-framework@0.0.1 pretest:php
> wp-env run tests-cli --env-cwd=wp-content/wp-framework-rt -- composer install --no-interaction

ℹ Starting 'composer install --no-interaction' on the tests-cli container. 

Composer could not detect the root package (rtcamp/wp-framework) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating optimized autoload files
Class rtCamp\WPFramework\Tests\Fixtures\LoaderRunner located in ./tests/Fixtures/LoaderFixtures.php does not comply with psr-4 autoloading standard (rule: rtCamp\WPFramework\Tests\ => ./tests). Skipping.
Class rtCamp\WPFramework\Tests\Fixtures\PlainRegistrable located in ./tests/Fixtures/LoaderFixtures.php does not comply with psr-4 autoloading standard (rule: rtCamp\WPFramework\Tests\ => ./tests). Skipping.
Class rtCamp\WPFramework\Tests\Fixtures\ConditionalAllowed located in ./tests/Fixtures/LoaderFixtures.php does not comply with psr-4 autoloading standard (rule: rtCamp\WPFramework\Tests\ => ./tests). Skipping.
Class rtCamp\WPFramework\Tests\Fixtures\ConditionalDenied located in ./tests/Fixtures/LoaderFixtures.php does not comply with psr-4 autoloading standard (rule: rtCamp\WPFramework\Tests\ => ./tests). Skipping.
Class rtCamp\WPFramework\Tests\Fixtures\ShareableRegistrable located in ./tests/Fixtures/LoaderFixtures.php does not comply with psr-4 autoloading standard (rule: rtCamp\WPFramework\Tests\ => ./tests). Skipping.
34 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
✔ Ran `composer install --no-interaction` in 'tests-cli'. (in 2s 912ms)

> wp-framework@0.0.1 test:php
> wp-env run tests-cli --env-cwd=wp-content/wp-framework-rt -- vendor/bin/phpunit -c phpunit.xml.dist

ℹ Starting 'vendor/bin/phpunit -c phpunit.xml.dist' on the tests-cli container. 

Installing...
Running as single site... To run multisite, use -c tests/phpunit/multisite.xml
Not running ajax tests. To execute these, use --group ajax.
Not running ms-files tests. To execute these, use --group ms-files.
Not running external-http tests. To execute these, use --group external-http.
PHPUnit 9.6.34 by Sebastian Bergmann and contributors.

Random Seed:   1784796014
Warning:       No code coverage driver available

...............................................................  63 / 238 ( 26%)
............................................................... 126 / 238 ( 52%)
............................................................... 189 / 238 ( 79%)
.................................................               238 / 238 (100%)

Time: 00:00.614, Memory: 48.50 MB

OK (238 tests, 487 assertions)
✔ Ran `vendor/bin/phpunit -c phpunit.xml.dist` in 'tests-cli'. (in 2s 929ms)

Acceptance criteria

Runtime behavior

  • AbstractAbility and AbstractAbilityRegistrar exist in wp-framework with unit tests; a trivial ability can be defined and registers on wp_abilities_api_init.
  • Abilities round-trip via wp_get_ability() with correct label/category
  • On WP < 6.9: all registrar tests skip, ability tests run (pure logic)

Code quality

  • Lint — zero errors
  • Static analysis — zero errors
  • Tests pass

Reviewer notes

  • AbstractAbility does not implement Registrable — abilities may only be registered inside the Abilities API init hooks, so the paired registrar owns that timing. This diverges from the usual Abstract* pattern but is called out in the class docblock and the cookbook.

Adi-ty added 2 commits July 23, 2026 13:52
Telemetry-agnostic base classes for the WordPress Abilities API (6.9+),
lifted from the shape proven in rtcamp/wp-dev-tools (rtCamp/wp-devtools#12,
item 1). AbstractAbility declares the pieces of an ability and maps them to
wp_register_ability() args; AbstractAbilityRegistrar (a Registrable) hooks
wp_abilities_api_categories_init / wp_abilities_api_init, registers the
shared category idempotently, and loops its abilities.

Both callbacks are wrapped in defaulted closures because core invokes them
with zero arguments when no input schema is declared. category_description()
is abstract: core rejects categories without a non-empty description. On
cores older than 6.9 the hooks never fire, so the registrar is inert and the
package's WordPress floor is unchanged.
Abstracts cookbook gains an Abilities section (must-implement list, override
seams, shared-category consumer example, the WP <6.9 inertness note); README
and docs index updated. The AI-instruction ability lists now name the ability
abstracts and wp_register_ability, and pick up AbstractFeature, which was
missing from both since it landed.
@Adi-ty
Adi-ty marked this pull request as ready for review July 23, 2026 08:45
Copilot AI review requested due to automatic review settings July 23, 2026 08:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds WordPress Abilities API abstractions, registration support, tests, and consumer guidance.

Changes:

  • Introduces AbstractAbility and AbstractAbilityRegistrar.
  • Adds unit and integration coverage for mapping, permissions, registration, and execution.
  • Updates framework documentation and AI instructions.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
inc/Contracts/Abstracts/AbstractAbility.php Defines the ability contract and registration arguments.
inc/Contracts/Abstracts/AbstractAbilityRegistrar.php Registers categories and abilities on API hooks.
tests/Contracts/Abstracts/AbstractAbilityTest.php Tests argument mapping and permissions.
tests/Contracts/Abstracts/AbstractAbilityRegistrarTest.php Tests registration and execution round-trips.
README.md Lists the new abstracts.
docs/index.md Updates abstract counts and navigation.
docs/abstracts.md Adds the Abilities API cookbook.
ai/framework-php.instructions.md Adds consumer review guidance.
.github/instructions/php.instructions.md Updates the framework abstract inventory.
AGENTS.md Documents WordPress-version compatibility.

Comment on lines +94 to +96
* @return array<string, mixed>|\WP_Error Result data, or an error.
*/
abstract public function execute( mixed $input ): array|\WP_Error;
@Adi-ty Adi-ty changed the title Feat/ability abstracts feat: add AbstractAbility and AbstractAbilityRegistrar Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants