REST API: Improve permission handling in global style endpoint.

The new wp_global_styles post type is registered to use edit_theme_options in the capability settings. The WP_REST_Global_Styles_Controller class's permission checks methods use the capability in a hard coded form rather than looking up the capability via the post type object. Changing the permission callbacks to lookup capabilities via the post type object, allows theme and plugin developers to modify the capability used for editing global styles via a filter and these values to be respected via the Global Styles REST API.

Props Spacedmonkey, peterwilsoncc, hellofromTonya , antonvlasenko, TimothyBlynJacobs, costdev, zieladam.
Fixes #54516.


Built from https://develop.svn.wordpress.org/trunk@52342


git-svn-id: http://core.svn.wordpress.org/trunk@51934 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
spacedmonkey 2021-12-07 20:58:00 +00:00
parent 9aba2584bb
commit ec370a0af4
2 changed files with 113 additions and 26 deletions

View File

@ -11,6 +11,15 @@
* Base Global Styles REST API Controller.
*/
class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
/**
* Post type.
*
* @since 5.9.0
* @var string
*/
protected $post_type;
/**
* Constructor.
* @since 5.9.0
@ -18,6 +27,7 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
public function __construct() {
$this->namespace = 'wp/v2';
$this->rest_base = 'global-styles';
$this->post_type = 'wp_global_styles';
}
/**
@ -75,22 +85,32 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
}
/**
* Checks if the user has permissions to make the request.
* Checks if a given request has access to read a single global style.
*
* @since 5.9.0
*
* @param WP_REST_Request $request Full details about the request.
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
protected function permissions_check() {
// Verify if the current user has edit_theme_options capability.
// This capability is required to edit/view/delete templates.
if ( ! current_user_can( 'edit_theme_options' ) ) {
public function get_item_permissions_check( $request ) {
$post = $this->get_post( $request['id'] );
if ( is_wp_error( $post ) ) {
return $post;
}
if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
return new WP_Error(
'rest_cannot_manage_global_styles',
__( 'Sorry, you are not allowed to access the global styles on this site.' ),
array(
'status' => rest_authorization_required_code(),
)
'rest_forbidden_context',
__( 'Sorry, you are not allowed to edit this global style.' ),
array( 'status' => rest_authorization_required_code() )
);
}
if ( ! $this->check_read_permission( $post ) ) {
return new WP_Error(
'rest_cannot_view',
__( 'Sorry, you are not allowed to view this global style.' ),
array( 'status' => rest_authorization_required_code() )
);
}
@ -98,13 +118,15 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
}
/**
* Checks if a given request has access to read a single global styles config.
* Checks if a global style can be read.
*
* @param WP_REST_Request $request Full details about the request.
* @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
* @since 5.9.0
*
* @param WP_Post $post Post object.
* @return bool Whether the post can be read.
*/
public function get_item_permissions_check( $request ) {
return $this->permissions_check( $request );
protected function check_read_permission( $post ) {
return current_user_can( 'read_post', $post->ID );
}
/**
@ -117,9 +139,9 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
* @return WP_REST_Response|WP_Error
*/
public function get_item( $request ) {
$post = get_post( $request['id'] );
if ( ! $post || 'wp_global_styles' !== $post->post_type ) {
return new WP_Error( 'rest_global_styles_not_found', __( 'No global styles config exist with that id.' ), array( 'status' => 404 ) );
$post = $this->get_post( $request['id'] );
if ( is_wp_error( $post ) ) {
return $post;
}
return $this->prepare_item_for_response( $post, $request );
@ -134,7 +156,32 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
* @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise.
*/
public function update_item_permissions_check( $request ) {
return $this->permissions_check( $request );
$post = $this->get_post( $request['id'] );
if ( is_wp_error( $post ) ) {
return $post;
}
if ( $post && ! $this->check_update_permission( $post ) ) {
return new WP_Error(
'rest_cannot_edit',
__( 'Sorry, you are not allowed to edit this global style.' ),
array( 'status' => rest_authorization_required_code() )
);
}
return true;
}
/**
* Checks if a global style can be edited.
*
* @since 5.9.0
*
* @param WP_Post $post Post object.
* @return bool Whether the post can be edited.
*/
protected function check_update_permission( $post ) {
return current_user_can( 'edit_post', $post->ID );
}
/**
@ -146,9 +193,9 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_item( $request ) {
$post_before = get_post( $request['id'] );
if ( ! $post_before || 'wp_global_styles' !== $post_before->post_type ) {
return new WP_Error( 'rest_global_styles_not_found', __( 'No global styles config exist with that id.' ), array( 'status' => 404 ) );
$post_before = $this->get_post( $request['id'] );
if ( is_wp_error( $post_before ) ) {
return $post_before;
}
$changes = $this->prepare_item_for_database( $request );
@ -289,6 +336,34 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
return $response;
}
/**
* Get the post, if the ID is valid.
*
* @since 5.9.0
*
* @param int $id Supplied ID.
* @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
*/
protected function get_post( $id ) {
$error = new WP_Error(
'rest_global_styles_not_found',
__( 'No global styles config exist with that id.' ),
array( 'status' => 404 )
);
$id = (int) $id;
if ( $id <= 0 ) {
return $error;
}
$post = get_post( $id );
if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
return $error;
}
return $post;
}
/**
* Prepares links for the request.
@ -323,7 +398,7 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
protected function get_available_actions() {
$rels = array();
$post_type = get_post_type_object( 'wp_global_styles' );
$post_type = get_post_type_object( $this->post_type );
if ( current_user_can( $post_type->cap->publish_posts ) ) {
$rels[] = 'https://api.w.org/action-publish';
}
@ -371,7 +446,7 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'wp_global_styles',
'title' => $this->post_type,
'type' => 'object',
'properties' => array(
'id' => array(
@ -426,7 +501,19 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
* @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
*/
public function get_theme_item_permissions_check( $request ) {
return $this->permissions_check( $request );
// Verify if the current user has edit_theme_options capability.
// This capability is required to edit/view/delete templates.
if ( ! current_user_can( 'edit_theme_options' ) ) {
return new WP_Error(
'rest_cannot_manage_global_styles',
__( 'Sorry, you are not allowed to access the global styles on this site.' ),
array(
'status' => rest_authorization_required_code(),
)
);
}
return true;
}
/**

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '5.9-beta1-52341';
$wp_version = '5.9-beta1-52342';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.