Skip to content
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

🚧 Experimental: Global styles revisions #49912

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
705cda0
Initial commit
ramonjd Dec 20, 2022
376d279
Updating test
ramonjd Dec 20, 2022
9978710
Sending and checking for settings as well since some style variations…
ramonjd Dec 21, 2022
926a2b0
Added a new endpoint to the global styles rest API (/revisions)
ramonjd Dec 22, 2022
11600cf
revisions is no longer a property of the response object
ramonjd Dec 22, 2022
631432e
Update description for rest param
ramonjd Dec 23, 2022
1a13b77
There's no reason to use the stored userConfig at all if we're reinst…
ramonjd Dec 23, 2022
bc2a83d
added a test for the revisions endpoint
ramonjd Dec 23, 2022
146464c
Added text domain
ramonjd Dec 23, 2022
087e786
Bumping minimum revision count until display to two:
ramonjd Dec 23, 2022
958e746
Added a very unpretty E2E test for global styles revisions. We can't …
ramonjd Dec 29, 2022
3c88909
Formatting the comments in the E2E test.
ramonjd Dec 29, 2022
5df24c5
Fixing up things after a rebase, mainly usage of __experimentalGetCur…
ramonjd Apr 5, 2023
225606b
Moving changes to global styles controller to 6.2 compat
ramonjd Apr 5, 2023
5c77f1e
JS LINT YO!
ramonjd Apr 5, 2023
70150bb
Relocate js utils tests for isGlobalStyleConfigEqual
ramonjd Apr 5, 2023
10b2de0
Move rest route registration to compat 6.3
ramonjd Apr 5, 2023
a066ab4
update e2e tests so that they pass :D I was importing a non-existant …
ramonjd Apr 11, 2023
be5005f
Testing with undo/reset buttons
ramonjd Apr 11, 2023
eed6463
Moving the revisions link so that it's under the drop down
ramonjd Apr 12, 2023
8671471
Yoda?
ramonjd Apr 12, 2023
7ee47a1
Adding author display name and avatar to rest response
ramonjd Apr 13, 2023
8640877
Update PHP tests title > date
ramonjd Apr 14, 2023
fc2b825
This is trash
ramonjd Apr 18, 2023
d16bd4d
This is also trash.
ramonjd Apr 19, 2023
7287070
This is also trash.
ramonjd Apr 20, 2023
23c4a57
This is also trash.
ramonjd Apr 20, 2023
f3cfeb0
This is also trash.
ramonjd Apr 20, 2023
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
9 changes: 0 additions & 9 deletions lib/compat/wordpress-6.2/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,6 @@ function gutenberg_pattern_directory_collection_params_6_2( $query_params ) {
}
add_filter( 'rest_pattern_directory_collection_params', 'gutenberg_pattern_directory_collection_params_6_2' );

