diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 5abd2817b8aa4..c2eef1f6e2d5d 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -3216,7 +3216,12 @@ static function ( $pseudo_selector ) use ( $selector ) { // 7. Generate and append any custom CSS rules. if ( isset( $node['css'] ) && ! $is_root_selector ) { - $block_rules .= $this->process_blocks_custom_css( $node['css'], $selector ); + $css_feature_selector = $block_metadata['selectors']['css'] ?? null; + if ( is_array( $css_feature_selector ) ) { + $css_feature_selector = $css_feature_selector['root'] ?? null; + } + $css_selector = is_string( $css_feature_selector ) ? $css_feature_selector : $selector; + $block_rules .= $this->process_blocks_custom_css( $node['css'], $css_selector ); } return $block_rules; @@ -4610,10 +4615,10 @@ protected function get_feature_declarations_for_node( $metadata, &$node ) { foreach ( $metadata['selectors'] as $feature => $feature_selectors ) { /* - * Skip if this is the block's root selector or the block doesn't - * have any styles for the feature. + * Skip if this is the block's root selector, the custom CSS + * selector, or the block doesn't have any styles for the feature. */ - if ( 'root' === $feature || empty( $node[ $feature ] ) ) { + if ( 'root' === $feature || 'css' === $feature || empty( $node[ $feature ] ) ) { continue; } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 95de67c69f98c..6ed1f23d8e5b2 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -7054,4 +7054,113 @@ public function test_sanitize_preserves_null_schema_behavior() { $this->assertSame( 'string-value', $settings['appearanceTools'], 'Appearance tools should be string value' ); $this->assertSame( array( 'nested' => 'value' ), $settings['custom'], 'Custom should be array value' ); } + + /** + * Tests that block custom CSS uses the css feature selector when defined + * in block metadata selectors config. + * + * @ticket 64695 + */ + public function test_get_styles_for_block_custom_css_uses_css_feature_selector() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/paragraph' => array( + 'css' => 'color:red;', + ), + ), + ), + ) + ); + + $paragraph_node = array( + 'name' => 'core/paragraph', + 'path' => array( 'styles', 'blocks', 'core/paragraph' ), + 'selector' => 'p', + 'selectors' => array( + 'root' => 'p', + 'css' => '.custom-p', + ), + ); + + $this->assertSame( + ':root :where(.custom-p){color:red;}', + $theme_json->get_styles_for_block( $paragraph_node ) + ); + } + + /** + * Tests that block custom CSS falls back to the root selector when no + * css feature selector is defined in block metadata selectors config. + * + * @ticket 64695 + */ + public function test_get_styles_for_block_custom_css_falls_back_to_root_selector() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/paragraph' => array( + 'css' => 'color:red;', + ), + ), + ), + ) + ); + + $paragraph_node = array( + 'name' => 'core/paragraph', + 'path' => array( 'styles', 'blocks', 'core/paragraph' ), + 'selector' => 'p', + 'selectors' => array( + 'root' => 'p', + ), + ); + + $this->assertSame( + ':root :where(p){color:red;}', + $theme_json->get_styles_for_block( $paragraph_node ) + ); + } + + /** + * Tests that block custom CSS uses the css feature selector when defined + * as an object with a root subkey in block metadata selectors config. + * + * @ticket 64695 + */ + public function test_get_styles_for_block_custom_css_uses_css_feature_selector_object_form() { + $theme_json = new WP_Theme_JSON( + array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/paragraph' => array( + 'css' => 'color:red;', + ), + ), + ), + ) + ); + + $paragraph_node = array( + 'name' => 'core/paragraph', + 'path' => array( 'styles', 'blocks', 'core/paragraph' ), + 'selector' => 'p', + 'selectors' => array( + 'root' => 'p', + 'css' => array( + 'root' => '.custom-p', + ), + ), + ); + + $this->assertSame( + ':root :where(.custom-p){color:red;}', + $theme_json->get_styles_for_block( $paragraph_node ) + ); + } }