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

Update: register block style variations defined by the theme using the init action #6756

122 changes: 99 additions & 23 deletions src/wp-includes/block-supports/block-style-variations.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,6 @@ function wp_render_block_style_variation_class_name( $block_content, $block ) {

/**
* Collects block style variation data for merging with theme.json data.
* As each block style variation is processed it is registered if it hasn't
* been already. This registration is required for later sanitization of
* theme.json data.
*
* @since 6.6.0
* @access private
Expand All @@ -224,14 +221,13 @@ function wp_render_block_style_variation_class_name( $block_content, $block ) {
*
* @return array Block variations data to be merged under `styles.blocks`.
*/
function wp_resolve_and_register_block_style_variations( $variations ) {
function wp_resolve_block_style_variations( $variations ) {
oandregal marked this conversation as resolved.
Show resolved Hide resolved
$variations_data = array();

if ( empty( $variations ) ) {
return $variations_data;
}

$registry = WP_Block_Styles_Registry::get_instance();
$have_named_variations = ! wp_is_numeric_array( $variations );

foreach ( $variations as $key => $variation ) {
Expand All @@ -253,23 +249,9 @@ function wp_resolve_and_register_block_style_variations( $variations ) {
* Block style variations read in via standalone theme.json partials
* need to have their name set to the kebab case version of their title.
*/
$variation_name = $have_named_variations ? $key : _wp_to_kebab_case( $variation['title'] );
$variation_label = $variation['title'] ?? $variation_name;
$variation_name = $have_named_variations ? $key : _wp_to_kebab_case( $variation['title'] );

foreach ( $supported_blocks as $block_type ) {
$registered_styles = $registry->get_registered_styles_for_block( $block_type );

// Register block style variation if it hasn't already been registered.
if ( ! array_key_exists( $variation_name, $registered_styles ) ) {
register_block_style(
$block_type,
array(
'name' => $variation_name,
'label' => $variation_label,
)
);
}

// Add block style variation data under current block type.
$path = array( $block_type, 'variations', $variation_name );
_wp_array_set( $variations_data, $path, $variation_data );
Expand Down Expand Up @@ -327,7 +309,7 @@ function wp_merge_block_style_variations_data( $variations_data, $theme_json, $o
function wp_resolve_block_style_variations_from_theme_style_variation( $theme_json ) {
$theme_json_data = $theme_json->get_data();
$shared_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
$variations_data = wp_resolve_and_register_block_style_variations( $shared_variations );
$variations_data = wp_resolve_block_style_variations( $shared_variations );

return wp_merge_block_style_variations_data( $variations_data, $theme_json, 'user' );
}
Expand All @@ -345,7 +327,7 @@ function wp_resolve_block_style_variations_from_theme_style_variation( $theme_js
*/
function wp_resolve_block_style_variations_from_theme_json_partials( $theme_json ) {
$block_style_variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' );
$variations_data = wp_resolve_and_register_block_style_variations( $block_style_variations );
$variations_data = wp_resolve_block_style_variations( $block_style_variations );

return wp_merge_block_style_variations_data( $variations_data, $theme_json );
}
Expand All @@ -364,7 +346,7 @@ function wp_resolve_block_style_variations_from_theme_json_partials( $theme_json
function wp_resolve_block_style_variations_from_primary_theme_json( $theme_json ) {
$theme_json_data = $theme_json->get_data();
$block_style_variations = $theme_json_data['styles']['blocks']['variations'] ?? array();
$variations_data = wp_resolve_and_register_block_style_variations( $block_style_variations );
$variations_data = wp_resolve_block_style_variations( $block_style_variations );

return wp_merge_block_style_variations_data( $variations_data, $theme_json );
}
Expand Down Expand Up @@ -422,3 +404,97 @@ function wp_enqueue_block_style_variation_styles() {
add_filter( 'wp_theme_json_data_theme', 'wp_resolve_block_style_variations_from_styles_registry', 10, 1 );

add_filter( 'wp_theme_json_data_user', 'wp_resolve_block_style_variations_from_theme_style_variation', 10, 1 );

/**
* Registers any block style variations contained within the provided
* theme.json data.
*
* @since 6.6.0
* @access private
oandregal marked this conversation as resolved.
Show resolved Hide resolved
*
* @param array $variations Shared block style variations.
*/
function wp_register_block_style_variations_from_theme_json_data( $variations ) {
if ( empty( $variations ) ) {
return $variations;
}

$registry = WP_Block_Styles_Registry::get_instance();
$have_named_variations = ! wp_is_numeric_array( $variations );

foreach ( $variations as $key => $variation ) {
$supported_blocks = $variation['blockTypes'] ?? array();

/*
* Standalone theme.json partial files for block style variations
* will have their styles under a top-level property by the same name.
* Variations defined within an existing theme.json or theme style
* variation will themselves already be the required styles data.
*/
$variation_data = $variation['styles'] ?? $variation;

if ( empty( $variation_data ) ) {
continue;
}

/*
* Block style variations read in via standalone theme.json partials
* need to have their name set to the kebab case version of their title.
*/
$variation_name = $have_named_variations ? $key : _wp_to_kebab_case( $variation['title'] );
$variation_label = $variation['title'] ?? $variation_name;

foreach ( $supported_blocks as $block_type ) {
$registered_styles = $registry->get_registered_styles_for_block( $block_type );

// Register block style variation if it hasn't already been registered.
if ( ! array_key_exists( $variation_name, $registered_styles ) ) {
register_block_style(
$block_type,
array(
'name' => $variation_name,
'label' => $variation_label,
)
);
}
}
}
}

/**
* Register shared block style variations defined by the theme.
*
* These can come in three forms:
* - the theme's theme.json
* - the theme's partials (standalone files in `/styles` that only define block style variations)
* - the user's theme.json (for example, theme style variations the user selected)
*
* @since 6.6.0
* @access private
oandregal marked this conversation as resolved.
Show resolved Hide resolved
*/
function wp_register_block_style_variations_from_theme() {
// Partials from `/styles`.
$variations_partials = WP_Theme_JSON_Resolver::get_style_variations( 'block' );
wp_register_block_style_variations_from_theme_json_data( $variations_partials );

/*
* Pull the data from the specific origin instead of the merged data.
* This is because, for 6.6, we only support registering block style variations
* for the 'theme' and 'custom' origins but not for 'default' (core theme.json)
* or 'custom' (theme.json in a block).
*
* When/If we add support for every origin, we should switch to using the public API
* instead, e.g.: wp_get_global_styles( array( 'blocks', 'variations' ) ).
*/

// theme.json of the theme.
$theme_json_theme = WP_Theme_JSON_Resolver::get_theme_data();
$variations_theme = $theme_json_theme->get_data()['styles']['blocks']['variations'] ?? array();
wp_register_block_style_variations_from_theme_json_data( $variations_theme );

// User data linked for this theme.
$theme_json_user = WP_Theme_JSON_Resolver::get_user_data();
$variations_user = $theme_json_user->get_data()['styles']['blocks']['variations'] ?? array();
wp_register_block_style_variations_from_theme_json_data( $variations_user );
}
add_action( 'init', 'wp_register_block_style_variations_from_theme' );
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ public function update_item_permissions_check( $request ) {
*
* @since 5.9.0
* @since 6.2.0 Added validation of styles.css property.
* @since 6.6.0 Added registration of newly created style variations provided by the user.
*
* @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.
Expand Down Expand Up @@ -263,6 +264,25 @@ protected function prepare_item_for_database( $request ) {
} elseif ( isset( $existing_config['styles'] ) ) {
$config['styles'] = $existing_config['styles'];
}

/*
* If the incoming request is going to create a new variation
* that is not yet registered, we register it here.
* This is because the variations are registered on init,
* but we want this endpoint to return the new variation immediately:
* if we don't register it, it'll be stripped out of the response
* just in this request (subsequent ones will be ok).
* Take the variations defined in styles.blocks.variations from the incoming request
* that are not part of the $exsting_config.
*/
if ( isset( $request['styles']['blocks']['variations'] ) ) {
oandregal marked this conversation as resolved.
Show resolved Hide resolved
$existing_variations = isset( $existing_config['styles']['blocks']['variations'] ) ? $existing_config['styles']['blocks']['variations'] : array();
$new_variations = array_diff_key( $request['styles']['blocks']['variations'], $existing_variations );
if ( ! empty( $new_variations ) ) {
wp_register_block_style_variations_from_theme_json_data( $new_variations );
}
}

if ( isset( $request['settings'] ) ) {
$config['settings'] = $request['settings'];
} elseif ( isset( $existing_config['settings'] ) ) {
Expand Down
7 changes: 7 additions & 0 deletions tests/phpunit/tests/block-supports/block-style-variations.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ public function filter_set_theme_root() {
public function test_add_registered_block_styles_to_theme_data() {
switch_theme( 'block-theme' );

/*
* Trigger block style registration that occurs on `init` action.
* do_action( 'init' ) could be used here however this direct call
* means only the updates being tested are performed.
*/
wp_register_block_style_variations_from_theme();

$variation_styles_data = array(
'color' => array(
'background' => 'darkslateblue',
Expand Down
49 changes: 49 additions & 0 deletions tests/phpunit/tests/rest-api/rest-global-styles-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,55 @@ public function test_update_item_invalid_styles_css() {
$this->assertErrorResponse( 'rest_custom_css_illegal_markup', $response, 400 );
}

/**
* Tests the submission of a custom block style variation that was defined
* within a theme style variation and wouldn't be registered at the time
* of saving via the API.
*
* @covers WP_REST_Global_Styles_Controller_Gutenberg::update_item
* @ticket 61312
*/
public function test_update_item_with_custom_block_style_variations() {
wp_set_current_user( self::$admin_id );
if ( is_multisite() ) {
grant_super_admin( self::$admin_id );
}

$group_variations = array(
'fromThemeStyleVariation' => array(
'color' => array(
'background' => '#ffffff',
'text' => '#000000',
),
),
);

$request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
$request->set_body_params(
array(
'styles' => array(
'blocks' => array(
'variations' => array(
'fromThemeStyleVariation' => array(
'blockTypes' => array( 'core/group', 'core/columns' ),
'color' => array(
'background' => '#000000',
'text' => '#ffffff',
),
),
),
'core/group' => array(
'variations' => $group_variations,
),
),
),
)
);
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertSame( $group_variations, $data['styles']['blocks']['core/group']['variations'] );
}

/**
* @doesNotPerformAssertions
*/
Expand Down
Loading