/**
* Registers the Global Styles REST API routes.
*/
function gutenberg_register_global_styles_endpoints() {
$editor_settings = new Gutenberg_REST_Global_Styles_Controller_6_2();
$editor_settings->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' );

/**
* Updates REST API response for the sidebars and marks them as 'inactive'.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<?php
/**
* REST API: Gutenberg_REST_Global_Styles_Controller class
*
* @package Gutenberg
* @subpackage REST_API
*/

/**
* Base Global Styles REST API Controller.
*/
class Gutenberg_REST_Global_Styles_Controller_6_3 extends Gutenberg_REST_Global_Styles_Controller_6_2 {
/**
* Registers the controllers routes.
*
* @since 6.3 Registers `/revisions` endpoint.
*
* @return void
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/(?P<id>[\/\w-]+)/revisions',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item_revisions' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'id' => array(
'description' => __( 'The id of the global styles post.', 'gutenberg' ),
'type' => 'string',
'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ),
),
),
),
)
);
parent::register_routes();
}

/**
* Returns revisions of the given global styles config custom post type.
*
* @since 6.3
*
* @param WP_REST_Request $request The request instance.
*
* @return WP_REST_Response|WP_Error
*/
public function get_item_revisions( $request ) {
$post = $this->get_post( $request['id'] );
if ( is_wp_error( $post ) ) {
return $post;
}
$revisions = array();
$raw_config = json_decode( $post->post_content, true );
$is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON'];

if ( $is_global_styles_user_theme_json ) {
$user_theme_revisions = wp_get_post_revisions(
$post->ID,
array(
'posts_per_page' => 100,
)
);

if ( ! empty( $user_theme_revisions ) ) {
// Mostly taken from wp_prepare_revisions_for_js().
foreach ( $user_theme_revisions as $id => $revision ) {
$raw_revision_config = json_decode( $revision->post_content, true );
$config = ( new WP_Theme_JSON_Gutenberg( $raw_revision_config, 'custom' ) )->get_raw_data();
$now_gmt = time();
$modified = strtotime( $revision->post_modified );
$modified_gmt = strtotime( $revision->post_modified_gmt . ' +0000' );
/* translators: %s: Human-readable time difference. */
$time_ago = sprintf( __( '%s ago', 'gutenberg' ), human_time_diff( $modified_gmt, $now_gmt ) );
$date_short = date_i18n( _x( 'j M @ H:i', 'revision date short format', 'gutenberg' ), $modified );
$revisions[] = array(
'styles' => ! empty( $config['styles'] ) ? $config['styles'] : new stdClass(),
'settings' => ! empty( $config['settings'] ) ? $config['settings'] : new stdClass(),
'date' => array(
'raw' => $revision->post_modified,
/* translators: 1: Human-readable time difference, 2: short date combined to show rendered revision date. */
'rendered' => sprintf( __( '%1$s (%2$s)', 'gutenberg' ), $time_ago, $date_short ),
),
'id' => $id,
'is_latest' => array_key_first( $user_theme_revisions ) === $id,
'author' => array(
'display_name' => get_the_author_meta( 'display_name', $post->post_author ),
'avatar_url' => get_avatar_url(
$post->post_author,
array(
'size' => 24,
)
),
),
);
}
}
}
return rest_ensure_response( $revisions );
}

/**
* Prepare a global styles config output for response.
*
* @since 5.9.0
* @since 6.2 Handling of style.css was added to WP_Theme_JSON.
* @since 6.3 Adds version-history to the response object.
*
* @param WP_Post $post Global Styles post object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response Response object.
*/
public function prepare_item_for_response( $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$raw_config = json_decode( $post->post_content, true );
$is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON'];
$config = array();
if ( $is_global_styles_user_theme_json ) {
$config = ( new WP_Theme_JSON_Gutenberg( $raw_config, 'custom' ) )->get_raw_data();
}

// Base fields for every post.
$data = array();
$fields = $this->get_fields_for_response( $request );

if ( rest_is_field_included( 'id', $fields ) ) {
$data['id'] = $post->ID;
}

if ( rest_is_field_included( 'title', $fields ) ) {
$data['title'] = array();
}
if ( rest_is_field_included( 'title.raw', $fields ) ) {
$data['title']['raw'] = $post->post_title;
}
if ( rest_is_field_included( 'title.rendered', $fields ) ) {
add_filter( 'protected_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' ) );
}

if ( rest_is_field_included( 'settings', $fields ) ) {
$data['settings'] = ! empty( $config['settings'] ) && $is_global_styles_user_theme_json ? $config['settings'] : new stdClass();
}

if ( rest_is_field_included( 'styles', $fields ) ) {
$data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass();
}

$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );

// Wrap the data in a response object.
$response = rest_ensure_response( $data );

if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
$links = $this->prepare_links( $post->ID );
if ( $is_global_styles_user_theme_json ) {
$revisions = wp_get_latest_revision_id_and_total_count( $post->ID );
$revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0;
$revisions_base = sprintf( '/%s/%s/%d/revisions', $this->namespace, $this->rest_base, $post->ID );
$links['version-history'] = array(
'href' => rest_url( $revisions_base ),
'count' => $revisions_count,
);
}
$response->add_links( $links );
if ( ! empty( $links['self']['href'] ) ) {
$actions = $this->get_available_actions();
$self = $links['self']['href'];
foreach ( $actions as $rel ) {
$response->add_link( $rel, $self );
}
}
}

return $response;
}
}
9 changes: 9 additions & 0 deletions lib/compat/wordpress-6.3/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,12 @@ function gutenberg_update_templates_template_parts_rest_controller( $args, $post
return $args;
}
add_filter( 'register_post_type_args', 'gutenberg_update_templates_template_parts_rest_controller', 10, 2 );

