Abilities API: add execution lifecycle filters to WP_Ability methods#11731
Abilities API: add execution lifecycle filters to WP_Ability methods#11731gziolo wants to merge 4 commits intoWordPress:trunkfrom
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
a8dc90a to
f59694c
Compare
Introduces a new filter inside `WP_Ability::normalize_input()` that fires after the method's built-in default-value handling, allowing plugins to transform input — for example, prompt enrichment or parameter defaulting beyond what JSON Schema handles. Returning a `WP_Error` halts execution. `WP_Ability::execute()` now short-circuits when `normalize_input()` returns a `WP_Error`, so a halt from the filter propagates as the execute result without reaching `validate_input()`, `check_permissions()`, or the `wp_before_execute_ability` action. Props gziolo. Fixes #64989.
Introduces a new filter inside `WP_Ability::check_permissions()` that fires after the registered `permission_callback` returns. Plugins can use it to enforce additional authorization rules — transport-level permission layering for protocol adapters, multi-factor gates, or temporary elevation for batch operations. Because the filter lives inside the method, overrides apply consistently across `execute()`, REST API permission checks, and WP-CLI call sites. Filters can return `true`, `false`, or a `WP_Error`. Props gziolo. Fixes #64989.
Introduces a short-circuit filter at the top of `WP_Ability::execute()`, modeled on `rest_pre_dispatch`. Returning a non-null value bypasses the entire pipeline — `normalize_input()`, `validate_input()`, `check_permissions()`, the registered `execute_callback`, output validation, and the `wp_before_execute_ability` / `wp_after_execute_ability` actions are all skipped, and the filter's return value is returned to the caller as-is. Useful for cached responses, rate limiting, maintenance mode, and test mocking. Callers that short-circuit are responsible for input integrity since input validation does not run. Props gziolo. Fixes #64989.
Introduces a new filter inside `WP_Ability::do_execute()` that fires after the registered `execute_callback` returns. Plugins can use it to transform the result — response formatting, stripping internal metadata, content safety filtering, response enrichment — or to recover from an execution failure by returning a successful value in place of a `WP_Error`. Because `do_execute()` is invoked from `WP_Ability::execute()` between `check_permissions()` and `validate_output()`, the transformed value is still validated against `output_schema` before the `wp_after_execute_ability` action fires. Placing the filter inside `do_execute()` keeps each "result" filter consistent with `wp_ability_normalize_input` and `wp_ability_permission_result`, which sit inside the methods whose return values they filter. Props gziolo. Fixes #64989.
f59694c to
9b2aa9a
Compare
Summary
Adds four new filters to
WP_Abilityto give plugins hook points across the executionlifecycle. Today the only execution-phase hooks are observation-only actions
(
wp_before_execute_ability,wp_after_execute_ability); plugins that need totransform input, modify output, override permission decisions, or short-circuit
execution have no place to do that in core, and have built parallel hook systems
on top.
This PR closes that gap by introducing four filters, three living inside their
owning
WP_Abilitymethods (so they apply consistently acrossexecute(), RESTpermission checks, and WP-CLI), and one on
execute()itself for orchestrationcontrol.
Filters added
wp_pre_execute_abilityexecute()rest_pre_dispatch).wp_ability_normalize_inputnormalize_input()WP_Errorhalts execution.wp_ability_permission_resultcheck_permissions()permission_callbackresult. Applies consistently across all call sites.wp_ability_execute_resultexecute(), afterdo_execute()do_execute()failures by returning a successful value in place ofWP_Error.Pipeline ordering inside
execute()Schema validation remains the final integrity gate:
wp_ability_normalize_inputfires before
validate_input(), andwp_ability_execute_resultfires beforevalidate_output(). Filters cannot bypass schema validation except byshort-circuiting via
wp_pre_execute_ability, where the caller takesresponsibility for the returned value's shape.
Commits
This PR is split into four atomic commits, one per filter, in lifecycle order.
Reviewers can read commit-by-commit or as a single diff.
wp_ability_normalize_inputwp_ability_permission_resultwp_pre_execute_abilitywp_ability_execute_resultTest plan
npm run env:composer -- format— cleannpm run env:composer -- lint— cleannpm run env:composer -- compat— cleannpm run typecheck:php— 0 errorsnpm run test:php -- --group=abilities-api— 263/263 passingTests_Theme_ThemeDir::test_broken_themes, fails on trunk too)20 new tests cover:
wp_pre_execute_ability(asserts no downstream filter, action, callback fires).wp_ability_execute_resultruns before output validation and beforewp_after_execute_ability.wp_ability_execute_resultreceivingWP_Errorfromdo_execute().wp_ability_permission_resultfiring whencheck_permissions()is called directly (REST/WP-CLI path).WP_Errorpropagation fromwp_ability_normalize_inputhalts the rest of the pipeline.Trac ticket
https://core.trac.wordpress.org/ticket/64989
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.7 (1M context)
Used for: Planning, implementation, unit tests, commit messages, and PR description.