-
Notifications
You must be signed in to change notification settings - Fork 26
Fix has_permission() return type inconsistency (Issue #67) #76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c60032b
0dba16e
209b541
5aeab28
eb86cc7
a44d683
d032fae
d55a0bb
e8d93f3
027c447
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 ) | ||
``` | ||
Comment on lines
+130
to
+134
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this intentional or did it leak? |
||
|
||
```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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know the doc in general uses a lot of unnecessary nesting, but I think this also make's it clearer than sandwiching the happy-path between two error states. // Use a strict check to catch both false and WP_Error
$permission = $ability->check_permission( $input );
if ( true === $permission ) {
// Permission granted - safe to execute.
$result = $ability->execute( $input );
if ( is_wp_error( $result ) ) {
// Handle execution error
echo 'Execution error: ' . $result->get_error_message();
} else {
// Use $result
if ( $result['success'] ) {
echo 'Option updated successfully!';
echo 'Previous value: ' . $result['previous_value'];
}
}
} else {
// Don't leak permission errors to unauthenticated users.
if ( is_wp_error( $permission ) ) {
error_log( 'Permission check failed: ' . $permission->get_error_message() );
}
echo 'You do not have permission to execute this ability.';
}
} Though imo we shouldn't be actively promoting $ability = wp_get_ability( 'my/ability' );
$result = $ability->execute( $input ) ;
// If we want to only handle perm errors and not also invalid inputs etc.
if ( is_wp_error() && 'ability_invalid_permissions' === $result->get_error_code() ) {
// handle the error
} |
||
$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.'; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -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 ) ) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we intentionally only handling false and saving the WP_Errors for
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's fix it. I don't think it was intentional. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my testing, the proposed code changes fail the result of 4 tests in the run controller. We would have to better handle the reason the request errored so it doesn't default to 403. It probably means, we would have to move some logic to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative would be to remove Technically speaking, we are good. However, we can improve the implementation/documentation to avoid future misunderstandings. |
||||||
return new \WP_Error( | ||||||
'rest_ability_cannot_execute', | ||||||
__( 'Sorry, you are not allowed to execute this ability.' ), | ||||||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this (and the previous example) is incorrect. By calling
$ability->execute()
,$ability->get_permission()
gets called, there's rarely a reason to explicitly check permissions as a separate step.