Make WordPress Core

Changeset 58987


Ignore:
Timestamp:
09/04/2024 02:22:16 PM (6 weeks ago)
Author:
hellofromTonya
Message:

Editor: Fix block custom CSS pseudo element selectors in global styles.

Fixes a regression introduced in [58241] where selectors with pseudo elements are wrapped within :where() causing malformed CSS and the CSS rule(s) not being applied.

When processing custom CSS for blocks, this changeset:

  • Strips the pseudo-elements from the original nested selector, performs the required wrapping in :root :where, then re-appends the pseudo-element selector with its leading combinators if present.
  • Removes empty CSS rules.

It includes the PHP changes.

Reference:

Follow-up to [58241], [56812], [55216].

Reviewed by andrewserong.
Merges [58896] to the 6.6 branch.

Props aaronrobertshaw, wongjn, harlet7, dballari, ramonopoly, andrewserong, aristath, hellofromTonya.
Fixes #61769.

Location:
branches/6.6
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/6.6

  • branches/6.6/src/wp-includes/class-wp-theme-json.php

    r58986 r58987  
    14401440        $processed_css = '';
    14411441
     1442        if ( empty( $css ) ) {
     1443            return $processed_css;
     1444        }
     1445
    14421446        // Split CSS nested rules.
    14431447        $parts = explode( '&', $css );
    14441448        foreach ( $parts as $part ) {
     1449            if ( empty( $part ) ) {
     1450                continue;
     1451            }
    14451452            $is_root_css = ( ! str_contains( $part, '{' ) );
    14461453            if ( $is_root_css ) {
     
    14551462                $nested_selector = $part[0];
    14561463                $css_value       = $part[1];
    1457                 $part_selector   = str_starts_with( $nested_selector, ' ' )
     1464
     1465                /*
     1466                 * Handle pseudo elements such as ::before, ::after etc. Regex will also
     1467                 * capture any leading combinator such as >, +, or ~, as well as spaces.
     1468                 * This allows pseudo elements as descendants e.g. `.parent ::before`.
     1469                 */
     1470                $matches            = array();
     1471                $has_pseudo_element = preg_match( '/([>+~\s]*::[a-zA-Z-]+)/', $nested_selector, $matches );
     1472                $pseudo_part        = $has_pseudo_element ? $matches[1] : '';
     1473                $nested_selector    = $has_pseudo_element ? str_replace( $pseudo_part, '', $nested_selector ) : $nested_selector;
     1474
     1475                // Finalize selector and re-append pseudo element if required.
     1476                $part_selector  = str_starts_with( $nested_selector, ' ' )
    14581477                    ? static::scope_selector( $selector, $nested_selector )
    14591478                    : static::append_to_selector( $selector, $nested_selector );
    1460                 $final_selector  = ":root :where($part_selector)";
    1461                 $processed_css  .= $final_selector . '{' . trim( $css_value ) . '}';}
     1479                $final_selector = ":root :where($part_selector)$pseudo_part";
     1480
     1481                $processed_css .= $final_selector . '{' . trim( $css_value ) . '}';
     1482            }
    14621483        }
    14631484        return $processed_css;
  • branches/6.6/tests/phpunit/tests/theme/wpThemeJson.php

    r58986 r58987  
    51545154    /**
    51555155     * @ticket 61165
     5156     * @ticket 61769
    51565157     *
    51575158     * @dataProvider data_process_blocks_custom_css
     
    51815182        return array(
    51825183            // Simple CSS without any nested selectors.
     5184            'empty css'                    => array(
     5185                'input'    => array(
     5186                    'selector' => '.foo',
     5187                    'css'      => '',
     5188                ),
     5189                'expected' => '',
     5190            ),
    51835191            'no nested selectors'          => array(
    51845192                'input'    => array(
     
    51965204                'expected' => ':root :where(.foo){color: red; margin: auto;}:root :where(.foo.one){color: blue;}:root :where(.foo .two){color: green;}',
    51975205            ),
     5206            'no root styles'               => array(
     5207                'input'    => array(
     5208                    'selector' => '.foo',
     5209                    'css'      => '&::before{color: red;}',
     5210                ),
     5211                'expected' => ':root :where(.foo)::before{color: red;}',
     5212            ),
    51985213            // CSS with pseudo elements.
    51995214            'with pseudo elements'         => array(
     
    52025217                    'css'      => 'color: red; margin: auto; &::before{color: blue;} & ::before{color: green;}  &.one::before{color: yellow;} & .two::before{color: purple;}',
    52035218                ),
    5204                 'expected' => ':root :where(.foo){color: red; margin: auto;}:root :where(.foo::before){color: blue;}:root :where(.foo ::before){color: green;}:root :where(.foo.one::before){color: yellow;}:root :where(.foo .two::before){color: purple;}',
     5219                'expected' => ':root :where(.foo){color: red; margin: auto;}:root :where(.foo)::before{color: blue;}:root :where(.foo) ::before{color: green;}:root :where(.foo.one)::before{color: yellow;}:root :where(.foo .two)::before{color: purple;}',
    52055220            ),
    52065221            // CSS with multiple root selectors.
     
    52105225                    'css'      => 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;} &::before{color: yellow;} & ::before{color: purple;}  &.three::before{color: orange;} & .four::before{color: skyblue;}',
    52115226                ),
    5212                 'expected' => ':root :where(.foo, .bar){color: red; margin: auto;}:root :where(.foo.one, .bar.one){color: blue;}:root :where(.foo .two, .bar .two){color: green;}:root :where(.foo::before, .bar::before){color: yellow;}:root :where(.foo ::before, .bar ::before){color: purple;}:root :where(.foo.three::before, .bar.three::before){color: orange;}:root :where(.foo .four::before, .bar .four::before){color: skyblue;}',
     5227                'expected' => ':root :where(.foo, .bar){color: red; margin: auto;}:root :where(.foo.one, .bar.one){color: blue;}:root :where(.foo .two, .bar .two){color: green;}:root :where(.foo, .bar)::before{color: yellow;}:root :where(.foo, .bar) ::before{color: purple;}:root :where(.foo.three, .bar.three)::before{color: orange;}:root :where(.foo .four, .bar .four)::before{color: skyblue;}',
    52135228            ),
    52145229        );
Note: See TracChangeset for help on using the changeset viewer.