diff --git a/docs/2.getting-started.md b/docs/2.getting-started.md index a19927c..d6a88c5 100644 --- a/docs/2.getting-started.md +++ b/docs/2.getting-started.md @@ -133,10 +133,27 @@ add_action( 'admin_init', 'my_plugin_use_ability' ); function my_plugin_use_ability() { $ability = wp_get_ability( 'my-plugin/get-site-title' ); - if ( $ability && $ability->has_permission() ) { - $site_title = $ability->execute(); - // $site_title now holds the result of get_bloginfo('name') - // error_log( 'Site Title: ' . $site_title ); + if ( $ability ) { + // Check permissions first - always use is_wp_error() to handle errors properly + $permission = $ability->check_permission(); + if ( is_wp_error( $permission ) ) { + // Handle permission error + error_log( 'Permission error: ' . $permission->get_error_message() ); + return; + } elseif ( $permission ) { + // Permission granted - safe to execute + $site_title = $ability->execute(); + if ( is_wp_error( $site_title ) ) { + // Handle execution error + error_log( 'Execution error: ' . $site_title->get_error_message() ); + } else { + // $site_title now holds the result of get_bloginfo('name') + // error_log( 'Site Title: ' . $site_title ); + } + } else { + // Permission denied + error_log( 'Permission denied for ability execution' ); + } } } ``` diff --git a/docs/4.using-abilities.md b/docs/4.using-abilities.md index 71d97ce..2c5053e 100644 --- a/docs/4.using-abilities.md +++ b/docs/4.using-abilities.md @@ -124,9 +124,14 @@ if ( $ability ) { } ``` -**Checking Permissions (`$ability->has_permission()`)** +**Checking Permissions (`$ability->check_permission()`)** -Before executing an ability, you can check if the current user has permission: +Before executing an ability, you can check if the current user has permission. The `check_permission()` method returns either `true`, `false`, or a `WP_Error` object, so you must use `is_wp_error()` to handle errors properly: + +```php +// Method signature: +// check_permission( $input = null ) +``` ```php $ability = wp_get_ability( 'my-plugin/update-option' ); @@ -136,12 +141,17 @@ if ( $ability ) { 'option_value' => 'New Site Name', ); - // Check permission before execution - if ( $ability->has_permission( $input ) ) { + // Check permission before execution - always use is_wp_error() first + $permission = $ability->check_permission( $input ); + if ( is_wp_error( $permission ) ) { + // Handle permission check error (validation, callback error, etc.) + echo 'Permission check failed: ' . $permission->get_error_message(); + } elseif ( $permission ) { + // Permission granted - safe to execute $result = $ability->execute( $input ); if ( is_wp_error( $result ) ) { - // Handle WP_Error - echo 'Error: ' . $result->get_error_message(); + // Handle execution error + echo 'Execution error: ' . $result->get_error_message(); } else { // Use $result if ( $result['success'] ) { @@ -150,6 +160,7 @@ if ( $ability ) { } } } else { + // Permission denied echo 'You do not have permission to execute this ability.'; } } diff --git a/includes/abilities-api/class-wp-ability.php b/includes/abilities-api/class-wp-ability.php index 267c876..560233a 100644 --- a/includes/abilities-api/class-wp-ability.php +++ b/includes/abilities-api/class-wp-ability.php @@ -312,12 +312,12 @@ protected function validate_input( $input = null ) { * * The input is validated against the input schema before it is passed to to permission callback. * - * @since 0.1.0 + * @since N.E.X.T * * @param mixed $input Optional. The input data for permission checking. Default `null`. * @return bool|\WP_Error Whether the ability has the necessary permission. */ - public function has_permission( $input = null ) { + public function check_permission( $input = null ) { $is_valid = $this->validate_input( $input ); if ( is_wp_error( $is_valid ) ) { return $is_valid; @@ -330,6 +330,24 @@ public function has_permission( $input = null ) { return call_user_func( $this->permission_callback, $input ); } + /** + * Checks whether the ability has the necessary permissions (deprecated). + * + * The input is validated against the input schema before it is passed to to permission callback. + * + * @deprecated N.E.X.T Use check_permission() instead. + * @see WP_Ability::check_permission() + * + * @since 0.1.0 + * + * @param mixed $input Optional. The input data for permission checking. Default `null`. + * @return bool|\WP_Error Whether the ability has the necessary permission. + */ + public function has_permission( $input = null ) { + _deprecated_function( __METHOD__, 'N.E.X.T', 'WP_Ability::check_permission()' ); + return $this->check_permission( $input ); + } + /** * Executes the ability callback. * @@ -394,7 +412,7 @@ protected function validate_output( $output ) { * @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure. */ public function execute( $input = null ) { - $has_permissions = $this->has_permission( $input ); + $has_permissions = $this->check_permission( $input ); if ( true !== $has_permissions ) { if ( is_wp_error( $has_permissions ) ) { if ( 'ability_invalid_input' === $has_permissions->get_error_code() ) { diff --git a/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php b/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php index 64fc223..699685b 100644 --- a/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php +++ b/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php @@ -163,7 +163,7 @@ public function run_ability_permissions_check( $request ) { } $input = $this->get_input_from_request( $request ); - if ( ! $ability->has_permission( $input ) ) { + if ( ! $ability->check_permission( $input ) ) { return new \WP_Error( 'rest_ability_cannot_execute', __( 'Sorry, you are not allowed to execute this ability.' ), diff --git a/tests/unit/abilities-api/wpRegisterAbility.php b/tests/unit/abilities-api/wpRegisterAbility.php index 22330b2..f25df2b 100644 --- a/tests/unit/abilities-api/wpRegisterAbility.php +++ b/tests/unit/abilities-api/wpRegisterAbility.php @@ -134,7 +134,7 @@ public function test_register_valid_ability(): void { $this->assertSame( self::$test_ability_args['output_schema'], $result->get_output_schema() ); $this->assertSame( self::$test_ability_args['meta'], $result->get_meta() ); $this->assertTrue( - $result->has_permission( + $result->check_permission( array( 'a' => 2, 'b' => 3, @@ -164,7 +164,7 @@ public function test_register_ability_no_permissions(): void { $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args ); $this->assertFalse( - $result->has_permission( + $result->check_permission( array( 'a' => 2, 'b' => 3, @@ -289,7 +289,7 @@ public function test_permission_callback_no_input_schema_match(): void { $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args ); - $actual = $result->has_permission( + $actual = $result->check_permission( array( 'a' => 2, 'b' => 3, @@ -308,6 +308,27 @@ public function test_permission_callback_no_input_schema_match(): void { ); } + /** + * Tests that deprecated has_permission() method still works. + * + * @expectedDeprecated WP_Ability::has_permission + */ + public function test_has_permission_deprecated_coverage(): void { + do_action( 'abilities_api_init' ); + + $result = wp_register_ability( self::$test_ability_name, self::$test_ability_args ); + + // Test that deprecated method still works + $this->assertTrue( + $result->has_permission( + array( + 'a' => 2, + 'b' => 3, + ) + ) + ); + } + /** * Tests permission callback receiving input for contextual permission checks. */ @@ -325,7 +346,7 @@ public function test_permission_callback_receives_input(): void { // Test with a > b (should be allowed) $this->assertTrue( - $result->has_permission( + $result->check_permission( array( 'a' => 5, 'b' => 3, @@ -342,7 +363,7 @@ public function test_permission_callback_receives_input(): void { // Test with a < b (should be denied) $this->assertFalse( - $result->has_permission( + $result->check_permission( array( 'a' => 2, 'b' => 8,