diff --git a/lib/compat/wordpress-6.2/class-wp-theme-json-6-2.php b/lib/compat/wordpress-6.2/class-wp-theme-json-6-2.php index c5c139dde487d3..bc0bff5841d959 100644 --- a/lib/compat/wordpress-6.2/class-wp-theme-json-6-2.php +++ b/lib/compat/wordpress-6.2/class-wp-theme-json-6-2.php @@ -280,6 +280,27 @@ protected static function remove_insecure_styles( $input ) { return $output; } + /** + * Processes the CSS, to apply nesting. + * + * @param string $css The CSS to process. + * @param string $selector The selector to nest. + * + * @return string The processed CSS. + */ + private function process_nested_css( $css, $selector ) { + $processed_css = ''; + + // Split CSS nested rules. + $parts = explode( '&', $css ); + foreach ( $parts as $part ) { + $processed_css .= ( ! str_contains( $part, '{' ) ) + ? $selector . '{' . $part . '}' // If the part doesn't contain braces, it applies to the root level. + : $selector . $part; // Prepend the selector, which effectively replaces the "&" character. + } + return $processed_css; + } + /** * Returns the stylesheet that results of processing * the theme.json structure this object represents. @@ -383,15 +404,16 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' // Load the custom CSS last so it has the highest specificity. if ( in_array( 'custom-css', $types, true ) ) { - // Add the global styles root CSS: + // Add the global styles root CSS. $stylesheet .= _wp_array_get( $this->theme_json, array( 'styles', 'css' ) ); // Add the global styles block CSS. - foreach ( $this->theme_json['styles']['blocks'] as $name => $node ) + foreach ( $this->theme_json['styles']['blocks'] as $name => $node ) { if ( _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ) ) { - $selector = static::$blocks_metadata[ $name ]['selector']; - $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); - $stylesheet .= $selector . '{' . $custom_block_css . '}'; + $selector = static::$blocks_metadata[ $name ]['selector']; + $custom_block_css = _wp_array_get( $this->theme_json, array( 'styles', 'blocks', $name, 'css' ) ); + $stylesheet .= $this->process_nested_css( $custom_block_css, $selector ); + } } } diff --git a/packages/edit-site/src/components/global-styles/use-global-styles-output.js b/packages/edit-site/src/components/global-styles/use-global-styles-output.js index 93ee152d5839c5..b10e6e090ab32e 100644 --- a/packages/edit-site/src/components/global-styles/use-global-styles-output.js +++ b/packages/edit-site/src/components/global-styles/use-global-styles-output.js @@ -939,6 +939,19 @@ export function useGlobalStylesOutput() { }, ]; + const processCSSNesting = ( css, blockSelector ) => { + let processedCSS = ''; + + // Split CSS nested rules. + const parts = css.split( '&' ); + parts.forEach( ( part ) => { + processedCSS += ! part.includes( '{' ) + ? blockSelector + '{' + part + '}' // If the part doesn't contain braces, it applies to the root level. + : blockSelector + part; // Prepend the selector, which effectively replaces the "&" character. + } ); + return processedCSS; + }; + // Loop through the blocks to check if there are custom CSS values. // If there are, get the block selector and push the selector together with // the CSS value to the 'stylesheets' array. @@ -946,11 +959,10 @@ export function useGlobalStylesOutput() { if ( mergedConfig.styles.blocks[ name[ 0 ] ]?.css ) { const selector = blockSelectors[ name[ 0 ] ].selector; stylesheets.push( { - css: - selector + - '{' + - mergedConfig.styles.blocks[ name[ 0 ] ]?.css + - '}', + css: processCSSNesting( + mergedConfig.styles.blocks[ name[ 0 ] ]?.css, + selector + ), isGlobalStyles: true, } ); }