From 49efa0b9e0d2c545034a32ba94ec2c4b593eedd6 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 09:16:25 +0200 Subject: [PATCH 01/30] Theme Json: Don't output double selectors for elements inside blocks #40889 Co-authored-by: Ben Dwyer --- src/wp-includes/class-wp-theme-json.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 2833e8be9c94d..a66375e858af3 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -611,6 +611,10 @@ protected static function get_blocks_metadata() { foreach ( static::ELEMENTS as $el_name => $el_selector ) { $element_selector = array(); foreach ( $block_selectors as $selector ) { + if ( $selector === $el_selector ) { + $element_selector = array( $el_selector ); + break; + } $element_selector[] = $selector . ' ' . $el_selector; } static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector ); From 84e59614ec6cb655f5d8cf79cb7f0e42c955a8ed Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 09:46:16 +0200 Subject: [PATCH 02/30] Global Styles: Load block CSS conditionally #41160 Co-authored-by: Ben Dwyer --- src/wp-includes/class-wp-theme-json.php | 51 +++++++++++++++++++ .../get-global-styles-and-settings.php | 23 +++++++++ src/wp-includes/script-loader.php | 33 ++++++++++++ src/wp-settings.php | 1 + 4 files changed, 108 insertions(+) create mode 100644 src/wp-includes/get-global-styles-and-settings.php diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index a66375e858af3..7b061edeab675 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1502,6 +1502,40 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { return $nodes; } + $nodes = array_merge( $nodes, static::get_block_nodes( $theme_json ) ); + + // This filter allows us to modify the output of WP_Theme_JSON so that we can do things like loading block CSS independently. + return apply_filters( 'get_style_nodes', $nodes ); + } + + /** + * A public helper to get the block nodes from a theme.json file. + * + * @return array The block nodes in theme.json. + */ + public function get_styles_block_nodes() { + return static::get_block_nodes( $this->theme_json ); + } + + /** + * An internal method to get the block nodes from a theme.json file. + * + * @param array $theme_json The theme.json converted to an array. + * + * @return array The block nodes in theme.json. + */ + private static function get_block_nodes( $theme_json ) { + $selectors = static::get_blocks_metadata(); + $nodes = array(); + if ( ! isset( $theme_json['styles'] ) ) { + return $nodes; + } + + // Blocks. + if ( ! isset( $theme_json['styles']['blocks'] ) ) { + return $nodes; + } + foreach ( $theme_json['styles']['blocks'] as $name => $node ) { $selector = null; if ( isset( $selectors[ $name ]['selector'] ) ) { @@ -1514,6 +1548,7 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { } $nodes[] = array( + 'name' => $name, 'path' => array( 'styles', 'blocks', $name ), 'selector' => $selector, 'duotone' => $duotone_selector, @@ -1532,6 +1567,22 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { return $nodes; } + /** + * Gets the CSS rules for a particular block from theme.json. + * + * @param array $block_metadata Meta data about the block to get styles for. + * + * @return array Styles for the block. + */ + public function get_styles_for_block( $block_metadata ) { + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); + $selector = $block_metadata['selector']; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + $declarations = static::compute_style_properties( $node, $settings ); + $block_rules = static::to_ruleset( $selector, $declarations ); + return $block_rules; + } + /** * For metadata values that can either be booleans or paths to booleans, gets the value. * diff --git a/src/wp-includes/get-global-styles-and-settings.php b/src/wp-includes/get-global-styles-and-settings.php new file mode 100644 index 0000000000000..b730ab2f8bcce --- /dev/null +++ b/src/wp-includes/get-global-styles-and-settings.php @@ -0,0 +1,23 @@ +get_styles_block_nodes(); + foreach ( $block_nodes as $metadata ) { + $block_css = $tree->get_styles_for_block( $metadata ); + $block_name = str_replace( 'core/', '', $metadata['name'] ); + // These block styles are added on block_render. + // This hooks inline CSS to them so that they are loaded conditionally + // based on whether or not the block is used on the page. + wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + } +} \ No newline at end of file diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 11858ec9bfe10..31c18d8b6247b 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2353,6 +2353,29 @@ function wp_common_block_scripts_and_styles() { do_action( 'enqueue_block_assets' ); } +/** + * This applies a filter to the list of style nodes that comes from `get_style_nodes` in WP_Theme_JSON. + * This particular filter removes all of the blocks from the array. + * + * We want WP_Theme_JSON to be ignorant of the implementation details of how the CSS is being used. + * This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are loading separate assets, + * without making the class aware of that detail. + * + * @since 6.1 + * + * @param array $nodes The nodes to filter. + * @return array A filtered array of style nodes. + */ +function filter_out_block_nodes( $nodes ) { + return array_filter( + $nodes, + function( $node ) { + return ! in_array( 'blocks', $node['path'], true ); + }, + ARRAY_FILTER_USE_BOTH + ); +} + /** * Enqueues the global styles defined via theme.json. * @@ -2377,6 +2400,16 @@ function wp_enqueue_global_styles() { return; } + /** + * If we are loading CSS for each block separately, then we can load the theme.json CSS conditionally. + * This removes the CSS from the global-styles stylesheet and adds it to the inline CSS for each block. + */ + if ( $separate_assets ) { + add_filter( 'get_style_nodes', 'filter_out_block_nodes' ); + // add each block as an inline css. + wp_add_global_styles_for_blocks(); + } + $stylesheet = wp_get_global_stylesheet(); if ( empty( $stylesheet ) ) { diff --git a/src/wp-settings.php b/src/wp-settings.php index 8fe16195e0aa0..415063db3fa88 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -170,6 +170,7 @@ require ABSPATH . WPINC . '/query.php'; require ABSPATH . WPINC . '/class-wp-date-query.php'; require ABSPATH . WPINC . '/theme.php'; +require ABSPATH . WPINC . '/get-global-styles-and-settings.php'; require ABSPATH . WPINC . '/class-wp-theme.php'; require ABSPATH . WPINC . '/class-wp-theme-json-schema.php'; require ABSPATH . WPINC . '/class-wp-theme-json.php'; From 89e4c3e8f7c2d8d20f44f753d002c1320614a6f9 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 10:01:43 +0200 Subject: [PATCH 03/30] formatting --- src/wp-includes/get-global-styles-and-settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/get-global-styles-and-settings.php b/src/wp-includes/get-global-styles-and-settings.php index b730ab2f8bcce..473765308ff53 100644 --- a/src/wp-includes/get-global-styles-and-settings.php +++ b/src/wp-includes/get-global-styles-and-settings.php @@ -20,4 +20,4 @@ function wp_add_global_styles_for_blocks() { // based on whether or not the block is used on the page. wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); } -} \ No newline at end of file +} From 76bb02061d5691d061c80f3754c4099f60018683 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 10:12:05 +0200 Subject: [PATCH 04/30] Add support for button elements to theme.json #40260 Co-authored-by: Ben Dwyer Co-authored-by: Dave Smith Co-authored-by: Adam Zielinski --- src/wp-includes/class-wp-theme-json.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 7b061edeab675..4953a120e482a 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -343,6 +343,8 @@ class WP_Theme_JSON { ), ); + const __EXPERIMENTAL_ELEMENT_BUTTON_CLASS_NAME = 'wp-element-button'; + /** * The valid elements that can be found under styles. * From 08da14c59894da9b75f7ddc678f83f03d1bf54b4 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 10:18:13 +0200 Subject: [PATCH 05/30] Elements: Add an API make it easier to get class names #41753 Co-authored-by: Ben Dwyer Co-authored-by: George Mamadashvili --- src/wp-includes/class-wp-theme-json.php | 19 +++++++++++++++++-- tests/phpunit/tests/theme/wpThemeJson.php | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 4953a120e482a..27c174fdce53c 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -343,8 +343,6 @@ class WP_Theme_JSON { ), ); - const __EXPERIMENTAL_ELEMENT_BUTTON_CLASS_NAME = 'wp-element-button'; - /** * The valid elements that can be found under styles. * @@ -367,6 +365,23 @@ class WP_Theme_JSON { 'caption' => '.wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption', ); + const __EXPERIMENTAL_ELEMENT_CLASS_NAMES = array( + 'button' => 'wp-element-button', + ); + + /** + * Given an element name, returns a class name. + * + * @param string $element The name of the element. + * + * @return string The name of the class. + * + * @since 6.1.0 + */ + public static function get_element_class_name( $element ) { + return array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ? static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ] : ''; + } + /** * Options that settings.appearanceTools enables. * diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 8a3649dbcbb90..a4e512b3b9f6d 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -2621,4 +2621,18 @@ function test_export_data_sets_appearance_tools() { $this->assertEqualSetsWithIndex( $expected, $actual ); } + + function test_get_element_class_name_button() { + $expected = 'wp-element-button'; + $actual = WP_Theme_JSON::get_element_class_name( 'button' ); + + $this->assertEquals( $expected, $actual ); + } + + function test_get_element_class_name_invalid() { + $expected = ''; + $actual = WP_Theme_JSON::get_element_class_name( 'unknown-element' ); + + $this->assertEquals( $expected, $actual ); + } } From 73dac664ef855bf75858ae537d2c04857a9fc091 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 10:22:48 +0200 Subject: [PATCH 06/30] Elements: Button - Fix element selectors #41822 Co-authored-by: Ben Dwyer Co-authored-by: Andrei Draganescu --- src/wp-includes/class-wp-theme-json.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 27c174fdce53c..bb0228f24ce8d 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -632,7 +632,12 @@ protected static function get_blocks_metadata() { $element_selector = array( $el_selector ); break; } - $element_selector[] = $selector . ' ' . $el_selector; + // This converts selectors like '.wp-element-button, .wp-block-button__link' + // to an array, so that the block selector is added to both parts of the selector. + $el_selectors = explode( ',', $el_selector ); + foreach ( $el_selectors as $el_selector_item ) { + $element_selector[] = $selector . ' ' . $el_selector_item; + } } static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector ); } From a478c4654012ca4d01dc437aa7a91d2363a20fa6 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 10:48:11 +0200 Subject: [PATCH 07/30] Support pseudo selectors on elements in theme json #41786 Co-authored-by: Ben Dwyer Co-authored-by: Dave Smith Co-authored-by: Adam Zielinski --- src/wp-includes/class-wp-theme-json.php | 108 +++++++- tests/phpunit/tests/theme/wpThemeJson.php | 302 ++++++++++++++++++++++ 2 files changed, 404 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index bb0228f24ce8d..06aa025770867 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -343,6 +343,15 @@ class WP_Theme_JSON { ), ); + /** + * Whitelist which defines which pseudo selectors are enabled for + * which elements. + * Note: this will effect both top level and block level elements. + */ + const VALID_ELEMENT_PSEUDO_SELECTORS = array( + 'link' => array( ':hover', ':focus', ':active' ), + ); + /** * The valid elements that can be found under styles. * @@ -505,14 +514,17 @@ protected static function do_opt_in_into_settings( &$context ) { * @return array The sanitized output. */ protected static function sanitize( $input, $valid_block_names, $valid_element_names ) { + $output = array(); if ( ! is_array( $input ) ) { return $output; } + // Preserve only the top most level keys. $output = array_intersect_key( $input, array_flip( static::VALID_TOP_LEVEL_KEYS ) ); + // Remove any rules that are annotated as "top" in VALID_STYLES constant. // Some styles are only meant to be available at the top-level (e.g.: blockGap), // hence, the schema for blocks & elements should not have them. $styles_non_top_level = static::VALID_STYLES; @@ -527,9 +539,22 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n // Build the schema based on valid block & element names. $schema = array(); $schema_styles_elements = array(); + + // Set allowed element pseudo selectors based on per element allow list. + // Target data structure in schema: + // e.g. + // - top level elements: `$schema['styles']['elements']['link'][':hover']`. + // - block level elements: `$schema['styles']['blocks']['core/button']['elements']['link'][':hover']`. foreach ( $valid_element_names as $element ) { $schema_styles_elements[ $element ] = $styles_non_top_level; + + if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { + $schema_styles_elements[ $element ][ $pseudo_selector ] = $styles_non_top_level; + } + } } + $schema_styles_blocks = array(); $schema_settings_blocks = array(); foreach ( $valid_block_names as $block ) { @@ -537,6 +562,7 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n $schema_styles_blocks[ $block ] = $styles_non_top_level; $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements; } + $schema['styles'] = static::VALID_STYLES; $schema['styles']['blocks'] = $schema_styles_blocks; $schema['styles']['elements'] = $schema_styles_elements; @@ -1516,6 +1542,19 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { 'path' => array( 'styles', 'elements', $element ), 'selector' => static::ELEMENTS[ $element ], ); + + // Handle any pseudo selectors for the element. + if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] ) ) { + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { + + if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) { + $nodes[] = array( + 'path' => array( 'styles', 'elements', $element ), + 'selector' => static::ELEMENTS[ $element ] . $pseudo_selector, + ); + } + } + } } } @@ -1582,6 +1621,18 @@ private static function get_block_nodes( $theme_json ) { 'path' => array( 'styles', 'blocks', $name, 'elements', $element ), 'selector' => $selectors[ $name ]['elements'][ $element ], ); + + // Handle any psuedo selectors for the element. + if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] ) ) { + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { + if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) { + $nodes[] = array( + 'path' => array( 'styles', 'blocks', $name, 'elements', $element ), + 'selector' => $selectors[ $name ]['elements'][ $element ] . $pseudo_selector, + ); + } + } + } } } } @@ -1597,11 +1648,38 @@ private static function get_block_nodes( $theme_json ) { * @return array Styles for the block. */ public function get_styles_for_block( $block_metadata ) { - $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); - $selector = $block_metadata['selector']; - $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); - $declarations = static::compute_style_properties( $node, $settings ); - $block_rules = static::to_ruleset( $selector, $declarations ); + + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); + + $selector = $block_metadata['selector']; + $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); + + // Attempt to parse a pseudo selector (e.g. ":hover") from the $selector ("a:hover"). + $pseudo_matches = array(); + preg_match( '/:[a-z]+/', $selector, $pseudo_matches ); + $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null; + + // Get a reference to element name from path. + // $block_metadata['path'] = array('styles','elements','link'); + // Make sure that $block_metadata['path'] describes an element node, like ['styles', 'element', 'link']. + // Skip non-element paths like just ['styles']. + $is_processing_element = in_array( 'elements', $block_metadata['path'], true ); + + $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null; + + // If the current selector is a pseudo selector that's defined in the allow list for the current + // element then compute the style properties for it. + // Otherwise just compute the styles for the default selector as normal. + if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) && isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) ) { + $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings ); + } else { + $declarations = static::compute_style_properties( $node, $settings ); + } + + $block_rules = ''; + + $block_rules .= static::to_ruleset( $selector, $declarations ); + return $block_rules; } @@ -1914,10 +1992,12 @@ public static function remove_insecure_properties( $theme_json ) { $valid_block_names = array_keys( static::get_blocks_metadata() ); $valid_element_names = array_keys( static::ELEMENTS ); - $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names ); + + $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names ); $blocks_metadata = static::get_blocks_metadata(); $style_nodes = static::get_style_nodes( $theme_json, $blocks_metadata ); + foreach ( $style_nodes as $metadata ) { $input = _wp_array_get( $theme_json, $metadata['path'], array() ); if ( empty( $input ) ) { @@ -1925,6 +2005,22 @@ public static function remove_insecure_properties( $theme_json ) { } $output = static::remove_insecure_styles( $input ); + + // Get a reference to element name from path. + // $metadata['path'] = array('styles','elements','link');. + $current_element = $metadata['path'][ count( $metadata['path'] ) - 1 ]; + + // $output is stripped of pseudo selectors. Readd and process them + // for insecure styles here. + if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) ) { + + foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] as $pseudo_selector ) { + if ( isset( $input[ $pseudo_selector ] ) ) { + $output[ $pseudo_selector ] = static::remove_insecure_styles( $input[ $pseudo_selector ] ); + } + } + } + if ( ! empty( $output ) ) { _wp_array_set( $sanitized, $metadata['path'], $output ); } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index a4e512b3b9f6d..0cfea52d12de4 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -725,6 +725,261 @@ public function test_get_stylesheet_preset_values_are_marked_as_important() { ); } + function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => 'green', + 'background' => 'red', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'green', + ), + 'typography' => array( + 'textTransform' => 'uppercase', + 'fontSize' => '10em', + ), + ), + ':focus' => array( + 'color' => array( + 'text' => 'yellow', + 'background' => 'black', + ), + ), + ), + ), + ), + ) + ); + + $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $element_styles = 'a{background-color: red;color: green;}a:hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:focus{background-color: black;color: yellow;}'; + + $expected = $base_styles . $element_styles; + + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + } + + function test_get_stylesheet_handles_only_psuedo_selector_rules_for_given_property() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'elements' => array( + 'link' => array( + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'green', + ), + 'typography' => array( + 'textTransform' => 'uppercase', + 'fontSize' => '10em', + ), + ), + ':focus' => array( + 'color' => array( + 'text' => 'yellow', + 'background' => 'black', + ), + ), + ), + ), + ), + ) + ); + + $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $element_styles = 'a:hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:focus{background-color: black;color: yellow;}'; + + $expected = $base_styles . $element_styles; + + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + } + + function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'elements' => array( + 'h4' => array( + 'color' => array( + 'text' => 'green', + 'background' => 'red', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'green', + ), + ), + ':focus' => array( + 'color' => array( + 'text' => 'yellow', + 'background' => 'black', + ), + ), + ), + ), + ), + ) + ); + + $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $element_styles = 'h4{background-color: red;color: green;}'; + + $expected = $base_styles . $element_styles; + + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + } + + function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => 'green', + 'background' => 'red', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'green', + ), + ), + ':levitate' => array( + 'color' => array( + 'text' => 'yellow', + 'background' => 'black', + ), + ), + ), + ), + ), + ) + ); + + $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $element_styles = 'a{background-color: red;color: green;}a:hover{background-color: green;color: red;}'; + + $expected = $base_styles . $element_styles; + + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertStringNotContainsString( 'a:levitate{', $theme_json->get_stylesheet( array( 'styles' ) ) ); + } + + function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseudo_selectors() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/group' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => 'green', + 'background' => 'red', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'green', + ), + 'typography' => array( + 'textTransform' => 'uppercase', + 'fontSize' => '10em', + ), + ), + ':focus' => array( + 'color' => array( + 'text' => 'yellow', + 'background' => 'black', + ), + ), + ), + ), + ), + ), + ), + ) + ); + + $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $element_styles = '.wp-block-group a{background-color: red;color: green;}.wp-block-group a:hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:focus{background-color: black;color: yellow;}'; + + $expected = $base_styles . $element_styles; + + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + } + + function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_selectors() { + $theme_json = new WP_Theme_JSON_Gutenberg( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => 'green', + 'background' => 'red', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'green', + ), + ), + ), + ), + 'blocks' => array( + 'core/group' => array( + 'elements' => array( + 'link' => array( + ':hover' => array( + 'color' => array( + 'text' => 'yellow', + 'background' => 'black', + ), + ), + ), + ), + ), + ), + ), + ) + ); + + $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $element_styles = 'a{background-color: red;color: green;}a:hover{background-color: green;color: red;}.wp-block-group a:hover{background-color: black;color: yellow;}'; + + $expected = $base_styles . $element_styles; + + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + } + /** * @ticket 52991 * @ticket 54336 @@ -2086,6 +2341,53 @@ public function test_remove_insecure_properties_applies_safe_styles() { $this->assertEqualSetsWithIndex( $expected, $actual ); } + function test_remove_invalid_element_pseudo_selectors() { + $actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => 'hotpink', + 'background' => 'yellow', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'blue', + ), + ), + ), + ), + ), + ), + true + ); + + $expected = array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'styles' => array( + 'elements' => array( + 'link' => array( + 'color' => array( + 'text' => 'hotpink', + 'background' => 'yellow', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + 'background' => 'blue', + ), + ), + ), + ), + ), + ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + /** * @ticket 54336 */ From 13d698602073081c81c46d117f541410735fba40 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 10:53:14 +0200 Subject: [PATCH 08/30] Global Styles: Allow references to values in other locations in the tree Co-authored-by: Ben Dwyer --- src/wp-includes/class-wp-theme-json.php | 37 +++++- tests/phpunit/tests/theme/wpThemeJson.php | 146 +++++++++++++++++++--- 2 files changed, 162 insertions(+), 21 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 06aa025770867..05401278f61dd 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1368,9 +1368,10 @@ protected static function flatten_tree( $tree, $prefix = '', $token = '--' ) { * @param array $styles Styles to process. * @param array $settings Theme settings. * @param array $properties Properties metadata. + * @param array $theme_json Theme JSON array. * @return array Returns the modified $declarations. */ - protected static function compute_style_properties( $styles, $settings = array(), $properties = null ) { + protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) { if ( null === $properties ) { $properties = static::PROPERTIES_METADATA; } @@ -1381,7 +1382,7 @@ protected static function compute_style_properties( $styles, $settings = array() } foreach ( $properties as $css_property => $value_path ) { - $value = static::get_property_value( $styles, $value_path ); + $value = static::get_property_value( $styles, $value_path, $theme_json ); // Look up protected properties, keyed by value path. // Skip protected properties that are explicitly set to `null`. @@ -1417,20 +1418,44 @@ protected static function compute_style_properties( $styles, $settings = array() * "var:preset|color|secondary" to the form * "--wp--preset--color--secondary". * + * It also converts references to a path to the value + * stored at that location, e.g. + * { "ref": "style.color.background" } => "#fff". + * * @since 5.8.0 * @since 5.9.0 Added support for values of array type, which are returned as is. * * @param array $styles Styles subtree. * @param array $path Which property to process. + * @param array $theme_json Theme JSON array. * @return string|array Style property value. */ - protected static function get_property_value( $styles, $path ) { + protected static function get_property_value( $styles, $path, $theme_json = null ) { $value = _wp_array_get( $styles, $path, '' ); + // This converts references to a path to the value at that path + // where the values is an array with a "ref" key, pointing to a path. + // For example: { "ref": "style.color.background" } => "#fff". + if ( is_array( $value ) && array_key_exists( 'ref', $value ) ) { + $value_path = explode( '.', $value['ref'] ); + $ref_value = _wp_array_get( $theme_json, $value_path ); + // Only use the ref value if we find anything. + if ( ! empty( $ref_value ) && is_string( $ref_value ) ) { + $value = $ref_value; + } + + if ( is_array( $ref_value ) && array_key_exists( 'ref', $ref_value ) ) { + $path_string = json_encode( $path ); + $ref_value_string = json_encode( $ref_value ); + _doing_it_wrong( 'get_property_value', "Your theme.json file uses a dynamic value (${ref_value_string}) for the path at ${path_string}. However, the value at ${path_string} is also a dynamic value (pointing to ${ref_value['ref']}) and pointing to another dynamic value is not supported. Please update ${path_string} to point directly to ${ref_value['ref']}.", '6.1.0' ); + } + } + if ( '' === $value || is_array( $value ) ) { return $value; } + // Convert custom CSS properties. $prefix = 'var:'; $prefix_len = strlen( $prefix ); $token_in = '|'; @@ -1671,15 +1696,15 @@ public function get_styles_for_block( $block_metadata ) { // element then compute the style properties for it. // Otherwise just compute the styles for the default selector as normal. if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) && isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) ) { - $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings ); + $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json ); } else { - $declarations = static::compute_style_properties( $node, $settings ); + $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json ); } $block_rules = ''; $block_rules .= static::to_ruleset( $selector, $declarations ); - + return $block_rules; } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 0cfea52d12de4..419b791f2c134 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -726,9 +726,9 @@ public function test_get_stylesheet_preset_values_are_marked_as_important() { } function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { - $theme_json = new WP_Theme_JSON_Gutenberg( + $theme_json = new WP_Theme_JSON( array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'elements' => array( 'link' => array( @@ -769,9 +769,9 @@ function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { } function test_get_stylesheet_handles_only_psuedo_selector_rules_for_given_property() { - $theme_json = new WP_Theme_JSON_Gutenberg( + $theme_json = new WP_Theme_JSON( array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'elements' => array( 'link' => array( @@ -808,9 +808,9 @@ function test_get_stylesheet_handles_only_psuedo_selector_rules_for_given_proper } function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements() { - $theme_json = new WP_Theme_JSON_Gutenberg( + $theme_json = new WP_Theme_JSON( array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'elements' => array( 'h4' => array( @@ -847,9 +847,9 @@ function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_element } function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { - $theme_json = new WP_Theme_JSON_Gutenberg( + $theme_json = new WP_Theme_JSON( array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'elements' => array( 'link' => array( @@ -887,9 +887,9 @@ function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { } function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseudo_selectors() { - $theme_json = new WP_Theme_JSON_Gutenberg( + $theme_json = new WP_Theme_JSON( array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'blocks' => array( 'core/group' => array( @@ -934,9 +934,9 @@ function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseu } function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_selectors() { - $theme_json = new WP_Theme_JSON_Gutenberg( + $theme_json = new WP_Theme_JSON( array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'elements' => array( 'link' => array( @@ -2342,9 +2342,9 @@ public function test_remove_insecure_properties_applies_safe_styles() { } function test_remove_invalid_element_pseudo_selectors() { - $actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( + $actual = WP_Theme_JSON::remove_insecure_properties( array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'elements' => array( 'link' => array( @@ -2366,7 +2366,7 @@ function test_remove_invalid_element_pseudo_selectors() { ); $expected = array( - 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( 'elements' => array( 'link' => array( @@ -2937,4 +2937,120 @@ function test_get_element_class_name_invalid() { $this->assertEquals( $expected, $actual ); } + + /** + * Testing that dynamic properties in theme.json return the value they refrence, e.g. + * array( 'ref' => 'styles.color.background' ) => "#ffffff". + */ + function test_get_property_value_valid() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => 2, + 'styles' => array( + 'color' => array( + 'background' => '#ffffff', + 'text' => '#000000', + ), + 'elements' => array( + 'button' => array( + 'color' => array( + 'background' => array( 'ref' => 'styles.color.text' ), + 'text' => array( 'ref' => 'styles.color.background' ), + ), + ), + ), + ), + ) + ); + + $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #000000;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}'; + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + } + + /** + * Testing that dynamic properties in theme.json that + * refer to other dynamic properties in a loop + * then they should be left untouched. + * + * @expectedIncorrectUsage get_property_value + */ + function test_get_property_value_loop() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => 2, + 'styles' => array( + 'color' => array( + 'background' => '#ffffff', + 'text' => array( 'ref' => 'styles.elements.button.color.background' ), + ), + 'elements' => array( + 'button' => array( + 'color' => array( + 'background' => array( 'ref' => 'styles.color.text' ), + 'text' => array( 'ref' => 'styles.color.background' ), + ), + ), + ), + ), + ) + ); + + $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}'; + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + } + + /** + * Testing that dynamic properties in theme.json that + * refer to other dynamic properties then they should be left unprocessed. + * + * @expectedIncorrectUsage get_property_value + */ + function test_get_property_value_recursion() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => 2, + 'styles' => array( + 'color' => array( + 'background' => '#ffffff', + 'text' => array( 'ref' => 'styles.color.background' ), + ), + 'elements' => array( + 'button' => array( + 'color' => array( + 'background' => array( 'ref' => 'styles.color.text' ), + 'text' => array( 'ref' => 'styles.color.background' ), + ), + ), + ), + ), + ) + ); + + $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}'; + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + } + + /** + * Testing that dynamic properties in theme.json that + * refer to themselves then they should be left unprocessed. + * + * @expectedIncorrectUsage get_property_value + */ + function test_get_property_value_self() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => 2, + 'styles' => array( + 'color' => array( + 'background' => '#ffffff', + 'text' => array( 'ref' => 'styles.color.text' ), + ), + ), + ) + ); + + $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + } + } From 824f04d99d31ee860a5708a103a742fa2d2d342e Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 10:54:43 +0200 Subject: [PATCH 09/30] format --- 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 05401278f61dd..dbb22cd548a92 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1673,7 +1673,7 @@ private static function get_block_nodes( $theme_json ) { * @return array Styles for the block. */ public function get_styles_for_block( $block_metadata ) { - + $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); $selector = $block_metadata['selector']; From 669e612e556396ce6b3d7c6ec14bad0969ab3cbf Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 11:22:07 +0200 Subject: [PATCH 10/30] Global Styles: Add support for caption elements #41140 Co-authored-by: Ben Dwyer Co-authored-by: David Calhoun <438664+dcalhoun@users.noreply.github.com> --- src/wp-includes/class-wp-theme-json.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index dbb22cd548a92..b548082e84fc6 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -376,6 +376,7 @@ class WP_Theme_JSON { const __EXPERIMENTAL_ELEMENT_CLASS_NAMES = array( 'button' => 'wp-element-button', + 'caption' => 'wp-element-caption', ); /** From d865f6ace36bc4b3a567340b96cec088eed637ff Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 11:25:25 +0200 Subject: [PATCH 11/30] Fix link element hover bleeding into button element default styles #42072 Co-authored-by: Dave Smith --- src/wp-includes/class-wp-theme-json.php | 24 ++++++++++++++++------- tests/phpunit/tests/theme/wpThemeJson.php | 10 +++++----- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index b548082e84fc6..7528e449e8c50 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -344,7 +344,7 @@ class WP_Theme_JSON { ); /** - * Whitelist which defines which pseudo selectors are enabled for + * Define which defines which pseudo selectors are enabled for * which elements. * Note: this will effect both top level and block level elements. */ @@ -1648,7 +1648,7 @@ private static function get_block_nodes( $theme_json ) { 'selector' => $selectors[ $name ]['elements'][ $element ], ); - // Handle any psuedo selectors for the element. + // Handle any pseudo selectors for the element. if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] ) ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) { @@ -1680,11 +1680,6 @@ public function get_styles_for_block( $block_metadata ) { $selector = $block_metadata['selector']; $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); - // Attempt to parse a pseudo selector (e.g. ":hover") from the $selector ("a:hover"). - $pseudo_matches = array(); - preg_match( '/:[a-z]+/', $selector, $pseudo_matches ); - $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null; - // Get a reference to element name from path. // $block_metadata['path'] = array('styles','elements','link'); // Make sure that $block_metadata['path'] describes an element node, like ['styles', 'element', 'link']. @@ -1693,6 +1688,21 @@ public function get_styles_for_block( $block_metadata ) { $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null; + $element_pseudo_allowed = isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) ? static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] : array(); + + // Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover"). + // This also resets the array keys. + $pseudo_matches = array_values( + array_filter( + $element_pseudo_allowed, + function( $pseudo_selector ) use ( $selector ) { + return str_contains( $selector, $pseudo_selector ); + } + ) + ); + + $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null; + // If the current selector is a pseudo selector that's defined in the allow list for the current // element then compute the style properties for it. // Otherwise just compute the styles for the default selector as normal. diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 419b791f2c134..8b1507eee21b0 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -760,7 +760,7 @@ function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a{background-color: red;color: green;}a:hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:focus{background-color: black;color: yellow;}'; + $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:not(.wp-element-button):focus{background-color: black;color: yellow;}'; $expected = $base_styles . $element_styles; @@ -799,7 +799,7 @@ function test_get_stylesheet_handles_only_psuedo_selector_rules_for_given_proper $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a:hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:focus{background-color: black;color: yellow;}'; + $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;}'; $expected = $base_styles . $element_styles; @@ -877,7 +877,7 @@ function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a{background-color: red;color: green;}a:hover{background-color: green;color: red;}'; + $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;}'; $expected = $base_styles . $element_styles; @@ -925,7 +925,7 @@ function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseu $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = '.wp-block-group a{background-color: red;color: green;}.wp-block-group a:hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:focus{background-color: black;color: yellow;}'; + $element_styles = '.wp-block-group a:not(.wp-element-button){background-color: red;color: green;}.wp-block-group a:not(.wp-element-button):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:not(.wp-element-button):focus{background-color: black;color: yellow;}'; $expected = $base_styles . $element_styles; @@ -972,7 +972,7 @@ function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_sele $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a{background-color: red;color: green;}a:hover{background-color: green;color: red;}.wp-block-group a:hover{background-color: black;color: yellow;}'; + $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;}.wp-block-group a:not(.wp-element-button):hover{background-color: black;color: yellow;}'; $expected = $base_styles . $element_styles; From 32a489a03b59dae851db0a99f087dd2a399490ae Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 11:27:09 +0200 Subject: [PATCH 12/30] Add visited to link element allowed pseudo selector list #42096 Co-authored-by: Dave Smith --- 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 7528e449e8c50..433509ce68b84 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -349,7 +349,7 @@ class WP_Theme_JSON { * Note: this will effect both top level and block level elements. */ const VALID_ELEMENT_PSEUDO_SELECTORS = array( - 'link' => array( ':hover', ':focus', ':active' ), + 'link' => array( ':hover', ':focus', ':active', ':visited' ), ); /** From 48d08e913433bd5777b27b25383544dc5e082d66 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 11:31:28 +0200 Subject: [PATCH 13/30] Link elements: Add a :where selector to the :not to lower specificity #42669 Co-authored-by: Ben Dwyer --- src/wp-includes/class-wp-theme-json.php | 2 +- tests/phpunit/tests/theme/wpThemeJson.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 433509ce68b84..0a82718cfaf94 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -360,7 +360,7 @@ class WP_Theme_JSON { * @var string[] */ const ELEMENTS = array( - 'link' => 'a', + 'link' => 'a:where(:not(.wp-element-button))', // The where is needed to lower the specificity. 'heading' => 'h1, h2, h3, h4, h5, h6', 'h1' => 'h1', 'h2' => 'h2', diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 8b1507eee21b0..27f355149d933 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -760,7 +760,7 @@ function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:not(.wp-element-button):focus{background-color: black;color: yellow;}'; + $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; $expected = $base_styles . $element_styles; @@ -768,7 +768,7 @@ function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } - function test_get_stylesheet_handles_only_psuedo_selector_rules_for_given_property() { + function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_property() { $theme_json = new WP_Theme_JSON( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -799,7 +799,7 @@ function test_get_stylesheet_handles_only_psuedo_selector_rules_for_given_proper $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;}'; + $element_styles = 'a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; $expected = $base_styles . $element_styles; @@ -877,7 +877,7 @@ function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;}'; + $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}'; $expected = $base_styles . $element_styles; @@ -925,7 +925,7 @@ function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseu $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = '.wp-block-group a:not(.wp-element-button){background-color: red;color: green;}.wp-block-group a:not(.wp-element-button):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:not(.wp-element-button):focus{background-color: black;color: yellow;}'; + $element_styles = '.wp-block-group a:where(:not(.wp-element-button)){background-color: red;color: green;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: green;color: red;font-size: 10em;text-transform: uppercase;}.wp-block-group a:where(:not(.wp-element-button)):focus{background-color: black;color: yellow;}'; $expected = $base_styles . $element_styles; @@ -972,7 +972,7 @@ function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_sele $base_styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $element_styles = 'a:not(.wp-element-button){background-color: red;color: green;}a:not(.wp-element-button):hover{background-color: green;color: red;}.wp-block-group a:not(.wp-element-button):hover{background-color: black;color: yellow;}'; + $element_styles = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}a:where(:not(.wp-element-button)):hover{background-color: green;color: red;}.wp-block-group a:where(:not(.wp-element-button)):hover{background-color: black;color: yellow;}'; $expected = $base_styles . $element_styles; From 7afe251d8ee6a7ed5bd732d8e710d98f181bbb0c Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 11:35:58 +0200 Subject: [PATCH 14/30] Pseudo elements supports on button elements #43088 Co-authored-by: Ben Dwyer --- src/wp-includes/class-wp-theme-json.php | 43 +++++++++++++++++++------ 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 0a82718cfaf94..d19892f45f2dd 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -350,6 +350,7 @@ class WP_Theme_JSON { */ const VALID_ELEMENT_PSEUDO_SELECTORS = array( 'link' => array( ':hover', ':focus', ':active', ':visited' ), + 'button' => array( ':hover', ':focus', ':active', ':visited' ), ); /** @@ -593,6 +594,29 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n return $output; } + /** + * This converts selectors like '.wp-element-button, .wp-block-button__link' + * to an array, so that the block selector is added to both parts of the selector. + * + * @param string $element The string with all the element's selectors. + * @param string $selector The string we want to append to the selectors. + * @param string $position The position we wand to append the selector in. + * @return string element selector. + */ + private static function appendToSelector( $element, $selector, $position = 0 ) { + $element_selector = array(); + $el_selectors = explode( ',', $element ); + foreach ( $el_selectors as $el_selector_item ) { + if ( 0 === $position ) { + $element_selector[] = $selector . $el_selector_item; + } else { + $element_selector[] = $el_selector_item . $selector; + } + } + $element_selector = implode( ',', $element_selector ); + return $element_selector; + } + /** * Returns the metadata for each block. * @@ -659,14 +683,9 @@ protected static function get_blocks_metadata() { $element_selector = array( $el_selector ); break; } - // This converts selectors like '.wp-element-button, .wp-block-button__link' - // to an array, so that the block selector is added to both parts of the selector. - $el_selectors = explode( ',', $el_selector ); - foreach ( $el_selectors as $el_selector_item ) { - $element_selector[] = $selector . ' ' . $el_selector_item; - } + $element_selector = static::appendToSelector( $el_selector, $selector . ' ', 0 ); } - static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector ); + static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = $element_selector; } } @@ -1574,9 +1593,11 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) { + $element_selector = array(); + $element_selector = static::appendToSelector( static::ELEMENTS[ $element ], $pseudo_selector, 1 ); $nodes[] = array( 'path' => array( 'styles', 'elements', $element ), - 'selector' => static::ELEMENTS[ $element ] . $pseudo_selector, + 'selector' => $element_selector, ); } } @@ -1652,9 +1673,13 @@ private static function get_block_nodes( $theme_json ) { if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] ) ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) { + + $block_selector = array(); + $block_selector = static::appendToSelector( $selectors[ $name ]['elements'][ $element ], $pseudo_selector, 1 ); + $nodes[] = array( 'path' => array( 'styles', 'blocks', $name, 'elements', $element ), - 'selector' => $selectors[ $name ]['elements'][ $element ] . $pseudo_selector, + 'selector' => $block_selector, ); } } From a8e7c20b02bd352300fac08c2c01926dda044346 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 11:39:02 +0200 Subject: [PATCH 15/30] Theme_JSON: Use existing append_to_selector for pseudo elements #43167 Co-authored-by: George Mamadashvili --- src/wp-includes/class-wp-theme-json.php | 47 +++++++++++-------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index d19892f45f2dd..88506d8300d0f 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -595,26 +595,27 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n } /** - * This converts selectors like '.wp-element-button, .wp-block-button__link' - * to an array, so that the block selector is added to both parts of the selector. + * Function that appends a sub-selector to a existing one. + * + * Given the compounded $selector "h1, h2, h3" + * and the $to_append selector ".some-class" the result will be + * "h1.some-class, h2.some-class, h3.some-class". * - * @param string $element The string with all the element's selectors. - * @param string $selector The string we want to append to the selectors. - * @param string $position The position we wand to append the selector in. - * @return string element selector. + * @since 5.8.0 + * @since 6.1.0 Added append position. + * + * @param string $selector Original selector. + * @param string $to_append Selector to append. + * @param string $position A position sub-selector should be appended. Default: 'right'. + * @return string */ - private static function appendToSelector( $element, $selector, $position = 0 ) { - $element_selector = array(); - $el_selectors = explode( ',', $element ); - foreach ( $el_selectors as $el_selector_item ) { - if ( 0 === $position ) { - $element_selector[] = $selector . $el_selector_item; - } else { - $element_selector[] = $el_selector_item . $selector; - } + protected static function append_to_selector( $selector, $to_append, $position = 'right' ) { + $new_selectors = array(); + $selectors = explode( ',', $selector ); + foreach ( $selectors as $sel ) { + $new_selectors[] = 'right' === $position ? $sel . $to_append : $to_append . $sel; } - $element_selector = implode( ',', $element_selector ); - return $element_selector; + return implode( ',', $new_selectors ); } /** @@ -683,7 +684,7 @@ protected static function get_blocks_metadata() { $element_selector = array( $el_selector ); break; } - $element_selector = static::appendToSelector( $el_selector, $selector . ' ', 0 ); + $element_selector = static::append_to_selector( $el_selector, $selector . ' ', 'left' ); } static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = $element_selector; } @@ -1593,11 +1594,9 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) { - $element_selector = array(); - $element_selector = static::appendToSelector( static::ELEMENTS[ $element ], $pseudo_selector, 1 ); $nodes[] = array( 'path' => array( 'styles', 'elements', $element ), - 'selector' => $element_selector, + 'selector' => static::append_to_selector( static::ELEMENTS[ $element ], $pseudo_selector ), ); } } @@ -1673,13 +1672,9 @@ private static function get_block_nodes( $theme_json ) { if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] ) ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) { - - $block_selector = array(); - $block_selector = static::appendToSelector( $selectors[ $name ]['elements'][ $element ], $pseudo_selector, 1 ); - $nodes[] = array( 'path' => array( 'styles', 'blocks', $name, 'elements', $element ), - 'selector' => $block_selector, + 'selector' => static::append_to_selector( $selectors[ $name ]['elements'][ $element ], $pseudo_selector ), ); } } From 9a531f776609eaf915c84a1118788da59e7d5849 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 11:40:14 +0200 Subject: [PATCH 16/30] formatting --- src/wp-includes/class-wp-theme-json.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 88506d8300d0f..51ad4e18fa1f5 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -349,7 +349,7 @@ class WP_Theme_JSON { * Note: this will effect both top level and block level elements. */ const VALID_ELEMENT_PSEUDO_SELECTORS = array( - 'link' => array( ':hover', ':focus', ':active', ':visited' ), + 'link' => array( ':hover', ':focus', ':active', ':visited' ), 'button' => array( ':hover', ':focus', ':active', ':visited' ), ); @@ -376,7 +376,7 @@ class WP_Theme_JSON { ); const __EXPERIMENTAL_ELEMENT_CLASS_NAMES = array( - 'button' => 'wp-element-button', + 'button' => 'wp-element-button', 'caption' => 'wp-element-caption', ); From 2be4b953eefa5a1a8576714d39f15c37bece0395 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 12:03:42 +0200 Subject: [PATCH 17/30] removed duplicated function --- src/wp-includes/class-wp-theme-json.php | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 51ad4e18fa1f5..d57320918f1d5 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1045,29 +1045,6 @@ static function ( $carry, $element ) { return $selector . '{' . $declaration_block . '}'; } - /** - * Function that appends a sub-selector to a existing one. - * - * Given the compounded $selector "h1, h2, h3" - * and the $to_append selector ".some-class" the result will be - * "h1.some-class, h2.some-class, h3.some-class". - * - * @since 5.8.0 - * - * @param string $selector Original selector. - * @param string $to_append Selector to append. - * @return string - */ - protected static function append_to_selector( $selector, $to_append ) { - $new_selectors = array(); - $selectors = explode( ',', $selector ); - foreach ( $selectors as $sel ) { - $new_selectors[] = $sel . $to_append; - } - - return implode( ',', $new_selectors ); - } - /** * Given a settings array, it returns the generated rulesets * for the preset classes. From c5b8388cc186075389dd38decdc01af92d821450 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 7 Sep 2022 16:49:17 +0200 Subject: [PATCH 18/30] moved gs function to correct file --- .../get-global-styles-and-settings.php | 23 ------------------- .../global-styles-and-settings.php | 20 ++++++++++++++++ src/wp-settings.php | 1 - 3 files changed, 20 insertions(+), 24 deletions(-) delete mode 100644 src/wp-includes/get-global-styles-and-settings.php diff --git a/src/wp-includes/get-global-styles-and-settings.php b/src/wp-includes/get-global-styles-and-settings.php deleted file mode 100644 index 473765308ff53..0000000000000 --- a/src/wp-includes/get-global-styles-and-settings.php +++ /dev/null @@ -1,23 +0,0 @@ -get_styles_block_nodes(); - foreach ( $block_nodes as $metadata ) { - $block_css = $tree->get_styles_for_block( $metadata ); - $block_name = str_replace( 'core/', '', $metadata['name'] ); - // These block styles are added on block_render. - // This hooks inline CSS to them so that they are loaded conditionally - // based on whether or not the block is used on the page. - wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); - } -} diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index efc2edcaaa354..3580babb8f089 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -192,3 +192,23 @@ function wp_get_global_styles_svg_filters() { return $svgs; } + +/** + * Adds global style rules to the inline style for each block. + * + * @since 6.1.0 + * + */ +function wp_add_global_styles_for_blocks() { + $tree = WP_Theme_JSON_Resolver::get_merged_data(); + // TODO some nodes dont have a name... + $block_nodes = $tree->get_styles_block_nodes(); + foreach ( $block_nodes as $metadata ) { + $block_css = $tree->get_styles_for_block( $metadata ); + $block_name = str_replace( 'core/', '', $metadata['name'] ); + // These block styles are added on block_render. + // This hooks inline CSS to them so that they are loaded conditionally + // based on whether or not the block is used on the page. + wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + } +} diff --git a/src/wp-settings.php b/src/wp-settings.php index 415063db3fa88..8fe16195e0aa0 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -170,7 +170,6 @@ require ABSPATH . WPINC . '/query.php'; require ABSPATH . WPINC . '/class-wp-date-query.php'; require ABSPATH . WPINC . '/theme.php'; -require ABSPATH . WPINC . '/get-global-styles-and-settings.php'; require ABSPATH . WPINC . '/class-wp-theme.php'; require ABSPATH . WPINC . '/class-wp-theme-json-schema.php'; require ABSPATH . WPINC . '/class-wp-theme-json.php'; From 12b386ca91276238d0fc69614ad9a42a3a5cb8ed Mon Sep 17 00:00:00 2001 From: Matias Benedetto Date: Thu, 9 Jun 2022 10:26:34 -0300 Subject: [PATCH 19/30] Fix CSS Selectors rendered by theme.json duotone/filter settings for blocks on public pages (#41335) * Adding the code existing in a previous version of this file, inside this loop: https://github.com/WordPress/gutenberg/blob/9c1c67bba4ba0dc7b241639719c567a364a8ea05/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php#L320 * Avoid repeating code * linting --- src/wp-includes/class-wp-theme-json.php | 90 ++++++++++++------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index d57320918f1d5..721ad83ca6a94 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -883,54 +883,7 @@ protected function get_block_classes( $style_nodes ) { if ( null === $metadata['selector'] ) { continue; } - - $node = _wp_array_get( $this->theme_json, $metadata['path'], array() ); - $selector = $metadata['selector']; - $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); - $declarations = static::compute_style_properties( $node, $settings ); - - // 1. Separate the ones who use the general selector - // and the ones who use the duotone selector. - $declarations_duotone = array(); - foreach ( $declarations as $index => $declaration ) { - if ( 'filter' === $declaration['name'] ) { - unset( $declarations[ $index ] ); - $declarations_duotone[] = $declaration; - } - } - - /* - * Reset default browser margin on the root body element. - * This is set on the root selector **before** generating the ruleset - * from the `theme.json`. This is to ensure that if the `theme.json` declares - * `margin` in its `spacing` declaration for the `body` element then these - * user-generated values take precedence in the CSS cascade. - * @link https://github.com/WordPress/gutenberg/issues/36147. - */ - if ( static::ROOT_BLOCK_SELECTOR === $selector ) { - $block_rules .= 'body { margin: 0; }'; - } - - // 2. Generate the rules that use the general selector. - $block_rules .= static::to_ruleset( $selector, $declarations ); - - // 3. Generate the rules that use the duotone selector. - if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) { - $selector_duotone = static::scope_selector( $metadata['selector'], $metadata['duotone'] ); - $block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone ); - } - - if ( static::ROOT_BLOCK_SELECTOR === $selector ) { - $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; - $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; - $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - - $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; - if ( $has_block_gap_support ) { - $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; - $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; - } - } + $block_rules .= static::get_styles_for_block( $metadata ); } return $block_rules; @@ -1711,8 +1664,49 @@ function( $pseudo_selector ) use ( $selector ) { $block_rules = ''; + // 1. Separate the ones who use the general selector + // and the ones who use the duotone selector. + $declarations_duotone = array(); + foreach ( $declarations as $index => $declaration ) { + if ( 'filter' === $declaration['name'] ) { + unset( $declarations[ $index ] ); + $declarations_duotone[] = $declaration; + } + } + + /* + * Reset default browser margin on the root body element. + * This is set on the root selector **before** generating the ruleset + * from the `theme.json`. This is to ensure that if the `theme.json` declares + * `margin` in its `spacing` declaration for the `body` element then these + * user-generated values take precedence in the CSS cascade. + * @link https://github.com/WordPress/gutenberg/issues/36147. + */ + if ( static::ROOT_BLOCK_SELECTOR === $selector ) { + $block_rules .= 'body { margin: 0; }'; + } + + // 2. Generate and append the rules that use the general selector. $block_rules .= static::to_ruleset( $selector, $declarations ); + // 3. Generate and append the rules that use the duotone selector. + if ( isset( $block_metadata['duotone'] ) && ! empty( $declarations_duotone ) ) { + $selector_duotone = static::scope_selector( $block_metadata['selector'], $block_metadata['duotone'] ); + $block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone ); + } + + if ( static::ROOT_BLOCK_SELECTOR === $selector ) { + $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; + $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; + $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; + + $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; + if ( $has_block_gap_support ) { + $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; + $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; + } + } + return $block_rules; } From 7ce9e7907044af57368ba4b7ad0e5044ea11f4eb Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 8 Sep 2022 11:56:48 +0200 Subject: [PATCH 20/30] Block styles: Account for style block nodes that have no name (#41446) Co-authored-by: Glen Davies Co-authored-by: Ben Dwyer --- .../global-styles-and-settings.php | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index 3580babb8f089..1762678686b31 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -200,15 +200,36 @@ function wp_get_global_styles_svg_filters() { * */ function wp_add_global_styles_for_blocks() { - $tree = WP_Theme_JSON_Resolver::get_merged_data(); - // TODO some nodes dont have a name... + $tree = WP_Theme_JSON_Resolver::get_merged_data(); $block_nodes = $tree->get_styles_block_nodes(); foreach ( $block_nodes as $metadata ) { - $block_css = $tree->get_styles_for_block( $metadata ); - $block_name = str_replace( 'core/', '', $metadata['name'] ); - // These block styles are added on block_render. - // This hooks inline CSS to them so that they are loaded conditionally - // based on whether or not the block is used on the page. - wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + $block_css = $tree->get_styles_for_block( $metadata ); + + if ( isset( $metadata['name'] ) ) { + $block_name = str_replace( 'core/', '', $metadata['name'] ); + // These block styles are added on block_render. + // This hooks inline CSS to them so that they are loaded conditionally + // based on whether or not the block is used on the page. + wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + } + + // The likes of block element styles from theme.json do not have $metadata['name'] set. + if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) { + $result = array_values( + array_filter( + $metadata['path'], + function ( $item ) { + if ( strpos( $item, 'core/' ) !== false ) { + return true; + } + return false; + } + ) + ); + if ( isset( $result[0] ) ) { + $block_name = str_replace( 'core/', '', $result[0] ); + wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); + } + } } } From a7283ec637d3805e719279152e295751af9983e9 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Fri, 9 Sep 2022 10:10:06 +0200 Subject: [PATCH 21/30] added since comments --- src/wp-includes/class-wp-theme-json.php | 7 ++++++- src/wp-includes/global-styles-and-settings.php | 4 ++-- src/wp-includes/script-loader.php | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 721ad83ca6a94..e8f7ab5e22a7a 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -347,6 +347,7 @@ class WP_Theme_JSON { * Define which defines which pseudo selectors are enabled for * which elements. * Note: this will effect both top level and block level elements. + * @since 6.1.0 */ const VALID_ELEMENT_PSEUDO_SELECTORS = array( 'link' => array( ':hover', ':focus', ':active', ':visited' ), @@ -357,7 +358,7 @@ class WP_Theme_JSON { * The valid elements that can be found under styles. * * @since 5.8.0 - * @since 6.1.0 Added `heading`, `button`, and `caption` to the elements. + * @since 6.1.0 Added heading, button and caption elements * @var string[] */ const ELEMENTS = array( @@ -1315,6 +1316,7 @@ protected static function flatten_tree( $tree, $prefix = '', $token = '--' ) { * * @since 5.8.0 * @since 5.9.0 Added the `$settings` and `$properties` parameters. + * @since 6.1.0 Added the `$theme_json` parameter. * * @param array $styles Styles to process. * @param array $settings Theme settings. @@ -1375,6 +1377,7 @@ protected static function compute_style_properties( $styles, $settings = array() * * @since 5.8.0 * @since 5.9.0 Added support for values of array type, which are returned as is. + * @since 6.1.0 Added the `$theme_json` parameter. * * @param array $styles Styles subtree. * @param array $path Which property to process. @@ -1619,6 +1622,8 @@ private static function get_block_nodes( $theme_json ) { /** * Gets the CSS rules for a particular block from theme.json. * + * @since 6.1.0 + * * @param array $block_metadata Meta data about the block to get styles for. * * @return array Styles for the block. diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index 1762678686b31..a7e58353ebc1e 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -195,9 +195,9 @@ function wp_get_global_styles_svg_filters() { /** * Adds global style rules to the inline style for each block. - * + * * @since 6.1.0 - * + * */ function wp_add_global_styles_for_blocks() { $tree = WP_Theme_JSON_Resolver::get_merged_data(); diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 31c18d8b6247b..f0d47cb85d0e6 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2361,7 +2361,7 @@ function wp_common_block_scripts_and_styles() { * This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are loading separate assets, * without making the class aware of that detail. * - * @since 6.1 + * @since 6.1.0 * * @param array $nodes The nodes to filter. * @return array A filtered array of style nodes. From c4c6059a685a770430778f3e1733759635b4acd1 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Fri, 9 Sep 2022 10:51:23 +0200 Subject: [PATCH 22/30] Styles API: Fixed selectors for nested elements #43988 --- src/wp-includes/class-wp-theme-json.php | 4 ++-- tests/phpunit/tests/theme/wpThemeJson.php | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index e8f7ab5e22a7a..8493326cd1f75 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -685,9 +685,9 @@ protected static function get_blocks_metadata() { $element_selector = array( $el_selector ); break; } - $element_selector = static::append_to_selector( $el_selector, $selector . ' ', 'left' ); + $element_selector[] = static::append_to_selector( $el_selector, $selector . ' ', 'left' ); } - static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = $element_selector; + static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector ); } } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 27f355149d933..c20628c36d6cd 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -458,9 +458,6 @@ public function test_get_stylesheet() { ), ), ), - 'spacing' => array( - 'blockGap' => false, - ), 'misc' => 'value', 'blocks' => array( 'core/group' => array( @@ -553,7 +550,7 @@ public function test_get_stylesheet() { ); $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; - $styles = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}'; + $styles = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}'; $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; $all = $variables . $styles . $presets; $this->assertEquals( $all, $theme_json->get_stylesheet() ); From 0015d99e9152370057ebf453c04e0a56ba5fabc4 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Fri, 9 Sep 2022 17:56:22 +0300 Subject: [PATCH 23/30] Use `array_key_exists()` for pseudo selectors --- src/wp-includes/class-wp-theme-json.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 8493326cd1f75..d7ee96d112dcd 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1523,7 +1523,7 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { ); // Handle any pseudo selectors for the element. - if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] ) ) { + if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) { @@ -1602,7 +1602,7 @@ private static function get_block_nodes( $theme_json ) { ); // Handle any pseudo selectors for the element. - if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] ) ) { + if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) { if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) { $nodes[] = array( @@ -1643,7 +1643,11 @@ public function get_styles_for_block( $block_metadata ) { $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null; - $element_pseudo_allowed = isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) ? static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] : array(); + $element_pseudo_allowed = array(); + + if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { + $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ]; + } // Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover"). // This also resets the array keys. @@ -1661,7 +1665,10 @@ function( $pseudo_selector ) use ( $selector ) { // If the current selector is a pseudo selector that's defined in the allow list for the current // element then compute the style properties for it. // Otherwise just compute the styles for the default selector as normal. - if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) && isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) ) { + if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) && + array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) + && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) + ) { $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json ); } else { $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json ); @@ -2044,8 +2051,7 @@ public static function remove_insecure_properties( $theme_json ) { // $output is stripped of pseudo selectors. Readd and process them // for insecure styles here. - if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] ) ) { - + if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] as $pseudo_selector ) { if ( isset( $input[ $pseudo_selector ] ) ) { $output[ $pseudo_selector ] = static::remove_insecure_styles( $input[ $pseudo_selector ] ); From b0d29f701e7e2a80e26862902ce81177b3644292 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 10 Sep 2022 01:18:50 +0300 Subject: [PATCH 24/30] Update documentation per the doc standards --- src/wp-includes/class-wp-theme-json.php | 121 ++++++++++++------ .../global-styles-and-settings.php | 9 +- src/wp-includes/script-loader.php | 11 +- tests/phpunit/tests/theme/wpThemeJson.php | 69 +++++++--- 4 files changed, 140 insertions(+), 70 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index d7ee96d112dcd..dad24e41de972 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -344,9 +344,9 @@ class WP_Theme_JSON { ); /** - * Define which defines which pseudo selectors are enabled for - * which elements. - * Note: this will effect both top level and block level elements. + * Defines which pseudo selectors are enabled for which elements. + * Note: this will effect both top-level and block-level elements. + * * @since 6.1.0 */ const VALID_ELEMENT_PSEUDO_SELECTORS = array( @@ -358,11 +358,11 @@ class WP_Theme_JSON { * The valid elements that can be found under styles. * * @since 5.8.0 - * @since 6.1.0 Added heading, button and caption elements + * @since 6.1.0 Added `heading`, `button`. and `caption` elements. * @var string[] */ const ELEMENTS = array( - 'link' => 'a:where(:not(.wp-element-button))', // The where is needed to lower the specificity. + 'link' => 'a:where(:not(.wp-element-button))', // The `where` is needed to lower the specificity. 'heading' => 'h1, h2, h3, h4, h5, h6', 'h1' => 'h1', 'h2' => 'h2', @@ -382,16 +382,21 @@ class WP_Theme_JSON { ); /** - * Given an element name, returns a class name. + * Returns a class name by an element name. * - * @param string $element The name of the element. + * @since 6.1.0 * + * @param string $element The name of the element. * @return string The name of the class. - * - * @since 6.1.0 */ public static function get_element_class_name( $element ) { - return array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ? static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ] : ''; + $class_name = ''; + + if ( array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ) { + $class_name = static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ]; + } + + return $class_name; } /** @@ -527,9 +532,11 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n // Preserve only the top most level keys. $output = array_intersect_key( $input, array_flip( static::VALID_TOP_LEVEL_KEYS ) ); - // Remove any rules that are annotated as "top" in VALID_STYLES constant. - // Some styles are only meant to be available at the top-level (e.g.: blockGap), - // hence, the schema for blocks & elements should not have them. + /* + * Remove any rules that are annotated as "top" in VALID_STYLES constant. + * Some styles are only meant to be available at the top-level (e.g.: blockGap), + * hence, the schema for blocks & elements should not have them. + */ $styles_non_top_level = static::VALID_STYLES; foreach ( array_keys( $styles_non_top_level ) as $section ) { foreach ( array_keys( $styles_non_top_level[ $section ] ) as $prop ) { @@ -543,11 +550,13 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n $schema = array(); $schema_styles_elements = array(); - // Set allowed element pseudo selectors based on per element allow list. - // Target data structure in schema: - // e.g. - // - top level elements: `$schema['styles']['elements']['link'][':hover']`. - // - block level elements: `$schema['styles']['blocks']['core/button']['elements']['link'][':hover']`. + /* + * Set allowed element pseudo selectors based on per element allow list. + * Target data structure in schema: + * e.g. + * - top level elements: `$schema['styles']['elements']['link'][':hover']`. + * - block level elements: `$schema['styles']['blocks']['core/button']['elements']['link'][':hover']`. + */ foreach ( $valid_element_names as $element ) { $schema_styles_elements[ $element ] = $styles_non_top_level; @@ -596,7 +605,7 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n } /** - * Function that appends a sub-selector to a existing one. + * Appends a sub-selector to an existing one. * * Given the compounded $selector "h1, h2, h3" * and the $to_append selector ".some-class" the result will be @@ -607,7 +616,7 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n * * @param string $selector Original selector. * @param string $to_append Selector to append. - * @param string $position A position sub-selector should be appended. Default: 'right'. + * @param string $position A position sub-selector should be appended. Default 'right'. * @return string */ protected static function append_to_selector( $selector, $to_append, $position = 'right' ) { @@ -1387,9 +1396,11 @@ protected static function compute_style_properties( $styles, $settings = array() protected static function get_property_value( $styles, $path, $theme_json = null ) { $value = _wp_array_get( $styles, $path, '' ); - // This converts references to a path to the value at that path - // where the values is an array with a "ref" key, pointing to a path. - // For example: { "ref": "style.color.background" } => "#fff". + /* + * This converts references to a path to the value at that path + * where the values is an array with a "ref" key, pointing to a path. + * For example: { "ref": "style.color.background" } => "#fff". + */ if ( is_array( $value ) && array_key_exists( 'ref', $value ) ) { $value_path = explode( '.', $value['ref'] ); $ref_value = _wp_array_get( $theme_json, $value_path ); @@ -1401,7 +1412,11 @@ protected static function get_property_value( $styles, $path, $theme_json = null if ( is_array( $ref_value ) && array_key_exists( 'ref', $ref_value ) ) { $path_string = json_encode( $path ); $ref_value_string = json_encode( $ref_value ); - _doing_it_wrong( 'get_property_value', "Your theme.json file uses a dynamic value (${ref_value_string}) for the path at ${path_string}. However, the value at ${path_string} is also a dynamic value (pointing to ${ref_value['ref']}) and pointing to another dynamic value is not supported. Please update ${path_string} to point directly to ${ref_value['ref']}.", '6.1.0' ); + _doing_it_wrong( + 'get_property_value', + "Your theme.json file uses a dynamic value (${ref_value_string}) for the path at ${path_string}. However, the value at ${path_string} is also a dynamic value (pointing to ${ref_value['ref']}) and pointing to another dynamic value is not supported. Please update ${path_string} to point directly to ${ref_value['ref']}.", + '6.1.0' + ); } } @@ -1544,13 +1559,23 @@ protected static function get_style_nodes( $theme_json, $selectors = array() ) { $nodes = array_merge( $nodes, static::get_block_nodes( $theme_json ) ); - // This filter allows us to modify the output of WP_Theme_JSON so that we can do things like loading block CSS independently. + /** + * Filters the list of style nodes with metadata. + * + * This allows for things like loading block CSS independently. + * + * @since 6.1.0 + * + * @param array $nodes Style nodes with metadata. + */ return apply_filters( 'get_style_nodes', $nodes ); } /** * A public helper to get the block nodes from a theme.json file. * + * @since 6.1.0 + * * @return array The block nodes in theme.json. */ public function get_styles_block_nodes() { @@ -1560,8 +1585,9 @@ public function get_styles_block_nodes() { /** * An internal method to get the block nodes from a theme.json file. * - * @param array $theme_json The theme.json converted to an array. + * @since 6.1.0 * + * @param array $theme_json The theme.json converted to an array. * @return array The block nodes in theme.json. */ private static function get_block_nodes( $theme_json ) { @@ -1625,7 +1651,6 @@ private static function get_block_nodes( $theme_json ) { * @since 6.1.0 * * @param array $block_metadata Meta data about the block to get styles for. - * * @return array Styles for the block. */ public function get_styles_for_block( $block_metadata ) { @@ -1635,10 +1660,12 @@ public function get_styles_for_block( $block_metadata ) { $selector = $block_metadata['selector']; $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); - // Get a reference to element name from path. - // $block_metadata['path'] = array('styles','elements','link'); - // Make sure that $block_metadata['path'] describes an element node, like ['styles', 'element', 'link']. - // Skip non-element paths like just ['styles']. + /* + * Get a reference to element name from path. + * $block_metadata['path'] = array( 'styles','elements','link' ); + * Make sure that $block_metadata['path'] describes an element node, like [ 'styles', 'element', 'link' ]. + * Skip non-element paths like just ['styles']. + */ $is_processing_element = in_array( 'elements', $block_metadata['path'], true ); $current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null; @@ -1649,8 +1676,10 @@ public function get_styles_for_block( $block_metadata ) { $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ]; } - // Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover"). - // This also resets the array keys. + /* + * Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover"). + * This also resets the array keys. + */ $pseudo_matches = array_values( array_filter( $element_pseudo_allowed, @@ -1662,9 +1691,11 @@ function( $pseudo_selector ) use ( $selector ) { $pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null; - // If the current selector is a pseudo selector that's defined in the allow list for the current - // element then compute the style properties for it. - // Otherwise just compute the styles for the default selector as normal. + /* + * If the current selector is a pseudo selector that's defined in the allow list for the current + * element then compute the style properties for it. + * Otherwise just compute the styles for the default selector as normal. + */ if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) && array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) @@ -1676,8 +1707,10 @@ function( $pseudo_selector ) use ( $selector ) { $block_rules = ''; - // 1. Separate the ones who use the general selector - // and the ones who use the duotone selector. + /* + * 1. Separate the ones who use the general selector + * and the ones who use the duotone selector. + */ $declarations_duotone = array(); foreach ( $declarations as $index => $declaration ) { if ( 'filter' === $declaration['name'] ) { @@ -2045,12 +2078,16 @@ public static function remove_insecure_properties( $theme_json ) { $output = static::remove_insecure_styles( $input ); - // Get a reference to element name from path. - // $metadata['path'] = array('styles','elements','link');. + /* + * Get a reference to element name from path. + * $metadata['path'] = array( 'styles', 'elements', 'link' ); + */ $current_element = $metadata['path'][ count( $metadata['path'] ) - 1 ]; - // $output is stripped of pseudo selectors. Readd and process them - // for insecure styles here. + /* + * $output is stripped of pseudo selectors. Re-add and process them + * or insecure styles here. + */ if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) { foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] as $pseudo_selector ) { if ( isset( $input[ $pseudo_selector ] ) ) { diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index a7e58353ebc1e..2e642cc2b1e05 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -197,7 +197,6 @@ function wp_get_global_styles_svg_filters() { * Adds global style rules to the inline style for each block. * * @since 6.1.0 - * */ function wp_add_global_styles_for_blocks() { $tree = WP_Theme_JSON_Resolver::get_merged_data(); @@ -207,9 +206,11 @@ function wp_add_global_styles_for_blocks() { if ( isset( $metadata['name'] ) ) { $block_name = str_replace( 'core/', '', $metadata['name'] ); - // These block styles are added on block_render. - // This hooks inline CSS to them so that they are loaded conditionally - // based on whether or not the block is used on the page. + /* + * These block styles are added on block_render. + * This hooks inline CSS to them so that they are loaded conditionally + * based on whether or not the block is used on the page. + */ wp_add_inline_style( 'wp-block-' . $block_name, $block_css ); } diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index f0d47cb85d0e6..122bd19d6a932 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2354,12 +2354,13 @@ function wp_common_block_scripts_and_styles() { } /** - * This applies a filter to the list of style nodes that comes from `get_style_nodes` in WP_Theme_JSON. + * Applies a filter to the list of style nodes that comes from WP_Theme_JSON::get_style_nodes(). + * * This particular filter removes all of the blocks from the array. * * We want WP_Theme_JSON to be ignorant of the implementation details of how the CSS is being used. - * This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are loading separate assets, - * without making the class aware of that detail. + * This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are + * loading separate assets, without making the class aware of that detail. * * @since 6.1.0 * @@ -2400,13 +2401,13 @@ function wp_enqueue_global_styles() { return; } - /** + /* * If we are loading CSS for each block separately, then we can load the theme.json CSS conditionally. * This removes the CSS from the global-styles stylesheet and adds it to the inline CSS for each block. */ if ( $separate_assets ) { add_filter( 'get_style_nodes', 'filter_out_block_nodes' ); - // add each block as an inline css. + // Add each block as an inline css. wp_add_global_styles_for_blocks(); } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index c20628c36d6cd..a681de61124b9 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -722,7 +722,10 @@ public function test_get_stylesheet_preset_values_are_marked_as_important() { ); } - function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { + /** + * @ticket 56467 + */ + public function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { $theme_json = new WP_Theme_JSON( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -765,7 +768,10 @@ function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors() { $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } - function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_property() { + /** + * @ticket 56467 + */ + public function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_property() { $theme_json = new WP_Theme_JSON( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -804,7 +810,10 @@ function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given_proper $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } - function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements() { + /** + * @ticket 56467 + */ + public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements() { $theme_json = new WP_Theme_JSON( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -843,7 +852,10 @@ function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_element $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } - function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { + /** + * @ticket 56467 + */ + public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { $theme_json = new WP_Theme_JSON( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -883,7 +895,10 @@ function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { $this->assertStringNotContainsString( 'a:levitate{', $theme_json->get_stylesheet( array( 'styles' ) ) ); } - function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseudo_selectors() { + /** + * @ticket 56467 + */ + public function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseudo_selectors() { $theme_json = new WP_Theme_JSON( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -930,7 +945,10 @@ function test_get_stylesheet_handles_priority_of_elements_vs_block_elements_pseu $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } - function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_selectors() { + /** + * @ticket 56467 + */ + public function test_get_stylesheet_handles_whitelisted_block_level_element_pseudo_selectors() { $theme_json = new WP_Theme_JSON( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -2338,7 +2356,10 @@ public function test_remove_insecure_properties_applies_safe_styles() { $this->assertEqualSetsWithIndex( $expected, $actual ); } - function test_remove_invalid_element_pseudo_selectors() { + /** + * @ticket 56467 + */ + public function test_remove_invalid_element_pseudo_selectors() { $actual = WP_Theme_JSON::remove_insecure_properties( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -2921,14 +2942,20 @@ function test_export_data_sets_appearance_tools() { $this->assertEqualSetsWithIndex( $expected, $actual ); } - function test_get_element_class_name_button() { + /** + * @ticket 56467 + */ + public function test_get_element_class_name_button() { $expected = 'wp-element-button'; $actual = WP_Theme_JSON::get_element_class_name( 'button' ); $this->assertEquals( $expected, $actual ); } - function test_get_element_class_name_invalid() { + /** + * @ticket 56467 + */ + public function test_get_element_class_name_invalid() { $expected = ''; $actual = WP_Theme_JSON::get_element_class_name( 'unknown-element' ); @@ -2936,10 +2963,12 @@ function test_get_element_class_name_invalid() { } /** - * Testing that dynamic properties in theme.json return the value they refrence, e.g. - * array( 'ref' => 'styles.color.background' ) => "#ffffff". + * Testing that dynamic properties in theme.json return the value they refrence, + * e.g. array( 'ref' => 'styles.color.background' ) => "#ffffff". + * + * @ticket 56467 */ - function test_get_property_value_valid() { + public function test_get_property_value_valid() { $theme_json = new WP_Theme_JSON( array( 'version' => 2, @@ -2965,10 +2994,10 @@ function test_get_property_value_valid() { } /** - * Testing that dynamic properties in theme.json that - * refer to other dynamic properties in a loop - * then they should be left untouched. + * Testing that dynamic properties in theme.json that refer to other dynamic properties in a loop + * should be left untouched. * + * @ticket 56467 * @expectedIncorrectUsage get_property_value */ function test_get_property_value_loop() { @@ -2997,9 +3026,10 @@ function test_get_property_value_loop() { } /** - * Testing that dynamic properties in theme.json that - * refer to other dynamic properties then they should be left unprocessed. + * Testing that dynamic properties in theme.json that refer to other dynamic properties + * should be left unprocessed. * + * @ticket 56467 * @expectedIncorrectUsage get_property_value */ function test_get_property_value_recursion() { @@ -3028,9 +3058,10 @@ function test_get_property_value_recursion() { } /** - * Testing that dynamic properties in theme.json that - * refer to themselves then they should be left unprocessed. + * Testing that dynamic properties in theme.json that refer to themselves + * should be left unprocessed. * + * @ticket 56467 * @expectedIncorrectUsage get_property_value */ function test_get_property_value_self() { From 27d6cf4f2be3272cc0e26ba81178efc658345cc3 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 10 Sep 2022 01:21:54 +0300 Subject: [PATCH 25/30] Use `assertSame()` in unit tests --- tests/phpunit/tests/theme/wpThemeJson.php | 70 +++++++++++------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index a681de61124b9..98d482c03bb36 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -367,8 +367,8 @@ public function test_get_stylesheet_support_for_shorthand_and_longhand_values() ); $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-block-group{border-radius: 10px;margin: 1em;padding: 24px;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;padding-top: 15px;}'; - $this->assertEquals( $styles, $theme_json->get_stylesheet() ); - $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $styles, $theme_json->get_stylesheet() ); + $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -399,8 +399,8 @@ public function test_get_stylesheet_skips_disabled_protected_properties() { ); $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -424,8 +424,8 @@ public function test_get_stylesheet_renders_enabled_protected_properties() { ); $expected = 'body { margin: 0; }body{--wp--style--block-gap: 1em;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -553,10 +553,10 @@ public function test_get_stylesheet() { $styles = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}'; $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; $all = $variables . $styles . $presets; - $this->assertEquals( $all, $theme_json->get_stylesheet() ); - $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); - $this->assertEquals( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) ); - $this->assertEquals( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) ); + $this->assertSame( $all, $theme_json->get_stylesheet() ); + $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) ); + $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) ); } /** @@ -584,7 +584,7 @@ public function test_get_stylesheet_preset_classes_work_with_compounded_selector ) ); - $this->assertEquals( + $this->assertSame( 'h1.has-white-color,h2.has-white-color,h3.has-white-color,h4.has-white-color,h5.has-white-color,h6.has-white-color{color: var(--wp--preset--color--white) !important;}h1.has-white-background-color,h2.has-white-background-color,h3.has-white-background-color,h4.has-white-background-color,h5.has-white-background-color,h6.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}h1.has-white-border-color,h2.has-white-border-color,h3.has-white-border-color,h4.has-white-border-color,h5.has-white-border-color,h6.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}', $theme_json->get_stylesheet( array( 'presets' ) ) ); @@ -628,10 +628,10 @@ public function test_get_stylesheet_preset_rules_come_after_block_rules() { $presets = '.wp-block-group.has-grey-color{color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.wp-block-group.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}'; $variables = '.wp-block-group{--wp--preset--color--grey: grey;}'; $all = $variables . $styles . $presets; - $this->assertEquals( $all, $theme_json->get_stylesheet() ); - $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); - $this->assertEquals( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) ); - $this->assertEquals( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) ); + $this->assertSame( $all, $theme_json->get_stylesheet() ); + $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) ); + $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) ); } /** @@ -669,11 +669,11 @@ public function test_get_stylesheet_generates_proper_classes_and_css_vars_from_s ) ); - $this->assertEquals( + $this->assertSame( '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-dark-grey-color{color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-color{color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-color{color: var(--wp--preset--color--white-2-black) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-dark-grey-background-color{background-color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-background-color{background-color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-background-color{background-color: var(--wp--preset--color--white-2-black) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-dark-grey-border-color{border-color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-border-color{border-color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-border-color{border-color: var(--wp--preset--color--white-2-black) !important;}', $theme_json->get_stylesheet( array( 'presets' ) ) ); - $this->assertEquals( + $this->assertSame( 'body{--wp--preset--color--grey: grey;--wp--preset--color--dark-grey: grey;--wp--preset--color--light-grey: grey;--wp--preset--color--white-2-black: grey;--wp--custom--white-2-black: value;}', $theme_json->get_stylesheet( array( 'variables' ) ) ); @@ -716,7 +716,7 @@ public function test_get_stylesheet_preset_values_are_marked_as_important() { 'default' ); - $this->assertEquals( + $this->assertSame( 'body{--wp--preset--color--grey: grey;}body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }p{background-color: blue;color: red;font-size: 12px;line-height: 1.3;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}', $theme_json->get_stylesheet() ); @@ -764,8 +764,8 @@ public function test_get_stylesheet_handles_whitelisted_element_pseudo_selectors $expected = $base_styles . $element_styles; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -806,8 +806,8 @@ public function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given $expected = $base_styles . $element_styles; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -848,8 +848,8 @@ public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_ $expected = $base_styles . $element_styles; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -890,8 +890,8 @@ public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() { $expected = $base_styles . $element_styles; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); $this->assertStringNotContainsString( 'a:levitate{', $theme_json->get_stylesheet( array( 'styles' ) ) ); } @@ -941,8 +941,8 @@ public function test_get_stylesheet_handles_priority_of_elements_vs_block_elemen $expected = $base_styles . $element_styles; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -991,8 +991,8 @@ public function test_get_stylesheet_handles_whitelisted_block_level_element_pseu $expected = $base_styles . $element_styles; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); - $this->assertEquals( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); } /** @@ -2949,7 +2949,7 @@ public function test_get_element_class_name_button() { $expected = 'wp-element-button'; $actual = WP_Theme_JSON::get_element_class_name( 'button' ); - $this->assertEquals( $expected, $actual ); + $this->assertSame( $expected, $actual ); } /** @@ -2959,7 +2959,7 @@ public function test_get_element_class_name_invalid() { $expected = ''; $actual = WP_Theme_JSON::get_element_class_name( 'unknown-element' ); - $this->assertEquals( $expected, $actual ); + $this->assertSame( $expected, $actual ); } /** @@ -2990,7 +2990,7 @@ public function test_get_property_value_valid() { ); $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #000000;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}'; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); } /** @@ -3054,7 +3054,7 @@ function test_get_property_value_recursion() { ); $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}'; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); } /** @@ -3078,7 +3078,7 @@ function test_get_property_value_self() { ); $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; - $this->assertEquals( $expected, $theme_json->get_stylesheet() ); + $this->assertSame( $expected, $theme_json->get_stylesheet() ); } } From b32c3081a193545c9fa52837a7756398fe5820cd Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 10 Sep 2022 01:33:35 +0300 Subject: [PATCH 26/30] Translate the `_doing_it_wrong()` notice --- src/wp-includes/class-wp-theme-json.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index dad24e41de972..78cb03a309853 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1414,7 +1414,14 @@ protected static function get_property_value( $styles, $path, $theme_json = null $ref_value_string = json_encode( $ref_value ); _doing_it_wrong( 'get_property_value', - "Your theme.json file uses a dynamic value (${ref_value_string}) for the path at ${path_string}. However, the value at ${path_string} is also a dynamic value (pointing to ${ref_value['ref']}) and pointing to another dynamic value is not supported. Please update ${path_string} to point directly to ${ref_value['ref']}.", + sprintf( + /* translators: 1: theme.json, 2: Value name, 3: Value path, 4: Another value name. */ + __( 'Your %1$s file uses a dynamic value (%2$s) for the path at %3$s. However, the value at %3$s is also a dynamic value (pointing to %4$s) and pointing to another dynamic value is not supported. Please update %3$s to point directly to %4$s.' ), + 'theme.json', + $ref_value_string, + $path_string, + $ref_value['ref'] + ), '6.1.0' ); } From 42bb46bbc4c33390897dbe73dba1010c5d7bb455 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 10 Sep 2022 01:50:52 +0300 Subject: [PATCH 27/30] Add `wp_` prefix to `filter_out_block_nodes()` --- src/wp-includes/script-loader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 122bd19d6a932..354845fb9d670 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2367,7 +2367,7 @@ function wp_common_block_scripts_and_styles() { * @param array $nodes The nodes to filter. * @return array A filtered array of style nodes. */ -function filter_out_block_nodes( $nodes ) { +function wp_filter_out_block_nodes( $nodes ) { return array_filter( $nodes, function( $node ) { @@ -2406,7 +2406,7 @@ function wp_enqueue_global_styles() { * This removes the CSS from the global-styles stylesheet and adds it to the inline CSS for each block. */ if ( $separate_assets ) { - add_filter( 'get_style_nodes', 'filter_out_block_nodes' ); + add_filter( 'get_style_nodes', 'wp_filter_out_block_nodes' ); // Add each block as an inline css. wp_add_global_styles_for_blocks(); } From 869c2c3deb46bfeaac165718e8dc6b5465750b2e Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 10 Sep 2022 14:51:47 +0300 Subject: [PATCH 28/30] Update a comment for clarity --- src/wp-includes/class-wp-theme-json.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 78cb03a309853..f784d8f866505 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1715,8 +1715,8 @@ function( $pseudo_selector ) use ( $selector ) { $block_rules = ''; /* - * 1. Separate the ones who use the general selector - * and the ones who use the duotone selector. + * 1. Separate the declarations that use the general selector + * from the ones using the duotone selector. */ $declarations_duotone = array(); foreach ( $declarations as $index => $declaration ) { From c46304f6a3b8a572d8df970abb95573698843826 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 10 Sep 2022 15:23:54 +0300 Subject: [PATCH 29/30] Add `public` keyword to test methods --- tests/phpunit/tests/theme/wpThemeJson.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 98d482c03bb36..740ea4a6d7b9c 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -3000,7 +3000,7 @@ public function test_get_property_value_valid() { * @ticket 56467 * @expectedIncorrectUsage get_property_value */ - function test_get_property_value_loop() { + public function test_get_property_value_loop() { $theme_json = new WP_Theme_JSON( array( 'version' => 2, @@ -3032,7 +3032,7 @@ function test_get_property_value_loop() { * @ticket 56467 * @expectedIncorrectUsage get_property_value */ - function test_get_property_value_recursion() { + public function test_get_property_value_recursion() { $theme_json = new WP_Theme_JSON( array( 'version' => 2, @@ -3064,7 +3064,7 @@ function test_get_property_value_recursion() { * @ticket 56467 * @expectedIncorrectUsage get_property_value */ - function test_get_property_value_self() { + public function test_get_property_value_self() { $theme_json = new WP_Theme_JSON( array( 'version' => 2, From a69b3faff32d5ebbd681865a6193b3afb0afd31c Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 10 Sep 2022 15:28:45 +0300 Subject: [PATCH 30/30] Fix typo in pseudo selectors description --- src/wp-includes/class-wp-theme-json.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index f784d8f866505..69a349f970cc7 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -345,7 +345,8 @@ class WP_Theme_JSON { /** * Defines which pseudo selectors are enabled for which elements. - * Note: this will effect both top-level and block-level elements. + * + * Note: this will affect both top-level and block-level elements. * * @since 6.1.0 */