From f8c56825474b66dda373c7693cde46078341cade Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:30:43 +1000 Subject: [PATCH 1/3] Scope feature selectors in prep for custom block style variations in theme json --- lib/class-wp-theme-json-gutenberg.php | 35 ++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 1d3f8feb90e23e..e6e53c5a04ce61 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1200,7 +1200,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' $node['selector'] = static::scope_selector( $options['scope'], $node['selector'] ); } foreach ( $style_nodes as &$node ) { - $node['selector'] = static::scope_selector( $options['scope'], $node['selector'] ); + $node = static::scope_style_node_selectors( $options['scope'], $node ); } unset( $node ); } @@ -4039,4 +4039,37 @@ function ( $matches ) use ( $variation_class ) { return implode( ',', $result ); } + + /** + * Scopes the selectors for a given style node. This includes the primary + * selector, i.e. `$node['selector']`, as well as any custom selectors for + * features and subfeatures, e.g. `$node['selectors']['border']` etc. + * + * @since 6.6.0 + * + * @param string $scope Selector to scope to. + * @param array $node Style node with selectors to scope. + * + * @return array Node with updated selectors. + */ + protected static function scope_style_node_selectors( $scope, $node ) { + $node['selector'] = static::scope_selector( $scope, $node['selector'] ); + + if ( empty( $node['selectors'] ) ) { + return $node; + } + + foreach ( $node['selectors'] as $feature => $selector ) { + if ( is_string( $selector ) ) { + $node['selectors'][ $feature ] = static::scope_selector( $scope, $selector ); + } + if ( is_array( $selector ) ) { + foreach ( $selector as $subfeature => $subfeature_selector ) { + $node['selectors'][ $feature ][ $subfeature ] = static::scope_selector( $scope, $subfeature_selector ); + } + } + } + + return $node; + } } From bb767f79eb4fa31310af9613de6052d354996bd8 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 26 Apr 2024 18:00:50 +1000 Subject: [PATCH 2/3] Add unit test for scoping feature selectors --- phpunit/class-wp-theme-json-test.php | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 1ab2639b5d539e..d1d4da5a6e16ed 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -5357,4 +5357,49 @@ public function data_get_block_style_variation_selector() { ), ); } + + /** + * Tests the correct scoping of selectors for a style node. + */ + public function test_scope_style_node_selectors() { + $theme_json = new ReflectionClass( 'WP_Theme_JSON_Gutenberg' ); + + $func = $theme_json->getMethod( 'scope_style_node_selectors' ); + $func->setAccessible( true ); + + $node = array( + 'name' => 'core/image', + 'path' => array( 'styles', 'blocks', 'core/image' ), + 'selector' => '.wp-block-image', + 'selectors' => array( + 'root' => '.wp-block-image', + 'border' => '.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder', + 'typography' => array( + 'textDecoration' => '.wp-block-image caption', + ), + 'filter' => array( + 'duotone' => '.wp-block-image img, .wp-block-image .components-placeholder', + ), + ), + ); + + $actual = $func->invoke( null, '.custom-scope', $node ); + $expected = array( + 'name' => 'core/image', + 'path' => array( 'styles', 'blocks', 'core/image' ), + 'selector' => '.custom-scope .wp-block-image', + 'selectors' => array( + 'root' => '.custom-scope .wp-block-image', + 'border' => '.custom-scope .wp-block-image img, .custom-scope .wp-block-image .wp-block-image__crop-area, .custom-scope .wp-block-image .components-placeholder', + 'typography' => array( + 'textDecoration' => '.custom-scope .wp-block-image caption', + ), + 'filter' => array( + 'duotone' => '.custom-scope .wp-block-image img, .custom-scope .wp-block-image .components-placeholder', + ), + ), + ); + + $this->assertEquals( $expected, $actual ); + } } From fd5a3c78cee360896cf1551597994e25617fdf8d Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 26 Apr 2024 18:01:08 +1000 Subject: [PATCH 3/3] Relocate scope_style_node_selectors beside scope_selector --- lib/class-wp-theme-json-gutenberg.php | 66 +++++++++++++-------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index e6e53c5a04ce61..78a5815d6726c1 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1856,6 +1856,39 @@ public static function scope_selector( $scope, $selector ) { return $result; } + /** + * Scopes the selectors for a given style node. This includes the primary + * selector, i.e. `$node['selector']`, as well as any custom selectors for + * features and subfeatures, e.g. `$node['selectors']['border']` etc. + * + * @since 6.6.0 + * + * @param string $scope Selector to scope to. + * @param array $node Style node with selectors to scope. + * + * @return array Node with updated selectors. + */ + protected static function scope_style_node_selectors( $scope, $node ) { + $node['selector'] = static::scope_selector( $scope, $node['selector'] ); + + if ( empty( $node['selectors'] ) ) { + return $node; + } + + foreach ( $node['selectors'] as $feature => $selector ) { + if ( is_string( $selector ) ) { + $node['selectors'][ $feature ] = static::scope_selector( $scope, $selector ); + } + if ( is_array( $selector ) ) { + foreach ( $selector as $subfeature => $subfeature_selector ) { + $node['selectors'][ $feature ][ $subfeature ] = static::scope_selector( $scope, $subfeature_selector ); + } + } + } + + return $node; + } + /** * Gets preset values keyed by slugs based on settings and metadata. * @@ -4039,37 +4072,4 @@ function ( $matches ) use ( $variation_class ) { return implode( ',', $result ); } - - /** - * Scopes the selectors for a given style node. This includes the primary - * selector, i.e. `$node['selector']`, as well as any custom selectors for - * features and subfeatures, e.g. `$node['selectors']['border']` etc. - * - * @since 6.6.0 - * - * @param string $scope Selector to scope to. - * @param array $node Style node with selectors to scope. - * - * @return array Node with updated selectors. - */ - protected static function scope_style_node_selectors( $scope, $node ) { - $node['selector'] = static::scope_selector( $scope, $node['selector'] ); - - if ( empty( $node['selectors'] ) ) { - return $node; - } - - foreach ( $node['selectors'] as $feature => $selector ) { - if ( is_string( $selector ) ) { - $node['selectors'][ $feature ] = static::scope_selector( $scope, $selector ); - } - if ( is_array( $selector ) ) { - foreach ( $selector as $subfeature => $subfeature_selector ) { - $node['selectors'][ $feature ][ $subfeature ] = static::scope_selector( $scope, $subfeature_selector ); - } - } - } - - return $node; - } }