-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Global Styles: Update REST controller override method and backport changes from Core #65259
Changes from all commits
457daea
04e462b
992719a
7d7cd38
d812e00
b75834d
01bf6be
c917442
f2b8dcd
43d70f9
2e75d56
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 |
---|---|---|
|
@@ -13,25 +13,30 @@ | |
/** | ||
* Base Global Styles REST API Controller. | ||
*/ | ||
class WP_REST_Global_Styles_Controller_Gutenberg extends WP_REST_Controller { | ||
class WP_REST_Global_Styles_Controller_Gutenberg extends WP_REST_Posts_Controller { | ||
|
||
/** | ||
* Post type. | ||
* Whether the controller supports batching. | ||
* | ||
* @since 5.9.0 | ||
* @var string | ||
* @since 6.6.0 | ||
* @var array | ||
*/ | ||
protected $post_type; | ||
protected $allow_batch = array( 'v1' => false ); | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @since 5.9.0 | ||
*/ | ||
public function __construct() { | ||
$this->namespace = 'wp/v2'; | ||
$this->rest_base = 'global-styles'; | ||
$this->post_type = 'wp_global_styles'; | ||
/** | ||
* Constructor. | ||
* | ||
* @since 6.6.0 | ||
* | ||
* @param string $post_type Post type. | ||
*/ | ||
public function __construct( $post_type = 'wp_global_styles' ) { | ||
parent::__construct( $post_type ); | ||
} | ||
|
||
/** | ||
|
@@ -54,8 +59,14 @@ public function register_routes() { | |
'type' => 'string', | ||
), | ||
), | ||
'allow_batch' => $this->allow_batch, | ||
), | ||
) | ||
), | ||
/* | ||
* $override is set to true to avoid conflicts with the core endpoint. | ||
* Do not sync to WordPress core. | ||
*/ | ||
true | ||
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. This is required to overwrite Core routes when this endpoint is registered. |
||
); | ||
|
||
// List themes global styles. | ||
|
@@ -65,8 +76,10 @@ public function register_routes() { | |
sprintf( | ||
'/%s/themes/(?P<stylesheet>%s)', | ||
$this->rest_base, | ||
// Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`. | ||
// Excludes invalid directory name characters: `/:<>*?"|`. | ||
/* | ||
* Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`. | ||
* Excludes invalid directory name characters: `/:<>*?"|`. | ||
*/ | ||
'[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?' | ||
), | ||
array( | ||
|
@@ -81,8 +94,14 @@ public function register_routes() { | |
'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ), | ||
), | ||
), | ||
'allow_batch' => $this->allow_batch, | ||
), | ||
) | ||
), | ||
/* | ||
* $override is set to true to avoid conflicts with the core endpoint. | ||
* Do not sync to WordPress core. | ||
*/ | ||
true | ||
); | ||
|
||
// Lists/updates a single global style variation based on the given id. | ||
|
@@ -108,8 +127,14 @@ public function register_routes() { | |
'permission_callback' => array( $this, 'update_item_permissions_check' ), | ||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), | ||
), | ||
'schema' => array( $this, 'get_public_item_schema' ), | ||
) | ||
'schema' => array( $this, 'get_public_item_schema' ), | ||
'allow_batch' => $this->allow_batch, | ||
), | ||
/* | ||
* $override is set to true to avoid conflicts with the core endpoint. | ||
* Do not sync to WordPress core. | ||
*/ | ||
true | ||
); | ||
} | ||
|
||
|
@@ -196,28 +221,10 @@ public function get_item_permissions_check( $request ) { | |
* @param WP_Post $post Post object. | ||
* @return bool Whether the post can be read. | ||
*/ | ||
protected function check_read_permission( $post ) { | ||
public function check_read_permission( $post ) { | ||
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. Done in Core in WordPress/wordpress-develop@6fc019a as part of inheriting |
||
return current_user_can( 'read_post', $post->ID ); | ||
} | ||
|
||
/** | ||
* Returns the given global styles config. | ||
* | ||
* @since 5.9.0 | ||
* | ||
* @param WP_REST_Request $request The request instance. | ||
* | ||
* @return WP_REST_Response|WP_Error | ||
*/ | ||
public function get_item( $request ) { | ||
$post = $this->get_post( $request['id'] ); | ||
if ( is_wp_error( $post ) ) { | ||
return $post; | ||
} | ||
|
||
return $this->prepare_item_for_response( $post, $request ); | ||
} | ||
|
||
/** | ||
* Checks if a given request has access to write a single global styles config. | ||
* | ||
|
@@ -243,61 +250,12 @@ public function update_item_permissions_check( $request ) { | |
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 ); | ||
} | ||
|
||
/** | ||
* Updates a single global style config. | ||
* | ||
* @since 5.9.0 | ||
* @since 6.2.0 Added validation of styles.css property. | ||
* | ||
* @param WP_REST_Request $request Full details about the request. | ||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. | ||
*/ | ||
public function update_item( $request ) { | ||
$post_before = $this->get_post( $request['id'] ); | ||
if ( is_wp_error( $post_before ) ) { | ||
return $post_before; | ||
} | ||
|
||
$changes = $this->prepare_item_for_database( $request ); | ||
if ( is_wp_error( $changes ) ) { | ||
return $changes; | ||
} | ||
|
||
$result = wp_update_post( wp_slash( (array) $changes ), true, false ); | ||
if ( is_wp_error( $result ) ) { | ||
return $result; | ||
} | ||
|
||
$post = get_post( $request['id'] ); | ||
$fields_update = $this->update_additional_fields_for_object( $post, $request ); | ||
if ( is_wp_error( $fields_update ) ) { | ||
return $fields_update; | ||
} | ||
|
||
wp_after_insert_post( $post, true, $post_before ); | ||
|
||
$response = $this->prepare_item_for_response( $post, $request ); | ||
|
||
return rest_ensure_response( $response ); | ||
} | ||
|
||
/** | ||
* Prepares a single global styles config for update. | ||
* | ||
* @since 5.9.0 | ||
* @since 6.2.0 Added validation of styles.css property. | ||
* @since 6.6.0 Added registration of block style variations from theme.json sources (theme.json, user theme.json, partials). | ||
* | ||
* @param WP_REST_Request $request Request object. | ||
* @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid. | ||
|
@@ -394,10 +352,12 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V | |
} | ||
if ( rest_is_field_included( 'title.rendered', $fields ) ) { | ||
add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); | ||
add_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); | ||
|
||
$data['title']['rendered'] = get_the_title( $post->ID ); | ||
|
||
remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); | ||
remove_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); | ||
Comment on lines
+355
to
+360
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. The cc @youknowriad to see whether this was intentional |
||
} | ||
|
||
if ( rest_is_field_included( 'settings', $fields ) ) { | ||
|
@@ -426,7 +386,7 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V | |
} | ||
$response->add_links( $links ); | ||
if ( ! empty( $links['self']['href'] ) ) { | ||
$actions = $this->get_available_actions(); | ||
$actions = $this->get_available_actions( $post, $request ); | ||
$self = $links['self']['href']; | ||
foreach ( $actions as $rel ) { | ||
$response->add_link( $rel, $self ); | ||
|
@@ -450,9 +410,12 @@ protected function prepare_links( $id ) { | |
$base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); | ||
|
||
$links = array( | ||
'self' => array( | ||
'self' => array( | ||
'href' => rest_url( trailingslashit( $base ) . $id ), | ||
), | ||
'about' => array( | ||
'href' => rest_url( 'wp/v2/types/' . $this->post_type ), | ||
), | ||
Comment on lines
+416
to
+418
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. Done in Core in WordPress/wordpress-develop@6fc019a as part of inheriting |
||
); | ||
|
||
if ( post_type_supports( $this->post_type, 'revisions' ) ) { | ||
|
@@ -473,13 +436,16 @@ protected function prepare_links( $id ) { | |
* | ||
* @since 5.9.0 | ||
* @since 6.2.0 Added 'edit-css' action. | ||
* @since 6.6.0 Added $post and $request parameters. | ||
* | ||
* @param WP_Post $post Post object. | ||
* @param WP_REST_Request $request Request object. | ||
* @return array List of link relations. | ||
*/ | ||
protected function get_available_actions() { | ||
protected function get_available_actions( $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable | ||
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. Done in Core in WordPress/wordpress-develop@6fc019a as part of inheriting |
||
$rels = array(); | ||
|
||
$post_type = get_post_type_object( $this->post_type ); | ||
$post_type = get_post_type_object( $post->post_type ); | ||
if ( current_user_can( $post_type->cap->publish_posts ) ) { | ||
$rels[] = 'https://api.w.org/action-publish'; | ||
} | ||
|
@@ -491,21 +457,6 @@ protected function get_available_actions() { | |
return $rels; | ||
} | ||
|
||
/** | ||
* Overwrites the default protected title format. | ||
* | ||
* By default, WordPress will show password protected posts with a title of | ||
* "Protected: %s", as the REST API communicates the protected status of a post | ||
* in a machine readable format, we remove the "Protected: " prefix. | ||
* | ||
* @since 5.9.0 | ||
* | ||
* @return string Protected title format. | ||
*/ | ||
public function protected_title_format() { | ||
return '%s'; | ||
} | ||
|
||
/** | ||
* Retrieves the query params for the global styles collection. | ||
* | ||
|
@@ -589,7 +540,7 @@ public function get_theme_item_permissions_check( $request ) { // phpcs:ignore V | |
|
||
/* | ||
* Verify if the current user has edit_theme_options capability. | ||
* This capability is required to edit/view/delete templates. | ||
* This capability is required to edit/view/delete global styles. | ||
*/ | ||
if ( ! current_user_can( 'edit_theme_options' ) ) { | ||
return new WP_Error( | ||
|
@@ -623,8 +574,8 @@ public function get_theme_item( $request ) { | |
} | ||
|
||
$theme = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( 'theme' ); | ||
$data = array(); | ||
$fields = $this->get_fields_for_response( $request ); | ||
$data = array(); | ||
|
||
if ( rest_is_field_included( 'settings', $fields ) ) { | ||
$data['settings'] = $theme->get_settings(); | ||
|
@@ -669,7 +620,7 @@ public function get_theme_items_permissions_check( $request ) { // phpcs:ignore | |
|
||
/* | ||
* Verify if the current user has edit_theme_options capability. | ||
* This capability is required to edit/view/delete templates. | ||
* This capability is required to edit/view/delete global styles. | ||
*/ | ||
if ( ! current_user_can( 'edit_theme_options' ) ) { | ||
return new WP_Error( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,14 +11,24 @@ | |
} | ||
|
||
/** | ||
* Registers the Global Styles REST API routes. | ||
* Overrides the REST controller for the `wp_global_styles` post type. | ||
* | ||
* @param array $args Array of arguments for registering a post type. | ||
* See the register_post_type() function for accepted arguments. | ||
* @param string $post_type Post type key. | ||
* | ||
* @return array Array of arguments for registering a post type. | ||
*/ | ||
function gutenberg_register_global_styles_endpoints() { | ||
$global_styles_controller = new WP_REST_Global_Styles_Controller_Gutenberg(); | ||
$global_styles_controller->register_routes(); | ||
} | ||
add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' ); | ||
function gutenberg_override_global_styles_endpoint( array $args ): array { | ||
$args['rest_controller_class'] = 'WP_REST_Global_Styles_Controller_Gutenberg'; | ||
$args['revisions_rest_controller_class'] = 'Gutenberg_REST_Global_Styles_Revisions_Controller_6_6'; | ||
$args['late_route_registration'] = true; | ||
$args['show_in_rest'] = true; | ||
$args['rest_base'] = 'global-styles'; | ||
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. The CI tests are running 6.5.5. I think it's computed for CI here. They should probably be running 6.6, but even so, adding the args for backwards compat just in case. Compare 6.5 https://github.com/WordPress/wordpress-develop/blob/6.5/src/wp-includes/post.php#L473 With 6.6 https://github.com/WordPress/wordpress-develop/blob/6.6/src/wp-includes/post.php#L476 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'm assuming that these tests run on the previous major WP version due to our BC commitment. That said, I did expect we also ran the unit tests on the latest too. |
||
|
||
return $args; | ||
} | ||
add_filter( 'register_wp_global_styles_post_type_args', 'gutenberg_override_global_styles_endpoint', 10, 2 ); | ||
|
||
/** | ||
* Registers the Edit Site Export REST API routes. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,14 +79,18 @@ public static function wpTearDownAfterClass() { | |
* @covers WP_REST_Global_Styles_Controller_Gutenberg::register_routes | ||
*/ | ||
public function test_register_routes() { | ||
// Register routes so that they overwrite identical Core routes. | ||
$global_styles_controller = new WP_REST_Global_Styles_Controller_Gutenberg(); | ||
$global_styles_controller->register_routes(); | ||
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. This needs to occur to ensure we're only testing the Gutenberg-registered endpoints... |
||
|
||
$routes = rest_get_server()->get_routes(); | ||
$this->assertArrayHasKey( | ||
'/wp/v2/global-styles/(?P<id>[\/\w-]+)', | ||
$routes, | ||
'Single global style based on the given ID route does not exist' | ||
); | ||
$this->assertCount( | ||
4, // Double core because both sets get registered in the plugin. | ||
2, | ||
$routes['/wp/v2/global-styles/(?P<id>[\/\w-]+)'], | ||
'Single global style based on the given ID route does not have exactly two elements' | ||
); | ||
|
@@ -96,7 +100,7 @@ public function test_register_routes() { | |
'Theme global styles route does not exist' | ||
); | ||
$this->assertCount( | ||
2, // Double core because both sets get registered in the plugin. | ||
1, | ||
$routes['/wp/v2/global-styles/themes/(?P<stylesheet>[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)'], | ||
'Theme global styles route does not have exactly one element' | ||
); | ||
|
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.
Done in Core in WordPress/wordpress-develop@6fc019a as part of inheriting
WP_REST_Posts_Controller