Make WordPress Core

Changeset 61390


Ignore:
Timestamp:
12/17/2025 03:27:28 PM (4 months ago)
Author:
jorgefilipecosta
Message:

Abilities API: Enhance WP_Ability validation for execute_callback and permission_callback.

Abilities API allows for extending WP_Ability by providing ability_class during the ability registration. This is meant to unlock complex abilities holding some sort of state or logic that requires multiple helper methods.
In all of those scenarios you would ovewrite execute or do_execute method.
However, because the check for execute_callback is in constructor, then in order to register an ability with ability_class overwrite, you have to BOTH: provide do_execute and provide a dummy execute_callback. The same need happens for permission_callback.
This commit fixes the issue execute_callback and permission_callback are now optional when a class is provided.

Props artpi, swissspidy, jorgefilipecosta, mindctrl.
Fixes #64407.

Location:
trunk
Files:
1 added
2 edited

Legend:

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

    r61086 r61390  
    278278        }
    279279
    280         if ( empty( $args['execute_callback'] ) || ! is_callable( $args['execute_callback'] ) ) {
     280        // If we are not overriding `ability_class` parameter during instantiation, then we need to validate the execute_callback.
     281        if ( get_class( $this ) === self::class && ( empty( $args['execute_callback'] ) || ! is_callable( $args['execute_callback'] ) ) ) {
    281282            throw new InvalidArgumentException(
    282283                __( 'The ability properties must contain a valid `execute_callback` function.' )
     
    284285        }
    285286
    286         if ( empty( $args['permission_callback'] ) || ! is_callable( $args['permission_callback'] ) ) {
     287        // If we are not overriding `ability_class` parameter during instantiation, then we need to validate the permission_callback.
     288        if ( get_class( $this ) === self::class && ( empty( $args['permission_callback'] ) || ! is_callable( $args['permission_callback'] ) ) ) {
    287289            throw new InvalidArgumentException(
    288290                __( 'The ability properties must provide a valid `permission_callback` function.' )
  • trunk/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php

    r61364 r61390  
    2424     */
    2525    public function set_up(): void {
     26        require_once DIR_TESTDATA . '/../includes/class-tests-custom-ability-class.php';
     27
    2628        parent::set_up();
    2729
     
    259261
    260262    /**
     263     * Should allow ability registration with custom ability_class that overrides do_execute.
     264     *
     265     * @ticket 64407
     266     *
     267     * @covers WP_Abilities_Registry::register
     268     * @covers WP_Ability::prepare_properties
     269     */
     270    public function test_register_with_custom_ability_class_without_execute_callback() {
     271        // Remove execute_callback and permission_callback since the custom class provides its own implementation.
     272        unset( self::$test_ability_args['execute_callback'] );
     273        unset( self::$test_ability_args['permission_callback'] );
     274
     275        self::$test_ability_args['ability_class'] = 'Tests_Custom_Ability_Class';
     276
     277        $result = $this->registry->register( self::$test_ability_name, self::$test_ability_args );
     278
     279        $this->assertInstanceOf( WP_Ability::class, $result, 'Should return a WP_Ability instance.' );
     280        $this->assertInstanceOf( Tests_Custom_Ability_Class::class, $result, 'Should return an instance of the custom class.' );
     281
     282        // Verify the custom execute method works.
     283        $execute_result = $result->execute(
     284            array(
     285                'a' => 5,
     286                'b' => 3,
     287            )
     288        );
     289        $this->assertSame( 15, $execute_result, 'Custom do_execute should multiply instead of add.' );
     290    }
     291
     292    /**
    261293     * Should reject ability registration without an execute callback.
    262294     *
Note: See TracChangeset for help on using the changeset viewer.