Make WordPress Core

Changeset 62514


Ignore:
Timestamp:
06/17/2026 03:37:58 AM (4 months ago)
Author:
isabel_brison
Message:

Editor: fix responsive element styles front end output.

Outputs viewport-specific state styles for elements such as Link or Heading that are part of a block.

Props isabel_brison, ramonopoly.
Fixes #65164.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-supports/states.php

    r62513 r62514  
    297297
    298298/**
     299 * Generates all element selectors for a block root selector.
     300 *
     301 * @since 7.1.0
     302 *
     303 * @param string $root_selector The block root CSS selector.
     304 * @return string[] Element selectors keyed by element name.
     305 */
     306function wp_get_block_state_element_selectors( $root_selector ) {
     307        if ( ! is_string( $root_selector ) || '' === trim( $root_selector ) ) {
     308                return array();
     309        }
     310
     311        $block_selectors   = wp_split_selector_list( $root_selector );
     312        $element_selectors = array();
     313
     314        foreach ( WP_Theme_JSON::ELEMENTS as $element_name => $element_selector ) {
     315                $selectors = array();
     316
     317                foreach ( $block_selectors as $block_selector ) {
     318                        $block_selector = trim( $block_selector );
     319                        if ( '' === $block_selector ) {
     320                                continue;
     321                        }
     322
     323                        if ( $block_selector === $element_selector ) {
     324                                $selectors = array( $element_selector );
     325                                break;
     326                        }
     327
     328                        $selector_prefix = "$block_selector ";
     329                        if ( ! str_contains( $element_selector, ',' ) ) {
     330                                $selectors[] = $selector_prefix . $element_selector;
     331                                continue;
     332                        }
     333
     334                        $prepended_selectors = array();
     335                        foreach ( wp_split_selector_list( $element_selector ) as $selector ) {
     336                                $prepended_selectors[] = $selector_prefix . $selector;
     337                        }
     338                        $selectors[] = implode( ',', $prepended_selectors );
     339                }
     340
     341                if ( ! empty( $selectors ) ) {
     342                        $element_selectors[ $element_name ] = implode( ',', $selectors );
     343                }
     344        }
     345
     346        return $element_selectors;
     347}
     348
     349/**
     350 * Adds a compiled state style rule to a rule list.
     351 *
     352 * @since 7.1.0
     353 *
     354 * @param array       $css_rules   Style rules.
     355 * @param string      $state       Pseudo-state selector.
     356 * @param string|null $selector    Block, feature, or element selector.
     357 * @param array       $style       Style object.
     358 * @param string|null $rules_group Optional CSS grouping rule, e.g. a media query.
     359 */
     360function wp_add_block_state_style_rule( &$css_rules, $state, $selector, $style, $rules_group = null ) {
     361        if ( empty( $style ) || ! is_array( $style ) ) {
     362                return;
     363        }
     364
     365        $compiled = wp_style_engine_get_styles(
     366                wp_normalize_state_style_for_css_output( $style )
     367        );
     368
     369        if ( empty( $compiled['declarations'] ) ) {
     370                return;
     371        }
     372
     373        $css_rules[] = array(
     374                'state'        => $state,
     375                'selector'     => $selector,
     376                'declarations' => $compiled['declarations'],
     377        );
     378        if ( ! empty( $rules_group ) ) {
     379                $css_rules[ count( $css_rules ) - 1 ]['rules_group'] = $rules_group;
     380        }
     381}
     382
     383/**
    299384 * Builds compiled state style rules, preserving the selector each rule targets.
    300385 *
    … …  
    318403
    319404                foreach ( wp_get_state_style_groups( $state_style, $block_selectors ) as $group ) {
    320                         $style    = wp_get_state_style_with_fallback_dimension_styles( $group['style'] );
    321                         $compiled = wp_style_engine_get_styles(
    322                                 wp_normalize_state_style_for_css_output( $style )
     405                        wp_add_block_state_style_rule(
     406                                $css_rules,
     407                                $state,
     408                                $group['selector'],
     409                                $group['style'],
     410                                $rules_group
    323411                        );
    324 
    325                         if ( ! empty( $compiled['declarations'] ) ) {
    326                                 $css_rules[] = array(
    327                                         'state'        => $state,
    328                                         'selector'     => $group['selector'],
    329                                         'declarations' => $compiled['declarations'],
    330                                 );
    331                                 if ( ! empty( $rules_group ) ) {
    332                                         $css_rules[ count( $css_rules ) - 1 ]['rules_group'] = $rules_group;
    333                                 }
    334                         }
    335412                }
    336413        }
    … …  
    502579                                )
    503580                        );
     581                }
     582
     583                if (
     584                        ! empty( $style[ $breakpoint ]['elements'] ) &&
     585                        is_array( $style[ $breakpoint ]['elements'] )
     586                ) {
     587                        $element_selectors = wp_get_block_state_element_selectors(
     588                                wp_get_block_css_selector( $block_type )
     589                        );
     590
     591                        foreach ( $style[ $breakpoint ]['elements'] as $element_name => $element_style ) {
     592                                if (
     593                                        empty( $element_style ) ||
     594                                        ! is_array( $element_style ) ||
     595                                        empty( $element_selectors[ $element_name ] )
     596                                ) {
     597                                        continue;
     598                                }
     599
     600                                $element_pseudo_states = WP_Theme_JSON::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ]
     601                                        ?? array();
     602                                $root_element_style    = wp_get_root_state_style(
     603                                        $element_style,
     604                                        $element_pseudo_states
     605                                );
     606
     607                                wp_add_block_state_style_rule(
     608                                        $css_rules,
     609                                        '',
     610                                        $element_selectors[ $element_name ],
     611                                        $root_element_style,
     612                                        $media_query
     613                                );
     614
     615                                foreach ( $element_pseudo_states as $pseudo_state ) {
     616                                        if (
     617                                                empty( $element_style[ $pseudo_state ] ) ||
     618                                                ! is_array( $element_style[ $pseudo_state ] )
     619                                        ) {
     620                                                continue;
     621                                        }
     622
     623                                        wp_add_block_state_style_rule(
     624                                                $css_rules,
     625                                                $pseudo_state,
     626                                                $element_selectors[ $element_name ],
     627                                                $element_style[ $pseudo_state ],
     628                                                $media_query
     629                                        );
     630                                }
     631                        }
    504632                }
    505633
  • trunk/tests/phpunit/tests/block-supports/states.php

    r62513 r62514  
    961961                $this->assertStringContainsString(
    962962                        '@media (width <= 480px){.' . $matches[0] . '{color:#ff0000 !important;}}',
     963                        $actual_stylesheet
     964                );
     965        }
     966
     967        /**
     968         * Tests that a responsive element color generates media-query scoped CSS.
     969         *
     970         * @covers ::wp_render_block_states_support
     971         *
     972         * @ticket 65164
     973         */
     974        public function test_responsive_element_color_generates_media_query_scoped_css() {
     975                $this->ensure_block_registered( 'core/group' );
     976
     977                $block_content = '<div class="wp-block-group"><p><a href="#">Link</a></p></div>';
     978                $block         = array(
     979                        'blockName' => 'core/group',
     980                        'attrs'     => array(
     981                                'style' => array(
     982                                        'mobile' => array(
     983                                                'elements' => array(
     984                                                        'link' => array(
     985                                                                'color' => array(
     986                                                                        'text' => '#00ff00',
     987                                                                ),
     988                                                        ),
     989                                                ),
     990                                        ),
     991                                ),
     992                        ),
     993                );
     994
     995                $actual = wp_render_block_states_support( $block_content, $block );
     996
     997                $this->assertMatchesRegularExpression(
     998                        '/^<div class="wp-block-group (wp-states-[a-f0-9]{8})"><p><a href="#">Link<\/a><\/p><\/div>$/',
     999                        $actual
     1000                );
     1001                preg_match( '/wp-states-[a-f0-9]{8}/', $actual, $matches );
     1002                $actual_stylesheet = wp_style_engine_get_stylesheet_from_context( 'block-supports', array( 'prettify' => false ) );
     1003
     1004                $this->assertStringContainsString(
     1005                        '@media (width <= 480px){.' . $matches[0] . ' a:where(:not(.wp-element-button)){color:#00ff00 !important;}}',
    9631006                        $actual_stylesheet
    9641007                );
Note: See TracChangeset for help on using the changeset viewer.