[wp-trac] [WordPress Trac] #65248: Abilities API: add `wp_ability_invoked` action for pipeline-entry observers

WordPress Trac noreply at wordpress.org
Fri May 15 11:38:16 UTC 2026


#65248: Abilities API: add `wp_ability_invoked` action for pipeline-entry observers
---------------------------+--------------------
 Reporter:  gziolo         |      Owner:  (none)
     Type:  enhancement    |     Status:  new
 Priority:  normal         |  Milestone:  7.1
Component:  Abilities API  |    Version:  6.9
 Severity:  normal         |   Keywords:
  Focuses:                 |
---------------------------+--------------------
 The execution lifecycle filters proposed in #64989 give the Abilities API
 four
 seams: `wp_pre_execute_ability`, `wp_before_execute_ability`,
 `wp_after_execute_ability`,
 and `wp_execute_ability_result`. `wp_before_execute_ability` fires after
 input
 normalization, validation, and the permission check — its contract is
 "execution is
 imminent." That contract is correct: rate-limiter, cached-response, and
 dry-run observers
 all rely on it not firing for calls that exit early.

 That leaves a gap for audit and snapshot observers, which need the
 opposite signal: "the
 pipeline received this invocation, regardless of outcome." They want a
 hook that fires
 for every call — approval-pending, rate-limited, cached, dry-run, and
 normal — so the
 audit row exists no matter how the call exits, and fires before
 normalization so the
 input is captured raw.

 == Proposal ==

 Add a `wp_ability_invoked` action at the top of `WP_Ability::execute()`,
 before
 `wp_pre_execute_ability` runs:

 {{{
 #!php
 do_action( 'wp_ability_invoked', $this->name, $input, $this );
 }}}

 The argument shape mirrors `wp_before_execute_ability` so observers can
 attach the same
 callback signature to both hooks. The past-tense verb communicates
 "entered the pipeline"
 without implying the call will execute.

 == Lifecycle position ==

 {{{
 execute( $input ) {
     do_action( 'wp_ability_invoked', ... );      // new — every call, raw
 input
     apply_filters( 'wp_pre_execute_ability', ... ); // existing — short-
 circuit seam
     // normalize_input → validate_input → check_permissions
     do_action( 'wp_before_execute_ability', ... ); // existing — execution
 imminent
     // execute_callback
     do_action( 'wp_after_execute_ability', ... );
     return apply_filters( 'wp_execute_ability_result', ... );
 }
 }}}

 == Motivation ==

 Surfaced in
 [https://github.com/WordPress/ai/discussions/477#discussioncomment-16900589
 WordPress/ai#477]. The AbilityGuard plugin currently writes its audit row
 inline inside
 its `wp_pre_execute_ability` handler because no earlier signal exists,
 which conflates
 "build the approval envelope" with "record that an invocation happened."
 Landing
 `wp_ability_invoked` lets that work move to a dedicated observer listener
 and keeps the
 pre-execute handler focused on its short-circuit responsibility.

 The same signal benefits any observability layer that needs invocation
 entry counts
 independent of outcome (telemetry, rate-limit accounting that includes
 rejected calls,
 etc.).

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/65248>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list