Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions docs/2.getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,15 @@ 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() ) {
if ( $ability ) {
$site_title = $ability->execute();
// $site_title now holds the result of get_bloginfo('name')
// error_log( 'Site Title: ' . $site_title );
if ( is_wp_error( $site_title ) ) {
// Handle any error (permission, validation, or execution)
error_log( 'Error: ' . $site_title->get_error_message() );
} else {
// $site_title now holds the result of get_bloginfo('name')
// error_log( 'Site Title: ' . $site_title );
}
}
}
```
61 changes: 42 additions & 19 deletions docs/4.using-abilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ $site_info_ability = wp_get_ability( 'my-plugin/get-site-info' );
if ( $site_info_ability ) {
// Ability exists and is registered
$result = $site_info_ability->execute();
if ( is_wp_error( $site_info ) ) {
// Handle WP_Error
echo 'Error: ' . $site_info->get_error_message();
if ( is_wp_error( $result ) ) {
// Handle any error (permission, validation, or execution)
echo 'Error: ' . $result->get_error_message();
} else {
// Use $site_info array
echo 'Site Name: ' . $site_info['name'];
// Use result data
echo 'Site Name: ' . $result['name'];
}
} else {
// Ability not found or not registered
Expand Down Expand Up @@ -74,10 +74,10 @@ $ability = wp_get_ability( 'my-plugin/get-site-info' );
if ( $ability ) {
$site_info = $ability->execute(); // No input required
if ( is_wp_error( $site_info ) ) {
// Handle WP_Error
// Handle any error (permission, validation, or execution)
echo 'Error: ' . $site_info->get_error_message();
} else {
// Use $site_info array
// Use result data
echo 'Site Name: ' . $site_info['name'];
}
}
Expand Down Expand Up @@ -124,9 +124,11 @@ if ( $ability ) {
}
```

**Checking Permissions (`$ability->has_permission()`)**

Before executing an ability, you can check if the current user has permission:
**Understanding Permissions**

Abilities handle permission checking automatically during execution. The `execute()` method will check permissions and return a `WP_Error` if access is denied. You rarely need to check permissions separately.


```php
$ability = wp_get_ability( 'my-plugin/update-option' );
Expand All @@ -136,21 +138,42 @@ if ( $ability ) {
'option_value' => 'New Site Name',
);

// Check permission before execution
if ( $ability->has_permission( $input ) ) {
$result = $ability->execute( $input );
if ( is_wp_error( $result ) ) {
// Handle WP_Error
echo 'Error: ' . $result->get_error_message();
} else {
// Use $result
// Recommended approach: execute() handles permission checking internally
$result = $ability->execute( $input );
if ( is_wp_error( $result ) ) {
// Handle any error (permission, validation, or execution)
echo 'Error: ' . $result->get_error_message();
} else {
// Success - use the result
if ( $result['success'] ) {
echo 'Option updated successfully!';
echo 'Previous value: ' . $result['previous_value'];
}
}
} else {
}
}
```

**Advanced Error Handling**

If you need to handle specific error types differently, you can check the error code:

```php
$ability = wp_get_ability( 'my-plugin/update-option' );
if ( $ability ) {
$result = $ability->execute( $input );

// Handle specific error types if needed
if ( is_wp_error( $result ) && 'ability_invalid_permissions' === $result->get_error_code() ) {
// Handle permission errors specifically
echo 'You do not have permission to execute this ability.';
} elseif ( is_wp_error( $result ) ) {
// Handle other errors (validation, execution, etc.)
echo 'Error: ' . $result->get_error_message();
} else {
// Success - use the result
if ( $result['success'] ) {
echo 'Option updated successfully!';
}
}
}
```
Expand Down
24 changes: 21 additions & 3 deletions includes/abilities-api/class-wp-ability.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
*
Expand Down Expand Up @@ -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() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public function run_ability_permissions_check( $request ) {
}

$input = $this->get_input_from_request( $request );
if ( ! $ability->has_permission( $input ) ) {
if ( true !== $ability->check_permission( $input ) ) {
return new \WP_Error(
'rest_ability_cannot_execute',
__( 'Sorry, you are not allowed to execute this ability.' ),
Expand Down
31 changes: 26 additions & 5 deletions tests/unit/abilities-api/wpRegisterAbility.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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.
*/
Expand All @@ -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,
Expand All @@ -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,
Expand Down