/**
* Registers the Global Styles REST API routes.
*/
function gutenberg_register_global_styles_endpoints() {
$editor_settings = new Gutenberg_REST_Global_Styles_Controller_6_3();
$editor_settings->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' );
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-pattern-directory-controller-6-3.php';
require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-templates-controller-6-3.php';
require_once __DIR__ . '/compat/wordpress-6.3/rest-api.php';
require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-global-styles-controller-6-3.php';

// Experimental.
if ( ! class_exists( 'WP_Rest_Customizer_Nonces' ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const DEFAULT_GLOBAL_STYLES_CONTEXT = {
base: {},
merged: {},
setUserConfig: () => {},
userConfigRevisionsCount: 0,
};

export const GlobalStylesContext = createContext(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1106,8 +1106,11 @@ const processCSSNesting = ( css, blockSelector ) => {
return processedCSS;
};

export function useGlobalStylesOutput() {
export function useGlobalStylesOutput( customMergedConfig = null ) {
let { merged: mergedConfig } = useContext( GlobalStylesContext );
if ( !! customMergedConfig ) {
mergedConfig = customMergedConfig;
}

const [ blockGap ] = useGlobalSetting( 'spacing.blockGap' );
const hasBlockGapSupport = blockGap !== null;
Expand Down
34 changes: 28 additions & 6 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,21 +131,21 @@ export function receiveCurrentTheme( currentTheme ) {
}

/**
* Returns an action object used in signalling that the current global styles id has been received.
* Returns an action object used in signalling that the current global styles has been received.
* Ignored from documentation as it's internal to the data store.
*
* @ignore
*
* @param {string} currentGlobalStylesId The current global styles id.
* @param {Object} currentGlobalStyles The current global styles CPT.
*
* @return {Object} Action object.
*/
export function __experimentalReceiveCurrentGlobalStylesId(
currentGlobalStylesId
export function __experimentalReceiveCurrentGlobalStyles(
currentGlobalStyles
) {
return {
type: 'RECEIVE_CURRENT_GLOBAL_STYLES_ID',
id: currentGlobalStylesId,
type: 'RECEIVE_CURRENT_GLOBAL_STYLES',
globalStyles: currentGlobalStyles,
};
}

Expand Down Expand Up @@ -193,6 +193,28 @@ export function __experimentalReceiveThemeGlobalStyleVariations(
};
}

/**
* Returns an action object used in signalling that the theme global styles CPT post revisions have been received.
* Ignored from documentation as it's internal to the data store.
*
* @ignore
*
* @param {number} currentId The post id.
* @param {Array} revisions The global styles revisions.
*
* @return {Object} Action object.
*/
export function __experimentalReceiveThemeGlobalStyleRevisions(
currentId,
revisions
) {
return {
type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS',
currentId,
revisions,
};
}

/**
* Returns an action object used in signalling that the index has been received.
*
Expand Down
29 changes: 25 additions & 4 deletions packages/core-data/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,10 @@ export function currentTheme( state = undefined, action ) {
*
* @return {string|undefined} Updated state.
*/
export function currentGlobalStylesId( state = undefined, action ) {
export function currentGlobalStyles( state = undefined, action ) {
switch ( action.type ) {
case 'RECEIVE_CURRENT_GLOBAL_STYLES_ID':
return action.id;
case 'RECEIVE_CURRENT_GLOBAL_STYLES':
return action.globalStyles;
}

return state;
Expand Down Expand Up @@ -183,6 +183,26 @@ export function themeGlobalStyleVariations( state = {}, action ) {
return state;
}

/**
* Reducer managing the theme global styles revisions.
*
* @param {Record<string, object>} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Record<string, object>} Updated state.
*/
export function themeGlobalStyleRevisions( state = {}, action ) {
switch ( action.type ) {
case 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS':
return {
...state,
[ action.currentId ]: action.revisions,
};
}

return state;
}

/**
* Higher Order Reducer for a given entity config. It supports:
*
Expand Down Expand Up @@ -646,9 +666,10 @@ export default combineReducers( {
terms,
users,
currentTheme,
currentGlobalStylesId,
currentGlobalStyles,
currentUser,
themeGlobalStyleVariations,
themeGlobalStyleRevisions,
themeBaseGlobalStyles,
taxonomies,
entities,
Expand Down
Loading