-
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 revisions: add route for single styles revisions #55827
Changes from all commits
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 |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
/** | ||
* REST API: Gutenberg_REST_Global_Styles_Revisions_Controller class, inspired by WP_REST_Revisions_Controller. | ||
* | ||
* @package WordPress | ||
* @subpackage REST_API | ||
* @since 6.3.0 | ||
*/ | ||
|
||
/** | ||
* Core class used to access global styles revisions via the REST API. | ||
* | ||
* @since 6.3.0 | ||
* | ||
* @see WP_REST_Controller | ||
*/ | ||
class Gutenberg_REST_Global_Styles_Revisions_Controller_6_5 extends Gutenberg_REST_Global_Styles_Revisions_Controller_6_4 { | ||
/** | ||
* Registers the controller's routes. | ||
* | ||
* @since 6.3.0 | ||
* @since 6.5.0 Adds route to fetch individual global styles revisions. | ||
*/ | ||
public function register_routes() { | ||
register_rest_route( | ||
$this->namespace, | ||
'/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base . '/(?P<id>[\d]+)', | ||
array( | ||
'args' => array( | ||
'parent' => array( | ||
'description' => __( 'The ID for the parent of the global styles revision.' ), | ||
'type' => 'integer', | ||
), | ||
'id' => array( | ||
'description' => __( 'Unique identifier for the global styles revision.' ), | ||
'type' => 'integer', | ||
), | ||
), | ||
array( | ||
'methods' => WP_REST_Server::READABLE, | ||
'callback' => array( $this, 'get_item' ), | ||
'permission_callback' => array( $this, 'get_item_permissions_check' ), | ||
'args' => array( | ||
'context' => $this->get_context_param( array( 'default' => 'view' ) ), | ||
), | ||
), | ||
'schema' => array( $this, 'get_public_item_schema' ), | ||
) | ||
); | ||
parent::register_routes(); | ||
} | ||
|
||
/** | ||
* Retrieves one global styles revision from the collection. | ||
* | ||
* @since 6.5.0 | ||
* | ||
* @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 get_item( $request ) { | ||
$parent = $this->get_parent( $request['parent'] ); | ||
if ( is_wp_error( $parent ) ) { | ||
return $parent; | ||
} | ||
|
||
$revision = $this->get_revision( $request['id'] ); | ||
if ( is_wp_error( $revision ) ) { | ||
return $revision; | ||
} | ||
|
||
$response = $this->prepare_item_for_response( $revision, $request ); | ||
return rest_ensure_response( $response ); | ||
} | ||
|
||
/** | ||
* Get the global styles revision, if the ID is valid. | ||
* | ||
* @since 6.5.0 | ||
* | ||
* @param int $id Supplied ID. | ||
* @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise. | ||
*/ | ||
protected function get_revision( $id ) { | ||
$error = new WP_Error( | ||
'rest_post_invalid_id', | ||
__( 'Invalid revision ID.' ), | ||
array( 'status' => 404 ) | ||
); | ||
|
||
if ( (int) $id <= 0 ) { | ||
return $error; | ||
} | ||
|
||
$revision = get_post( (int) $id ); | ||
if ( empty( $revision ) || empty( $revision->ID ) || 'revision' !== $revision->post_type ) { | ||
return $error; | ||
} | ||
Comment on lines
+95
to
+98
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. Do we need to check that the 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 also taken from The parent post type check ( You bring up a great point though. Currently I can, for any post type, return the revision of different post just by knowing the post ID. So for the following:
As with the above comment, it could be a good question to raise in Core Slack or in a trac ticket. There might be a reason why all post type revisions work this way. 🤔 I'll make a note to ask. Thank you! 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. Question asked here: https://wordpress.slack.com/archives/C02RQC26G/p1699504213232439 |
||
|
||
return $revision; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
/** | ||
* PHP and WordPress configuration compatibility functions for the Gutenberg | ||
* editor plugin changes related to REST API. | ||
* | ||
* @package gutenberg | ||
*/ | ||
|
||
if ( ! defined( 'ABSPATH' ) ) { | ||
die( 'Silence is golden.' ); | ||
} | ||
|
||
/** | ||
* Registers the Global Styles Revisions REST API routes. | ||
*/ | ||
function gutenberg_register_global_styles_revisions_endpoints() { | ||
$global_styles_revisions_controller = new Gutenberg_REST_Global_Styles_Revisions_Controller_6_5(); | ||
$global_styles_revisions_controller->register_routes(); | ||
} | ||
|
||
add_action( 'rest_api_init', 'gutenberg_register_global_styles_revisions_endpoints' ); |
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.
In the
get_items
version of retrieving revisions, they're guarded behind a check against the$parent
ofif ( wp_revisions_enabled( $paren ) ) {
... should we add a similar check here, too?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've modelled this class as closely as possible to WP_REST_Revisions_Controller.
The reason I wouldn't want to make these changes here is because they should be probably be raised in trac and discussed in the wider context of revisions since they all work this way.
Even so I think it should be okay for global styles.
This is what the docs say about the
supports
flag for register_post_type, specifically:So if a post type cannot store revisions, there'll be none to fetch.
It's possible
wp_revisions_enabled
is used inget_items
to save an expensivenew WP_Query()
call.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.
@ramonjd I'm curious why you couldn't just use the core revisions controller, what feature was missing?
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.
@adamsilverstein Thanks for the question. It is a good one.
Global styles post revisions store stringified JSON in the post content field. When preparing the response, the JSON needs to be parsed and structured according to the theme.json model, that is, something like this:
That's the main difference - the responses are different.
Also deleting revisions wasn't a requirement.
I did consider extending
WP_REST_Revisions_Controller
way back when I introduced the global styles revisions endpoint.Global styles revisions were a bit new and had the following characteristics:
Back then, it was more code to override the parent class's functions, and I thought having it as a stand alone class left more elbow room for subsequent tweaks and changes. Especially since global styles revisions were new and evolving.
Also, since I tried to sync what I needed from
WP_REST_Revisions_Controller
, I thought that it wouldn't affect backwards compatibility if we one day decided to refactor this code and extendWP_REST_Revisions_Controller
.Today I think the functionality is more balanced. Overriding fields and response-related methods would still be needed, but are a lot of shared methods between the two classes and, arguably, a delete route would bring it in line with current revision expectations.
What do you think?
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.
Hey @ramonjd thanks for clarifying your thinking here. I agree it makes sense to build out a separate class for your exact needs, especially while building something new where you want to change things and avoid breaking the existing controller.
Given that you mainly want to alter the response behavior, I wonder if you could use the existing revisions controller and leverage the
rest_prepare_revision
filter provided to adjust the shape of the return as you desire - this should let you control the exact response you want for each revision.My main concern with adding another controller is the added maintenance burden. For example the issue you discovered with mismatched parent ids would need to get fixed in two places.
If you feel your controller is doing everything it needs to, I would encourage at least experimenting with using the filter approach and relying on the existing controller. This should reduce the amount of code you need.
cc: @TimothyBJacobs for a second opinion
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.
Thanks, I appreciate the insight. 🙇🏻
Good call. I'd like to try this. The maintenance burden is on my mind 😅
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.
+1 let me know if you find any shortcomings in the core endpoint or the filter/hooks it provides - if so maybe we can address those in core.
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 have a Core PR in progress here:
I ended up replacing the base class with
WP_REST_Revisions_Controller
so that theWP_REST_Global_Styles_Revisions_Controller
was still available (I wasn't sure about how radical I should be about maintaining backwards compatibility), but more importantly, so I could preserve the following features by overwriting class methods:Thanks for the nudge! It removes a lot of code.