diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index e8d51c4e0f569..455aeeb1214c3 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -3498,23 +3498,6 @@ public function get_styles_for_block( $block_metadata ) { $element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ]; } - /* - * Check if we're processing a block pseudo-selector. - * $block_metadata['path'] = array( 'styles', 'blocks', 'core/button', ':hover' ); - */ - $is_processing_block_pseudo = false; - $block_pseudo_selector = null; - if ( in_array( 'blocks', $block_metadata['path'], true ) && count( $block_metadata['path'] ) >= 4 ) { - $block_name = static::get_block_name_from_metadata_path( $block_metadata ); // 'core/button' - $last_path_element = $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ]; // ':hover' - - if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ] ) && - in_array( $last_path_element, static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ], true ) ) { - $is_processing_block_pseudo = true; - $block_pseudo_selector = $last_path_element; - } - } - /* * Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover"). * This also resets the array keys. @@ -3544,15 +3527,12 @@ static function ( $pseudo_selector ) use ( $selector ) { && 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, $selector, $use_root_padding ); - } elseif ( $is_processing_block_pseudo ) { - // Process block pseudo-selector styles - // For block pseudo-selectors, we need to get the block data first, then access the pseudo-selector - $block_name = static::get_block_name_from_metadata_path( $block_metadata ); // 'core/button' - $block_data = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $block_name ), array() ); - $pseudo_data = $block_data[ $block_pseudo_selector ] ?? array(); - - $declarations = static::compute_style_properties( $pseudo_data, $settings, null, $this->theme_json, $selector, $use_root_padding ); } else { + /* + * For block pseudo-selector nodes (e.g. ':hover'), $node has already had any + * feature-selector properties (e.g. writingMode) removed by get_feature_declarations_for_node, + * so those properties are not output twice. + */ $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json, $selector, $use_root_padding ); } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 78e1c38f0a03a..dfc09200ec2b4 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -7160,6 +7160,37 @@ public function test_merge_incoming_data_unique_slugs_always_preserved() { $this->assertEqualSetsWithIndex( $expected, $actual ); } + /** + * Tests that when a block with a custom feature selector (e.g. core/button's writingMode + * uses '.wp-block-button' rather than the root '.wp-block-button .wp-block-button__link') + * has pseudo-state styles, the feature selector CSS is scoped to the pseudo-state and not + * output under the block's default-state selector. + */ + public function test_get_stylesheet_pseudo_selector_scopes_feature_selector_css() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/button' => array( + ':hover' => array( + 'typography' => array( + 'writingMode' => 'vertical-rl', + ), + ), + ), + ), + ), + ), + 'default' + ); + + $css = $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ); + + // writing-mode should be scoped to :hover, not the root block selector. + $this->assertSame( ':root :where(.wp-block-button:hover){writing-mode: vertical-rl;}', $css ); + } + /** * Test that block pseudo selectors are processed correctly. */