diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index c20960bd0f9cc..8697ad5fc5a13 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1330,6 +1330,14 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n $schema_styles_blocks = array(); $schema_settings_blocks = array(); + $breakpoint_states = array_keys( $responsive_media_queries ); + + $common_block_settings = static::VALID_SETTINGS; + // `viewport` and `blockVisibility` are global-only settings and cannot be set per block for now. + unset( + $common_block_settings['viewport'], + $common_block_settings['blockVisibility'] + ); /* * Generate a schema for blocks. @@ -1340,21 +1348,27 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n * * As each variation needs both a `blocks` schema and responsive `blocks` schemas * for further nested inner `blocks`, the overall schema is generated in multiple passes. + * + * All blocks start with the same style schema. Build that common schema + * once, then add block-specific pseudo and custom states below. */ + $responsive_block_schema = $styles_non_top_level; + $responsive_block_schema['elements'] = $schema_styles_elements; + + $common_block_schema = $styles_non_top_level; + $common_block_schema['elements'] = $schema_styles_elements; + + foreach ( $breakpoint_states as $breakpoint_state ) { + $common_block_schema[ $breakpoint_state ] = $responsive_block_schema; + } + foreach ( $valid_block_names as $block ) { - $schema_settings_blocks[ $block ] = static::VALID_SETTINGS; - // `viewport` and `blockVisibility` are global-only settings and cannot be set per block for now. - unset( $schema_settings_blocks[ $block ]['viewport'] ); - unset( $schema_settings_blocks[ $block ]['blockVisibility'] ); - $schema_styles_blocks[ $block ] = $styles_non_top_level; - $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements; - - // Add responsive breakpoint states for all blocks. - foreach ( array_keys( $responsive_media_queries ) as $breakpoint_state ) { - $schema_styles_blocks[ $block ][ $breakpoint_state ] = $styles_non_top_level; - $schema_styles_blocks[ $block ][ $breakpoint_state ]['elements'] = $schema_styles_elements; + $schema_settings_blocks[ $block ] = $common_block_settings; + $schema_styles_blocks[ $block ] = $common_block_schema; - if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block ] ) ) { + // Add responsive pseudo-selectors only to blocks that support them. + if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block ] ) ) { + foreach ( $breakpoint_states as $breakpoint_state ) { foreach ( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block ] as $pseudo_selector ) { $schema_styles_blocks[ $block ][ $breakpoint_state ][ $pseudo_selector ] = $styles_non_top_level; } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index c2cda7bb158d0..407489e6d26f2 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -8242,6 +8242,94 @@ public function test_blocks_without_pseudo_support_ignore_pseudo_selectors() { $this->assertStringNotContainsString( 'p:hover{', $theme_json->get_stylesheet( array( 'styles' ) ) ); } + /** + * Tests that responsive pseudo-states are kept only for supported blocks. + * + * @covers WP_Theme_JSON::sanitize + * + * @ticket 66003 + */ + public function test_sanitize_keeps_responsive_pseudo_states_on_supported_blocks_only() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/button' => array( + '@mobile' => array( + ':hover' => array( + 'color' => array( + 'text' => 'blue', + ), + ), + ), + ), + 'core/paragraph' => array( + 'color' => array( + 'text' => 'black', + ), + '@mobile' => array( + 'color' => array( + 'text' => 'green', + ), + ':hover' => array( + 'color' => array( + 'text' => 'red', + ), + ), + ), + ), + 'core/navigation-link' => array( + '-current' => array( + 'color' => array( + 'text' => 'purple', + ), + ), + ), + ), + ), + ) + ); + + $actual = $theme_json->get_raw_data(); + + $expected = array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/button' => array( + '@mobile' => array( + ':hover' => array( + 'color' => array( + 'text' => 'blue', + ), + ), + ), + ), + 'core/paragraph' => array( + 'color' => array( + 'text' => 'black', + ), + '@mobile' => array( + 'color' => array( + 'text' => 'green', + ), + ), + ), + 'core/navigation-link' => array( + '-current' => array( + 'color' => array( + 'text' => 'purple', + ), + ), + ), + ), + ), + ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + /** * Test that block pseudo selectors work with elements within blocks. */