Skip to content

Commit c049ddc

Browse files
committed
Enhance WP_Ability validation for execute_callback
This commit updates the WP_Ability class to validate the execute_callback only when the ability_class parameter is not overridden during instantiation.
1 parent 48b2b65 commit c049ddc

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

src/wp-includes/abilities-api/class-wp-ability.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ protected function prepare_properties( array $args ): array {
277277
);
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.' )
283284
);

tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,30 @@ public function test_register_incorrect_execute_callback_type() {
257257
$this->assertNull( $result );
258258
}
259259

260+
/**
261+
* Should allow ability registration with custom ability_class that overrides do_execute.
262+
*
263+
* @ticket 64098
264+
*
265+
* @covers WP_Abilities_Registry::register
266+
* @covers WP_Ability::prepare_properties
267+
*/
268+
public function test_register_with_custom_ability_class_without_execute_callback() {
269+
// Remove execute_callback since the custom class provides its own implementation.
270+
unset( self::$test_ability_args['execute_callback'] );
271+
272+
self::$test_ability_args['ability_class'] = 'Tests_Custom_Ability_Class';
273+
274+
$result = $this->registry->register( self::$test_ability_name, self::$test_ability_args );
275+
276+
$this->assertInstanceOf( WP_Ability::class, $result, 'Should return a WP_Ability instance.' );
277+
$this->assertInstanceOf( Tests_Custom_Ability_Class::class, $result, 'Should return an instance of the custom class.' );
278+
279+
// Verify the custom execute method works.
280+
$execute_result = $result->execute( array( 'a' => 5, 'b' => 3 ) );
281+
$this->assertSame( 15, $execute_result, 'Custom do_execute should multiply instead of add.' );
282+
}
283+
260284
/**
261285
* Should reject ability registration without an execute callback.
262286
*
@@ -651,3 +675,32 @@ static function ( $args, $name ) {
651675
$this->assertNotSame( $filtered_ability->get_label(), $unfiltered_ability->get_label(), 'The filter incorrectly modified the args for an ability it should not have.' );
652676
}
653677
}
678+
679+
/**
680+
* Test custom ability class that extends WP_Ability.
681+
*
682+
* This class overrides do_execute() and check_permissions() directly,
683+
* allowing registration without execute_callback or permission_callback.
684+
*/
685+
class Tests_Custom_Ability_Class extends WP_Ability {
686+
687+
/**
688+
* Custom execute implementation that multiplies instead of adds.
689+
*
690+
* @param mixed $input The input data.
691+
* @return int The result of multiplying a and b.
692+
*/
693+
protected function do_execute( $input = null ) {
694+
return $input['a'] * $input['b'];
695+
}
696+
697+
/**
698+
* Custom permission check that always returns true.
699+
*
700+
* @param mixed $input The input data.
701+
* @return bool Always true.
702+
*/
703+
public function check_permissions( $input = null ) {
704+
return true;
705+
}
706+
}

0 commit comments

Comments
 (0)