Skip to content

Commit

Permalink
Block custom CSS: Fix incorrect CSS when multiple root selectors
Browse files Browse the repository at this point in the history
  • Loading branch information
t-hamano committed Aug 12, 2023
1 parent 73eca1d commit 65d02b2
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 6 deletions.
24 changes: 21 additions & 3 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -1138,9 +1138,27 @@ protected function process_blocks_custom_css( $css, $selector ) {
// Split CSS nested rules.
$parts = explode( '&', $css );
foreach ( $parts as $part ) {
$processed_css .= ( ! str_contains( $part, '{' ) )
? trim( $selector ) . '{' . trim( $part ) . '}' // If the part doesn't contain braces, it applies to the root level.
: trim( $selector . $part ); // Prepend the selector, which effectively replaces the "&" character.
$is_root_css = ( ! str_contains( $part, '{' ) );
if ( $is_root_css ) {
// If the part doesn't contain braces, it applies to the root level.
$processed_css .= trim( $selector ) . '{' . trim( $part ) . '}';
} else {
// If the part contains braces, it's a nested CSS rule.
$part = explode( '{', str_replace( '}', '', $part ) );
if ( count( $part ) !== 2 ) {
continue;
}
$nested_selector = $part[0];
$css_value = $part[1];
$root_selectors = explode( ',', $selector );
$combined_selectors = array_map(
static function( $root_selector ) use ( $nested_selector ) {
return $root_selector . $nested_selector;
},
$root_selectors
);
$processed_css .= implode( ',', $combined_selectors ) . '{' . trim( $css_value ) . '}';
}
}
return $processed_css;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1127,9 +1127,26 @@ const processCSSNesting = ( css, blockSelector ) => {
// 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.
const isRootCss = ! part.includes( '{' );
if ( isRootCss ) {
// If the part doesn't contain braces, it applies to the root level.
processedCSS += `${ blockSelector }{${ part }}`;
} else {
// If the part contains braces, it's a nested CSS rule.
const splittedPart = part.replace( '}', '' ).split( '{' );
if ( splittedPart.length !== 2 ) {
return;
}

const [ nestedSelector, cssValue ] = splittedPart;
const rootSelectors = blockSelector.split( ',' );
const combinedSelectors = rootSelectors.map(
( rootSelector ) => rootSelector + nestedSelector
);
processedCSS += `${ combinedSelectors.join(
', '
) }{${ cssValue.trim() }}`;
}
} );
return processedCSS;
};
Expand Down
8 changes: 8 additions & 0 deletions phpunit/class-wp-theme-json-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -2033,6 +2033,14 @@ public function data_process_blocks_custom_css() {
),
'expected' => '.foo{color: red; margin: auto;}.foo .bar{color: blue;}.foo::before{color: green;}',
),
// CSS with multiple root selectors.
'with multiple root selectors' => array(
'input' => array(
'selector' => '.foo, .bar',
'css' => 'color: red; margin: auto; & .baz{color: blue;} &::before{color: green;}',
),
'expected' => '.foo, .bar{color: red; margin: auto;}.foo .baz, .bar .baz{color: blue;}.foo::before, .bar::before{color: green;}',
),
);
}

Expand Down

0 comments on commit 65d02b2

Please sign in to comment.