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

Global Styles: Prevent duplicate CSS for block style variations #6827

1 change: 1 addition & 0 deletions src/wp-includes/block-supports/block-style-variations.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ function wp_render_block_style_variation_support_styles( $parsed_block ) {
array( 'styles' ),
array( 'custom' ),
array(
'block_style_variations' => true,
'skip_root_layout_styles' => true,
'scope' => ".$class_name",
)
Expand Down
32 changes: 24 additions & 8 deletions src/wp-includes/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ public function get_settings() {
* @since 5.8.0
* @since 5.9.0 Removed the `$type` parameter, added the `$types` and `$origins` parameters.
* @since 6.3.0 Add fallback layout styles for Post Template when block gap support isn't available.
* @since 6.6.0 Added `skip_root_layout_styles` option to omit layout styles if desired.
* @since 6.6.0 Added boolean `skip_root_layout_styles` option to omit layout styles if desired.
*
* @param string[] $types Types of styles to load. Will load all by default. It accepts:
* - `variables`: only the CSS Custom Properties for presets & custom ones.
Expand All @@ -1260,6 +1260,7 @@ public function get_settings() {
* @type string $scope Makes sure all style are scoped to a given selector
* @type string $root_selector Overwrites and forces a given selector to be used on the root node
* @type bool $skip_root_layout_styles Omits root layout styles from the generated stylesheet. Default false.
* @type bool $block_style_variations Includes styles for block style variations in the generated stylesheet. Default false.
aaronrobertshaw marked this conversation as resolved.
Show resolved Hide resolved
* }
* @return string The resulting stylesheet.
*/
Expand All @@ -1281,7 +1282,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'
}

$blocks_metadata = static::get_blocks_metadata();
$style_nodes = static::get_style_nodes( $this->theme_json, $blocks_metadata );
$style_nodes = static::get_style_nodes( $this->theme_json, $blocks_metadata, $options );
$setting_nodes = static::get_setting_nodes( $this->theme_json, $blocks_metadata );

$root_style_key = array_search( static::ROOT_BLOCK_SELECTOR, array_column( $style_nodes, 'selector' ), true );
Expand Down Expand Up @@ -2446,12 +2447,18 @@ protected static function get_setting_nodes( $theme_json, $selectors = array() )
* ]
*
* @since 5.8.0
* @since 6.6.0 Added options array for modifying generated nodes.
*
* @param array $theme_json The tree to extract style nodes from.
* @param array $selectors List of selectors per block.
* @param array $options {
* Optional. An array of options for now used for internal purposes only (may change without notice).
*
* @type bool $block_style_variations Includes style nodes for block style variations. Default false.
aaronrobertshaw marked this conversation as resolved.
Show resolved Hide resolved
* }
* @return array An array of style nodes metadata.
*/
protected static function get_style_nodes( $theme_json, $selectors = array() ) {
protected static function get_style_nodes( $theme_json, $selectors = array(), $options = array() ) {
$nodes = array();
if ( ! isset( $theme_json['styles'] ) ) {
return $nodes;
Expand Down Expand Up @@ -2493,7 +2500,7 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) {
return $nodes;
}

$block_nodes = static::get_block_nodes( $theme_json );
$block_nodes = static::get_block_nodes( $theme_json, $selectors, $options );
foreach ( $block_nodes as $block_node ) {
$nodes[] = $block_node;
}
Expand Down Expand Up @@ -2564,12 +2571,19 @@ private static function update_separator_declarations( $declarations ) {
*
* @since 6.1.0
* @since 6.3.0 Refactored and stabilized selectors API.
* @since 6.6.0 Added optional selectors and options for generating block nodes.
*
* @param array $theme_json The theme.json converted to an array.
* @param array $selectors Optional list of selectors per block.
* @param array $options {
* Optional. An array of options for now used for internal purposes only (may change without notice).
*
* @type bool $block_style_variations Includes nodes for block style variations. Default false.
* }
* @return array The block nodes in theme.json.
*/
private static function get_block_nodes( $theme_json ) {
$selectors = static::get_blocks_metadata();
private static function get_block_nodes( $theme_json, $selectors = array(), $options = array() ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've checked these changes against WordPress/gutenberg#41217 and smoke tested this PR.

LGTM

Thanks for cleaning that up.

$selectors = empty( $selectors ) ? static::get_blocks_metadata() : $selectors;
$nodes = array();
if ( ! isset( $theme_json['styles'] ) ) {
return $nodes;
Expand Down Expand Up @@ -2597,7 +2611,8 @@ private static function get_block_nodes( $theme_json ) {
}

$variation_selectors = array();
if ( isset( $node['variations'] ) ) {
$include_variations = $options['block_style_variations'] ?? false;
if ( $include_variations && isset( $node['variations'] ) ) {
foreach ( $node['variations'] as $variation => $node ) {
$variation_selectors[] = array(
'path' => array( 'styles', 'blocks', $name, 'variations', $variation ),
Expand Down Expand Up @@ -3266,7 +3281,8 @@ public static function remove_insecure_properties( $theme_json, $origin = 'theme
$theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names, $valid_variations );

$blocks_metadata = static::get_blocks_metadata();
$style_nodes = static::get_style_nodes( $theme_json, $blocks_metadata );
$style_options = array( 'block_style_variations' => true ); // Allow variations data.
$style_nodes = static::get_style_nodes( $theme_json, $blocks_metadata, $style_options );

foreach ( $style_nodes as $metadata ) {
$input = _wp_array_get( $theme_json, $metadata['path'], array() );
Expand Down
81 changes: 81 additions & 0 deletions tests/phpunit/tests/theme/wpThemeJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -5500,4 +5500,85 @@ public function test_scope_style_node_selectors() {

$this->assertEquals( $expected, $actual );
}

/**
* Block style variations styles aren't generated by default. This test covers
* the `get_block_nodes` does not include variations by default, preventing
* the inclusion of their styles.
*
* @ticket 61443
*/
public function test_opt_out_of_block_style_variations_by_default() {
$theme_json = new ReflectionClass( 'WP_Theme_JSON' );

$func = $theme_json->getMethod( 'get_block_nodes' );
$func->setAccessible( true );

$theme_json = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array(
'blocks' => array(
'core/button' => array(
'variations' => array(
'outline' => array(
'color' => array(
'background' => 'red',
),
),
),
),
),
),
);
$selectors = array();

$block_nodes = $func->invoke( null, $theme_json, $selectors );
$button_variations = $block_nodes[0]['variations'] ?? array();

$this->assertEquals( array(), $button_variations );
}

/**
* Block style variations styles aren't generated by default. This test ensures
* variations are included by `get_block_nodes` when requested.
*
* @ticket 61443
*/
public function test_opt_in_to_block_style_variations() {
$theme_json = new ReflectionClass( 'WP_Theme_JSON' );

$func = $theme_json->getMethod( 'get_block_nodes' );
$func->setAccessible( true );

$theme_json = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array(
'blocks' => array(
'core/button' => array(
'variations' => array(
'outline' => array(
'color' => array(
'background' => 'red',
),
),
),
),
),
),
);
$selectors = array();
$options = array( 'block_style_variations' => true );

$block_nodes = $func->invoke( null, $theme_json, $selectors, $options );
$button_variations = $block_nodes[0]['variations'] ?? array();

$expected = array(
array(
'path' => array( 'styles', 'blocks', 'core/button', 'variations', 'outline' ),
'selector' => '.wp-block-button.is-style-outline .wp-block-button__link',
),
);

$this->assertEquals( $expected, $button_variations );
}
}
Loading