Make WordPress Core

Changeset 61130


Ignore:
Timestamp:
11/04/2025 04:32:45 PM (5 weeks ago)
Author:
jorgefilipecosta
Message:

Abilities API: Use stricter doing_action check when registering.

Applies feedback provided that doing_action would be better check on this situation to avoid developers facing future registration timing issues.

Developed in #10452.

Props gziolo, jorgefilipecosta, flixos90, mukesh27, jason_the_adams.
See #64098.

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/abilities-api.php

    r61086 r61130  
    277277 */
    278278function wp_register_ability( string $name, array $args ): ?WP_Ability {
    279     if ( ! did_action( 'wp_abilities_api_init' ) ) {
     279    if ( ! doing_action( 'wp_abilities_api_init' ) ) {
    280280        _doing_it_wrong(
    281281            __FUNCTION__,
     
    466466 */
    467467function wp_register_ability_category( string $slug, array $args ): ?WP_Ability_Category {
    468     if ( ! did_action( 'wp_abilities_api_categories_init' ) ) {
     468    if ( ! doing_action( 'wp_abilities_api_categories_init' ) ) {
    469469        _doing_it_wrong(
    470470            __FUNCTION__,
  • trunk/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php

    r61032 r61130  
    3030        remove_all_filters( 'wp_register_ability_args' );
    3131
    32         // Fire the init hook to allow test ability category registration.
    33         do_action( 'wp_abilities_api_categories_init' );
     32        // Simulates the Abilities API init hook to allow test ability category registration.
     33        global $wp_current_filter;
     34        $wp_current_filter[] = 'wp_abilities_api_categories_init';
    3435        wp_register_ability_category(
    3536            'math',
     
    3940            )
    4041        );
     42        array_pop( $wp_current_filter );
    4143
    4244        self::$test_ability_args = array(
  • trunk/tests/phpunit/tests/abilities-api/wpAbility.php

    r61032 r61130  
    1818    public function set_up(): void {
    1919        parent::set_up();
    20 
    21         // Fire the init hook to allow test ability category registration.
    22         do_action( 'wp_abilities_api_categories_init' );
    23         wp_register_ability_category(
    24             'math',
    25             array(
    26                 'label'       => 'Math',
    27                 'description' => 'Mathematical operations and calculations.',
    28             )
    29         );
    3020
    3121        self::$test_ability_properties = array(
     
    5747     */
    5848    public function tear_down(): void {
    59         // Clean up registered test ability category.
    60         wp_unregister_ability_category( 'math' );
    61 
    6249        parent::tear_down();
    6350    }
  • trunk/tests/phpunit/tests/abilities-api/wpRegisterAbility.php

    r61032 r61130  
    3030     */
    3131    public function set_up(): void {
     32        global $wp_current_filter;
     33
    3234        parent::set_up();
    3335
    34         // Fire the init hook to allow test ability category registration.
    35         do_action( 'wp_abilities_api_categories_init' );
     36        // Simulate the init hook for ability categories to allow test ability category registration.
     37        $wp_current_filter[] = 'wp_abilities_api_categories_init';
    3638        wp_register_ability_category(
    3739            'math',
     
    8789     */
    8890    public function tear_down(): void {
     91        global $wp_current_filter;
     92
    8993        foreach ( wp_get_abilities() as $ability ) {
    9094            if ( ! str_starts_with( $ability->get_name(), 'test/' ) ) {
     
    102106
    103107    /**
     108     * Simulates the `wp_abilities_api_init` action.
     109     */
     110    private function simulate_doing_wp_abilities_init_action() {
     111        global $wp_current_filter;
     112
     113        $wp_current_filter[] = 'wp_abilities_api_init';
     114    }
     115
     116    /**
    104117     * Tests registering an ability with invalid name.
    105118     *
     
    109122     */
    110123    public function test_register_ability_invalid_name(): void {
    111         do_action( 'wp_abilities_api_init' );
     124        $this->simulate_doing_wp_abilities_init_action();
    112125
    113126        $result = wp_register_ability( 'invalid_name', array() );
     
    117130
    118131    /**
    119      * Tests registering an ability when `abilities_api_init` action has not fired.
     132     * Tests registering an ability when `wp_abilities_api_init` action has not fired.
    120133     *
    121134     * @ticket 64098
     
    124137     */
    125138    public function test_register_ability_no_abilities_api_init_action(): void {
    126         global $wp_actions;
    127 
    128         // Store the original action count.
    129         $original_count = isset( $wp_actions['wp_abilities_api_init'] ) ? $wp_actions['wp_abilities_api_init'] : 0;
    130 
    131         // Reset the action count to simulate it not being fired.
    132         unset( $wp_actions['wp_abilities_api_init'] );
    133 
    134         $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args );
    135 
    136         // Restore the original action count.
    137         if ( $original_count > 0 ) {
    138             $wp_actions['wp_abilities_api_init'] = $original_count;
    139         }
     139        $this->assertFalse( doing_action( 'wp_abilities_api_init' ) );
     140
     141        $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args );
    140142
    141143        $this->assertNull( $result );
     
    152154        global $wp_actions;
    153155
    154         do_action( 'wp_abilities_api_init' );
    155 
    156156        // Store the original action count.
    157157        $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
     
    159159        // Reset the action count to simulate it not being fired.
    160160        unset( $wp_actions['init'] );
     161
     162        $this->simulate_doing_wp_abilities_init_action();
    161163
    162164        $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args );
     
    176178     */
    177179    public function test_register_valid_ability(): void {
    178         do_action( 'wp_abilities_api_init' );
     180        $this->simulate_doing_wp_abilities_init_action();
    179181
    180182        $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args );
     
    226228     */
    227229    public function test_register_ability_no_permissions(): void {
    228         do_action( 'wp_abilities_api_init' );
     230        $this->simulate_doing_wp_abilities_init_action();
    229231
    230232        self::$test_ability_args['permission_callback'] = static function (): bool {
     
    261263     */
    262264    public function test_register_ability_custom_ability_class(): void {
    263         do_action( 'wp_abilities_api_init' );
     265        $this->simulate_doing_wp_abilities_init_action();
    264266
    265267        $result = wp_register_ability(
     
    303305     */
    304306    public function test_execute_ability_no_input_schema_match(): void {
    305         do_action( 'wp_abilities_api_init' );
     307        $this->simulate_doing_wp_abilities_init_action();
    306308
    307309        $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args );
     
    332334     */
    333335    public function test_execute_ability_no_output_schema_match(): void {
    334         do_action( 'wp_abilities_api_init' );
     336        $this->simulate_doing_wp_abilities_init_action();
    335337
    336338        self::$test_ability_args['execute_callback'] = static function (): bool {
     
    363365     */
    364366    public function test_validate_input_no_input_schema_match(): void {
    365         do_action( 'wp_abilities_api_init' );
     367        $this->simulate_doing_wp_abilities_init_action();
    366368
    367369        $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args );
     
    392394     */
    393395    public function test_permission_callback_receives_input(): void {
    394         do_action( 'wp_abilities_api_init' );
     396        $this->simulate_doing_wp_abilities_init_action();
    395397
    396398        $received_input                                 = null;
     
    454456        unset( $wp_actions['init'] );
    455457
     458        $this->simulate_doing_wp_abilities_init_action();
     459
    456460        $result = wp_unregister_ability( self::$test_ability_name );
    457461
     
    470474     */
    471475    public function test_unregister_existing_ability() {
    472         do_action( 'wp_abilities_api_init' );
     476        $this->simulate_doing_wp_abilities_init_action();
    473477
    474478        wp_register_ability( self::$test_ability_name, self::$test_ability_args );
     
    497501        // Reset the action count to simulate it not being fired.
    498502        unset( $wp_actions['init'] );
     503
     504        $this->simulate_doing_wp_abilities_init_action();
    499505
    500506        $result = wp_get_ability( self::$test_ability_name );
     
    514520     */
    515521    public function test_get_existing_ability_using_callback() {
     522        $this->simulate_doing_wp_abilities_init_action();
     523
    516524        $name     = self::$test_ability_name;
    517525        $args     = self::$test_ability_args;
     
    557565        unset( $wp_actions['init'] );
    558566
     567        $this->simulate_doing_wp_abilities_init_action();
     568
    559569        $result = wp_has_ability( self::$test_ability_name );
    560570
     
    573583     */
    574584    public function test_has_registered_ability() {
    575         do_action( 'wp_abilities_api_init' );
     585        $this->simulate_doing_wp_abilities_init_action();
    576586
    577587        wp_register_ability( self::$test_ability_name, self::$test_ability_args );
     
    588598     */
    589599    public function test_has_registered_nonexistent_ability() {
    590         do_action( 'wp_abilities_api_init' );
     600        $this->simulate_doing_wp_abilities_init_action();
    591601
    592602        $result = wp_has_ability( 'test/non-existent' );
     
    610620        // Reset the action count to simulate it not being fired.
    611621        unset( $wp_actions['init'] );
     622
     623        $this->simulate_doing_wp_abilities_init_action();
    612624
    613625        $result = wp_get_abilities();
     
    627639     */
    628640    public function test_get_all_registered_abilities() {
    629         do_action( 'wp_abilities_api_init' );
     641        $this->simulate_doing_wp_abilities_init_action();
    630642
    631643        $ability_one_name = 'test/ability-one';
  • trunk/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php

    r61032 r61130  
    4646
    4747    /**
    48      * Test registering ability category before `abilities_api_categories_init` hook.
     48     * Simulates the `wp_abilities_api_categories_init` action.
     49     */
     50    private function simulate_doing_wp_ability_categories_init_action() {
     51        global $wp_current_filter;
     52
     53        $wp_current_filter[] = 'wp_abilities_api_categories_init';
     54    }
     55
     56    /**
     57     * Test registering ability category before `wp_abilities_api_categories_init` hook.
    4958     *
    5059     * @ticket 64098
     
    5362     */
    5463    public function test_register_category_before_init_hook(): void {
     64        $this->assertFalse( doing_action( 'wp_abilities_api_categories_init' ) );
     65
    5566        $result = wp_register_ability_category(
    5667            self::$test_ability_category_name,
     
    7182        global $wp_actions;
    7283
    73         do_action( 'wp_abilities_api_categories_init' );
    74 
    75         // Store the original action count.
    76         $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
    77 
    78         // Reset the action count to simulate it not being fired.
    79         unset( $wp_actions['init'] );
     84        // Store the original action count.
     85        $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
     86
     87        // Reset the action count to simulate it not being fired.
     88        unset( $wp_actions['init'] );
     89
     90        $this->simulate_doing_wp_ability_categories_init_action();
    8091
    8192        $result = wp_register_ability_category(
     
    98109     */
    99110    public function test_register_valid_category(): void {
    100         do_action( 'wp_abilities_api_categories_init' );
     111        $this->simulate_doing_wp_ability_categories_init_action();
    101112
    102113        $result = wp_register_ability_category(
     
    121132        global $wp_actions;
    122133
    123         do_action( 'wp_abilities_api_categories_init' );
    124 
    125         // Store the original action count.
    126         $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
    127 
    128         // Reset the action count to simulate it not being fired.
    129         unset( $wp_actions['init'] );
     134        // Store the original action count.
     135        $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
     136
     137        // Reset the action count to simulate it not being fired.
     138        unset( $wp_actions['init'] );
     139
     140        $this->simulate_doing_wp_ability_categories_init_action();
    130141
    131142        $result = wp_unregister_ability_category( self::$test_ability_category_name );
     
    147158     */
    148159    public function test_unregister_nonexistent_category(): void {
    149         do_action( 'wp_abilities_api_categories_init' );
     160        $this->simulate_doing_wp_ability_categories_init_action();
    150161
    151162        $result = wp_unregister_ability_category( 'test-nonexistent' );
     
    160171     */
    161172    public function test_unregister_existing_category(): void {
    162         do_action( 'wp_abilities_api_categories_init' );
     173        $this->simulate_doing_wp_ability_categories_init_action();
    163174
    164175        wp_register_ability_category(
     
    183194        global $wp_actions;
    184195
    185         do_action( 'wp_abilities_api_categories_init' );
    186 
    187         // Store the original action count.
    188         $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
    189 
    190         // Reset the action count to simulate it not being fired.
    191         unset( $wp_actions['init'] );
     196        // Store the original action count.
     197        $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
     198
     199        // Reset the action count to simulate it not being fired.
     200        unset( $wp_actions['init'] );
     201
     202        $this->simulate_doing_wp_ability_categories_init_action();
    192203
    193204        $result = wp_has_ability_category( self::$test_ability_category_name );
     
    207218     */
    208219    public function test_has_registered_nonexistent_ability_category(): void {
    209         do_action( 'wp_abilities_api_categories_init' );
     220        $this->simulate_doing_wp_ability_categories_init_action();
    210221
    211222        $result = wp_has_ability_category( 'test/non-existent' );
     
    220231     */
    221232    public function test_has_registered_ability_category(): void {
    222         do_action( 'wp_abilities_api_categories_init' );
     233        $this->simulate_doing_wp_ability_categories_init_action();
    223234
    224235        $category_slug = self::$test_ability_category_name;
     
    244255        global $wp_actions;
    245256
    246         do_action( 'wp_abilities_api_categories_init' );
    247 
    248         // Store the original action count.
    249         $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
    250 
    251         // Reset the action count to simulate it not being fired.
    252         unset( $wp_actions['init'] );
     257        // Store the original action count.
     258        $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
     259
     260        // Reset the action count to simulate it not being fired.
     261        unset( $wp_actions['init'] );
     262
     263        $this->simulate_doing_wp_ability_categories_init_action();
    253264
    254265        $result = wp_get_ability_category( self::$test_ability_category_name );
     
    270281     */
    271282    public function test_get_nonexistent_category(): void {
    272         do_action( 'wp_abilities_api_categories_init' );
     283        $this->simulate_doing_wp_ability_categories_init_action();
    273284
    274285        $result = wp_get_ability_category( 'test-nonexistent' );
     
    317328        global $wp_actions;
    318329
    319         do_action( 'wp_abilities_api_categories_init' );
    320 
    321         // Store the original action count.
    322         $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
    323 
    324         // Reset the action count to simulate it not being fired.
    325         unset( $wp_actions['init'] );
     330        // Store the original action count.
     331        $original_count = isset( $wp_actions['init'] ) ? $wp_actions['init'] : 0;
     332
     333        // Reset the action count to simulate it not being fired.
     334        unset( $wp_actions['init'] );
     335
     336        $this->simulate_doing_wp_ability_categories_init_action();
    326337
    327338        $result = wp_get_ability_categories( self::$test_ability_category_name );
     
    341352     */
    342353    public function test_get_all_categories(): void {
    343         do_action( 'wp_abilities_api_categories_init' );
     354        $this->simulate_doing_wp_ability_categories_init_action();
    344355
    345356        wp_register_ability_category(
  • trunk/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php

    r61045 r61130  
    6363        do_action( 'rest_api_init' );
    6464
    65         // Initialize the API and register test ability categories.
    66         do_action( 'wp_abilities_api_categories_init' );
    6765        $this->register_test_ability_categories();
    6866
     
    9492     */
    9593    public function register_test_ability_categories(): void {
     94        // Simulates the init hook to allow test ability categories registration.
     95        global $wp_current_filter;
     96        $wp_current_filter[] = 'wp_abilities_api_categories_init';
     97
    9698        wp_register_ability_category(
    9799            'test-data-retrieval',
     
    131133            );
    132134        }
     135
     136        array_pop( $wp_current_filter );
    133137    }
    134138
  • trunk/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php

    r61032 r61130  
    3838        );
    3939
    40         // Fire the init hook to allow test ability categories registration.
    41         do_action( 'wp_abilities_api_categories_init' );
    4240        self::register_test_categories();
    4341    }
     
    6866        do_action( 'rest_api_init' );
    6967
    70         // Initialize Abilities API.
    71         do_action( 'wp_abilities_api_init' );
    7268        $this->register_test_abilities();
    7369
     
    10096     */
    10197    public static function register_test_categories(): void {
     98        // Simulates the init hook to allow test ability categories registration.
     99        global $wp_current_filter;
     100        $wp_current_filter[] = 'wp_abilities_api_categories_init';
     101
    102102        wp_register_ability_category(
    103103            'math',
     
    123123            )
    124124        );
     125
     126        array_pop( $wp_current_filter );
     127    }
     128
     129    /**
     130     * Helper to register a test ability.
     131     *
     132     * @param string $name Ability name.
     133     * @param array  $args Ability arguments.
     134     */
     135    private function register_test_ability( string $name, array $args ): void {
     136        // Simulates the init hook to allow test abilities registration.
     137        global $wp_current_filter;
     138        $wp_current_filter[] = 'wp_abilities_api_init';
     139
     140        wp_register_ability( $name, $args );
     141
     142        array_pop( $wp_current_filter );
    125143    }
    126144
     
    130148    private function register_test_abilities(): void {
    131149        // Register a regular ability.
    132         wp_register_ability(
     150        $this->register_test_ability(
    133151            'test/calculator',
    134152            array(
     
    174192
    175193        // Register a read-only ability.
    176         wp_register_ability(
     194        $this->register_test_ability(
    177195            'test/system-info',
    178196            array(
     
    221239
    222240        // Ability that does not show in REST.
    223         wp_register_ability(
     241        $this->register_test_ability(
    224242            'test/not-show-in-rest',
    225243            array(
     
    236254        // Register multiple abilities for pagination testing
    237255        for ( $i = 1; $i <= 60; $i++ ) {
    238             wp_register_ability(
     256            $this->register_test_ability(
    239257                "test/ability-{$i}",
    240258                array(
     
    590608    public function test_ability_name_with_valid_special_characters(): void {
    591609        // Register ability with hyphen (valid).
    592         wp_register_ability(
     610        $this->register_test_ability(
    593611            'test-hyphen/ability',
    594612            array(
  • trunk/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php

    r61047 r61130  
    5050        );
    5151
    52         // Fire the init hook to allow test ability categories registration.
    53         do_action( 'wp_abilities_api_categories_init' );
    5452        self::register_test_categories();
    5553    }
     
    7977        do_action( 'rest_api_init' );
    8078
    81         // Initialize Abilities API.
    82         do_action( 'wp_abilities_api_init' );
    8379        $this->register_test_abilities();
    8480
     
    110106     */
    111107    public static function register_test_categories(): void {
     108        // Simulates the init hook to allow test ability category registration.
     109        global $wp_current_filter;
     110        $wp_current_filter[] = 'wp_abilities_api_categories_init';
     111
    112112        wp_register_ability_category(
    113113            'math',
     
    133133            )
    134134        );
     135
     136        array_pop( $wp_current_filter );
     137    }
     138
     139    /**
     140     * Helper to register a test ability.
     141     *
     142     * @param string $name Ability name.
     143     * @param array  $args Ability arguments.
     144     */
     145    private function register_test_ability( string $name, array $args ): void {
     146        // Simulates the init hook to allow test abilities registration.
     147        global $wp_current_filter;
     148        $wp_current_filter[] = 'wp_abilities_api_init';
     149
     150        wp_register_ability( $name, $args );
     151
     152        array_pop( $wp_current_filter );
    135153    }
    136154
     
    140158    private function register_test_abilities(): void {
    141159        // Regular ability (POST only).
    142         wp_register_ability(
     160        $this->register_test_ability(
    143161            'test/calculator',
    144162            array(
     
    177195
    178196        // Read-only ability (GET method).
    179         wp_register_ability(
     197        $this->register_test_ability(
    180198            'test/user-info',
    181199            array(
     
    223241
    224242        // Destructive ability (DELETE method).
    225         wp_register_ability(
     243        $this->register_test_ability(
    226244            'test/delete-user',
    227245            array(
     
    264282
    265283        // Ability with contextual permissions
    266         wp_register_ability(
     284        $this->register_test_ability(
    267285            'test/restricted',
    268286            array(
     
    295313
    296314        // Ability that does not show in REST.
    297         wp_register_ability(
     315        $this->register_test_ability(
    298316            'test/not-show-in-rest',
    299317            array(
     
    309327
    310328        // Ability that returns null
    311         wp_register_ability(
     329        $this->register_test_ability(
    312330            'test/null-return',
    313331            array(
     
    326344
    327345        // Ability that returns WP_Error
    328         wp_register_ability(
     346        $this->register_test_ability(
    329347            'test/error-return',
    330348            array(
     
    343361
    344362        // Ability with invalid output
    345         wp_register_ability(
     363        $this->register_test_ability(
    346364            'test/invalid-output',
    347365            array(
     
    363381
    364382        // Read-only ability for query params testing.
    365         wp_register_ability(
     383        $this->register_test_ability(
    366384            'test/query-params',
    367385            array(
     
    464482     */
    465483    public function test_regular_ability_requires_post(): void {
    466         wp_register_ability(
     484        $this->register_test_ability(
    467485            'test/open-tool',
    468486            array(
     
    794812    public function test_output_validation_failure_returns_error(): void {
    795813        // Register ability with strict output schema.
    796         wp_register_ability(
     814        $this->register_test_ability(
    797815            'test/strict-output',
    798816            array(
     
    843861    public function test_input_validation_failure_returns_error(): void {
    844862        // Register ability with strict input schema.
    845         wp_register_ability(
     863        $this->register_test_ability(
    846864            'test/strict-input',
    847865            array(
     
    892910    public function test_ability_without_annotations_defaults_to_post_method(): void {
    893911        // Register ability without annotations.
    894         wp_register_ability(
     912        $this->register_test_ability(
    895913            'test/no-annotations',
    896914            array(
     
    927945     */
    928946    public function test_empty_input_handling_get_method(): void {
    929         wp_register_ability(
     947        $this->register_test_ability(
    930948            'test/read-only-empty',
    931949            array(
     
    959977     */
    960978    public function test_empty_input_handling_get_method_with_normalized_input(): void {
    961         wp_register_ability(
     979        $this->register_test_ability(
    962980            'test/read-only-empty-array',
    963981            array(
     
    9951013     */
    9961014    public function test_empty_input_handling_post_method(): void {
    997         wp_register_ability(
     1015        $this->register_test_ability(
    9981016            'test/regular-empty',
    9991017            array(
     
    10661084    public function test_php_type_strings_in_input(): void {
    10671085        // Register ability that accepts any input
    1068         wp_register_ability(
     1086        $this->register_test_ability(
    10691087            'test/echo',
    10701088            array(
     
    11151133    public function test_mixed_encoding_in_input(): void {
    11161134        // Register ability that accepts any input
    1117         wp_register_ability(
     1135        $this->register_test_ability(
    11181136            'test/echo-encoding',
    11191137            array(
     
    11841202    public function test_invalid_http_methods( string $method ): void {
    11851203        // Register an ability with no permission requirements for this test
    1186         wp_register_ability(
     1204        $this->register_test_ability(
    11871205            'test/method-test',
    11881206            array(
Note: See TracChangeset for help on using the changeset viewer.