From 82c3a1ab2c1da33a252572282aa55534b8e43c86 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 14 Jun 2024 22:22:00 +1000 Subject: [PATCH 1/7] Global Styles: Prevent duplicate CSS for block style variations --- .../block-supports/block-style-variations.php | 1 + src/wp-includes/class-wp-theme-json.php | 27 +++++-- tests/phpunit/tests/theme/wpThemeJson.php | 79 +++++++++++++++++++ 3 files changed, 100 insertions(+), 7 deletions(-) diff --git a/src/wp-includes/block-supports/block-style-variations.php b/src/wp-includes/block-supports/block-style-variations.php index 8e84292ac0eb4..6cfb1d65a45bd 100644 --- a/src/wp-includes/block-supports/block-style-variations.php +++ b/src/wp-includes/block-supports/block-style-variations.php @@ -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", ) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 05f5e7b9e7629..509ee441899d7 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -750,7 +750,7 @@ public static function get_element_class_name( $element ) { * @param string $origin Optional. What source of data this object represents. * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. */ - public function __construct( $theme_json = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA ), $origin = 'theme' ) { + public function __construct( $theme_json = array( 'version' => self::LATEST_SCHEMA ), $origin = 'theme' ) { if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { $origin = 'theme'; } @@ -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. * } * @return string The resulting stylesheet. */ @@ -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 ); @@ -2449,9 +2450,14 @@ protected static function get_setting_nodes( $theme_json, $selectors = array() ) * * @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. + * } * @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; @@ -2493,7 +2499,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, $options ); foreach ( $block_nodes as $block_node ) { $nodes[] = $block_node; } @@ -2566,9 +2572,14 @@ private static function update_separator_declarations( $declarations ) { * @since 6.3.0 Refactored and stabilized selectors API. * * @param array $theme_json The theme.json converted to an array. + * @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 ) { + private static function get_block_nodes( $theme_json, $options = array() ) { $selectors = static::get_blocks_metadata(); $nodes = array(); if ( ! isset( $theme_json['styles'] ) ) { @@ -2597,7 +2608,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 ), @@ -3266,7 +3278,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() ); diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 6a0597be82508..91cd2f9a168ae 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -5500,4 +5500,83 @@ 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', + ), + ), + ), + ), + ), + ), + ); + + $block_nodes = $func->invoke( null, $theme_json ); + $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', + ), + ), + ), + ), + ), + ), + ); + $options = array( 'block_style_variations' => true ); + + $block_nodes = $func->invoke( null, $theme_json, $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 ); + } } From 0383a95d4f4f23b197cc56898ecc4fa4325dc98c Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:05:05 +1000 Subject: [PATCH 2/7] Fix overzealous phpcbf --- src/wp-includes/class-wp-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 509ee441899d7..8a9bc0c98cc98 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -750,7 +750,7 @@ public static function get_element_class_name( $element ) { * @param string $origin Optional. What source of data this object represents. * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. */ - public function __construct( $theme_json = array( 'version' => self::LATEST_SCHEMA ), $origin = 'theme' ) { + public function __construct( $theme_json = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA ), $origin = 'theme' ) { if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { $origin = 'theme'; } From da7c09d2f2c4ce07ae4a339b5e56bfdfe539c07c Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:07:55 +1000 Subject: [PATCH 3/7] Fix function signatures to absorb old missed backport --- src/wp-includes/class-wp-theme-json.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 8a9bc0c98cc98..43774ca009e09 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -2447,6 +2447,7 @@ 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. @@ -2499,7 +2500,7 @@ protected static function get_style_nodes( $theme_json, $selectors = array(), $o return $nodes; } - $block_nodes = static::get_block_nodes( $theme_json, $options ); + $block_nodes = static::get_block_nodes( $theme_json, $selectors, $options ); foreach ( $block_nodes as $block_node ) { $nodes[] = $block_node; } @@ -2570,8 +2571,10 @@ 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). * @@ -2579,8 +2582,8 @@ private static function update_separator_declarations( $declarations ) { * } * @return array The block nodes in theme.json. */ - private static function get_block_nodes( $theme_json, $options = array() ) { - $selectors = static::get_blocks_metadata(); + private static function get_block_nodes( $theme_json, $selectors = array(), $options = array() ) { + $selectors = empty( $selectors ) ? static::get_blocks_metadata() : $selectors; $nodes = array(); if ( ! isset( $theme_json['styles'] ) ) { return $nodes; From 8011db329a06eb4ecae3d739b6d5d8b83fa7fa7f Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:08:17 +1000 Subject: [PATCH 4/7] Revert the unit tests back to the as they are in GB --- tests/phpunit/tests/theme/wpThemeJson.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 91cd2f9a168ae..bcf0468442abb 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -5530,8 +5530,9 @@ public function test_opt_out_of_block_style_variations_by_default() { ), ), ); + $selectors = array(); - $block_nodes = $func->invoke( null, $theme_json ); + $block_nodes = $func->invoke( null, $theme_json, $selectors ); $button_variations = $block_nodes[0]['variations'] ?? array(); $this->assertEquals( array(), $button_variations ); @@ -5565,9 +5566,10 @@ public function test_opt_in_to_block_style_variations() { ), ), ); + $selectors = array(); $options = array( 'block_style_variations' => true ); - $block_nodes = $func->invoke( null, $theme_json, $options ); + $block_nodes = $func->invoke( null, $theme_json, $selectors, $options ); $button_variations = $block_nodes[0]['variations'] ?? array(); $expected = array( From 7a72f569f820b706d0bae5837d043e002eb07933 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 17 Jun 2024 09:26:06 +1000 Subject: [PATCH 5/7] Address nit for since comment --- src/wp-includes/class-wp-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 43774ca009e09..4fdc8b1ff595a 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -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. From 1d8e2a50672bc92ef3ebf90714767ff66a362748 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:49:48 +1000 Subject: [PATCH 6/7] Update src/wp-includes/class-wp-theme-json.php Co-authored-by: Mukesh Panchal --- src/wp-includes/class-wp-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 4fdc8b1ff595a..489c6010db9cc 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -2454,7 +2454,7 @@ protected static function get_setting_nodes( $theme_json, $selectors = array() ) * @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. + * @type bool $block_style_variations Includes style nodes for block style variations. Default false. * } * @return array An array of style nodes metadata. */ From 0933c7da533a546919d773e779105865dd09b681 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:13:18 +1000 Subject: [PATCH 7/7] Prefix block style variations option with include for clarity --- .../block-supports/block-style-variations.php | 6 +++--- src/wp-includes/class-wp-theme-json.php | 21 ++++++++++--------- tests/phpunit/tests/theme/wpThemeJson.php | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/wp-includes/block-supports/block-style-variations.php b/src/wp-includes/block-supports/block-style-variations.php index 6cfb1d65a45bd..b85ab6aad655a 100644 --- a/src/wp-includes/block-supports/block-style-variations.php +++ b/src/wp-includes/block-supports/block-style-variations.php @@ -136,9 +136,9 @@ 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", + 'include_block_style_variations' => true, + 'skip_root_layout_styles' => true, + 'scope' => ".$class_name", ) ); diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 489c6010db9cc..3b8bb1c50e84f 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -750,7 +750,7 @@ public static function get_element_class_name( $element ) { * @param string $origin Optional. What source of data this object represents. * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. */ - public function __construct( $theme_json = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA ), $origin = 'theme' ) { + public function __construct( $theme_json = array( 'version' => self::LATEST_SCHEMA ), $origin = 'theme' ) { if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { $origin = 'theme'; } @@ -1247,7 +1247,8 @@ 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 boolean `skip_root_layout_styles` option to omit layout styles if desired. + * @since 6.6.0 Added boolean `skip_root_layout_styles` and `include_block_style_variations` options + * to control styles output as 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. @@ -1257,10 +1258,10 @@ public function get_settings() { * @param array $options { * Optional. An array of options for now used for internal purposes only (may change without notice). * - * @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. + * @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 $include_block_style_variations Includes styles for block style variations in the generated stylesheet. Default false. * } * @return string The resulting stylesheet. */ @@ -2454,7 +2455,7 @@ protected static function get_setting_nodes( $theme_json, $selectors = array() ) * @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. + * @type bool $include_block_style_variations Includes style nodes for block style variations. Default false. * } * @return array An array of style nodes metadata. */ @@ -2578,7 +2579,7 @@ private static function update_separator_declarations( $declarations ) { * @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. + * @type bool $include_block_style_variations Includes nodes for block style variations. Default false. * } * @return array The block nodes in theme.json. */ @@ -2611,7 +2612,7 @@ private static function get_block_nodes( $theme_json, $selectors = array(), $opt } $variation_selectors = array(); - $include_variations = $options['block_style_variations'] ?? false; + $include_variations = $options['include_block_style_variations'] ?? false; if ( $include_variations && isset( $node['variations'] ) ) { foreach ( $node['variations'] as $variation => $node ) { $variation_selectors[] = array( @@ -3281,7 +3282,7 @@ 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_options = array( 'block_style_variations' => true ); // Allow variations data. + $style_options = array( 'include_block_style_variations' => true ); // Allow variations data. $style_nodes = static::get_style_nodes( $theme_json, $blocks_metadata, $style_options ); foreach ( $style_nodes as $metadata ) { diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index bcf0468442abb..cb8545534bccf 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -5567,7 +5567,7 @@ public function test_opt_in_to_block_style_variations() { ), ); $selectors = array(); - $options = array( 'block_style_variations' => true ); + $options = array( 'include_block_style_variations' => true ); $block_nodes = $func->invoke( null, $theme_json, $selectors, $options ); $button_variations = $block_nodes[0]['variations'] ?? array();