Make WordPress Core


Ignore:
Timestamp:
07/09/2026 01:46:32 AM (8 weeks ago)
Author:
isabel_brison
Message:

Editor: allow configuring viewport values in theme.json.

Enables a viewport object with tablet and mobile in theme.json settings and applies its values to style state and block visibility media queries.

Props isabel_brison, ramonopoly.
Fixes #65596.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-theme-json.php

    r62650 r62671  
    413413         *              Added support for `dimensions.width` and `dimensions.height`.
    414414         *              Added support for `typography.textIndent`.
     415         * @since 7.1.0 Added `viewport` property.
    415416         * @var array
    416417         */
     
    502503                        'writingMode'      => null,
    503504                ),
     505                'viewport'                      => array(
     506                        'mobile' => null,
     507                        'tablet' => null,
     508                ),
    504509        );
    505510
     
    669674
    670675        /**
    671          * Responsive breakpoint state keys and their corresponding CSS media queries.
    672          * These are available for all blocks and wrap their styles in the given media query.
    673          * Keep in sync with RESPONSIVE_BREAKPOINTS in packages/global-styles-engine/src/core/render.tsx.
     676         * Default viewport breakpoint sizes.
    674677         *
    675678         * @since 7.1.0
    676679         * @var array
    677680         */
    678         const RESPONSIVE_BREAKPOINTS = array(
    679                 '@mobile' => '@media (width <= 480px)',
    680                 '@tablet' => '@media (480px < width <= 782px)',
     681        const DEFAULT_VIEWPORT_BREAKPOINTS = array(
     682                'mobile' => '480px',
     683                'tablet' => '782px',
    681684        );
     685
     686        /**
     687         * Returns CSS media queries for responsive viewport style states.
     688         *
     689         * Breakpoint values are read from `settings.viewport`, sanitized, and
     690         * normalized before the media query strings are generated. By default, the
     691         * returned keys are the theme.json style-state names (`@mobile`, `@tablet`).
     692         * When `$options['include_desktop']` is truthy, `@desktop` is included.
     693         *
     694         * @since 7.1.0
     695         *
     696         * @param mixed $viewport_settings Viewport settings from theme.json.
     697         * @param array $options           {
     698         *     Optional. Options for generating media queries.
     699         *
     700         *     @type bool $include_desktop Whether to include the desktop media query. Default false.
     701         * }
     702         * @return array Responsive media queries.
     703         */
     704        public static function get_viewport_media_queries( $viewport_settings = null, $options = array() ) {
     705                $breakpoints = static::sanitize_viewport_settings( $viewport_settings );
     706
     707                $responsive_media_queries = array();
     708
     709                if ( isset( $breakpoints['mobile'] ) ) {
     710                        $responsive_media_queries['@mobile'] = "@media (width <= {$breakpoints['mobile']})";
     711                }
     712
     713                if ( isset( $breakpoints['tablet'] ) ) {
     714                        $responsive_media_queries['@tablet'] = isset( $breakpoints['mobile'] )
     715                                ? sprintf(
     716                                        '@media (%s < width <= %s)',
     717                                        $breakpoints['mobile'],
     718                                        $breakpoints['tablet']
     719                                )
     720                                : "@media (width <= {$breakpoints['tablet']})";
     721                }
     722
     723                if ( ! empty( $options['include_desktop'] ) ) {
     724                        if ( isset( $breakpoints['tablet'] ) ) {
     725                                $desktop_breakpoint = $breakpoints['tablet'];
     726                        } else {
     727                                $desktop_breakpoint = $breakpoints['mobile'];
     728                        }
     729
     730                        $responsive_media_queries['@desktop'] =
     731                                "@media (width > {$desktop_breakpoint})";
     732                }
     733
     734                return $responsive_media_queries;
     735        }
     736
     737        /**
     738         * Checks whether a viewport breakpoint value is a safe CSS length.
     739         *
     740         * Viewport breakpoints are limited to numeric `px`, `em`, and `rem` lengths.
     741         * CSS functions, percentages, and other units are rejected because breakpoint
     742         * values are interpolated into generated media queries.
     743         *
     744         * @since 7.1.0
     745         *
     746         * @param mixed $value Value to check.
     747         * @return bool Whether the value is valid.
     748         */
     749        private static function is_valid_viewport_breakpoint_size( $value ) {
     750                if ( ! is_string( $value ) ) {
     751                        return false;
     752                }
     753
     754                $value = trim( $value );
     755                if ( '' === $value ) {
     756                        return false;
     757                }
     758
     759                return 1 === preg_match( '/^(?:\d+|\d*\.\d+)(?:px|em|rem)$/', $value );
     760        }
     761
     762        /**
     763         * Converts a valid viewport breakpoint size to pixels for ordering checks.
     764         *
     765         * Generated media queries keep the original units. This method only
     766         * normalizes values so `mobile` and `tablet` can be compared safely. `em`
     767         * and `rem` lengths use a 16px base for comparison.
     768         *
     769         * @since 7.1.0
     770         *
     771         * @param mixed $value Viewport breakpoint size.
     772         * @return float|null Viewport breakpoint size in pixels, or null when invalid.
     773         */
     774        private static function get_viewport_breakpoint_value_in_pixels( $value ) {
     775                if ( ! static::is_valid_viewport_breakpoint_size( $value ) ) {
     776                        return null;
     777                }
     778
     779                $value = trim( $value );
     780                $unit  = substr( $value, -3 );
     781                if ( 'rem' === $unit ) {
     782                        $number = (float) substr( $value, 0, -3 );
     783                } else {
     784                        $unit   = substr( $value, -2 );
     785                        $number = (float) substr( $value, 0, -2 );
     786                }
     787
     788                /*
     789                 * Use the most common browser default font size as the base for em/rem
     790                 * media query conversions. This pixel value is only used to compare
     791                 * breakpoint order; generated media queries keep the original units.
     792                 */
     793                return 'px' === $unit ? $number : $number * 16;
     794        }
     795
     796        /**
     797         * Sanitizes and normalizes viewport breakpoint settings.
     798         *
     799         * Keeps only supported breakpoint keys, trims valid CSS lengths, and returns
     800         * the default breakpoints when no valid custom breakpoint is provided. When
     801         * only one breakpoint is valid, it remains keyed by its configured state and
     802         * uses a single max-width media query. When `tablet` is not larger than
     803         * `mobile`, it is removed.
     804         *
     805         * @since 7.1.0
     806         *
     807         * @param mixed $viewport_settings Viewport settings from theme.json.
     808         * @return array Sanitized viewport breakpoint settings.
     809         */
     810        private static function sanitize_viewport_settings( $viewport_settings ) {
     811                if ( ! is_array( $viewport_settings ) ) {
     812                        return static::DEFAULT_VIEWPORT_BREAKPOINTS;
     813                }
     814
     815                $breakpoints = array();
     816                foreach ( array_keys( static::DEFAULT_VIEWPORT_BREAKPOINTS ) as $breakpoint ) {
     817                        $value = $viewport_settings[ $breakpoint ] ?? null;
     818                        $px    = static::get_viewport_breakpoint_value_in_pixels( $value );
     819                        if ( null !== $px ) {
     820                                $breakpoints[ $breakpoint ] = array(
     821                                        'value' => trim( $value ),
     822                                        'px'    => $px,
     823                                );
     824                        }
     825                }
     826
     827                if ( empty( $breakpoints ) ) {
     828                        return static::DEFAULT_VIEWPORT_BREAKPOINTS;
     829                }
     830
     831                if ( 1 === count( $breakpoints ) ) {
     832                        $breakpoint = key( $breakpoints );
     833                        return array( $breakpoint => $breakpoints[ $breakpoint ]['value'] );
     834                }
     835
     836                $sanitized = array( 'mobile' => $breakpoints['mobile']['value'] );
     837
     838                if ( isset( $breakpoints['tablet'] ) && $breakpoints['mobile']['px'] < $breakpoints['tablet']['px'] ) {
     839                        $sanitized['tablet'] = $breakpoints['tablet']['value'];
     840                }
     841
     842                return $sanitized;
     843        }
    682844
    683845        /**
     
    11191281
    11201282                // Build the schema based on valid block & element names.
    1121                 $schema                 = array();
    1122                 $schema_styles_elements = array();
     1283                $schema                   = array();
     1284                $schema_styles_elements   = array();
     1285                $responsive_media_queries = static::get_viewport_media_queries( $input['settings']['viewport'] ?? null );
    11231286
    11241287                /*
     
    11401303
    11411304                        // Add responsive breakpoint states for elements.
    1142                         foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint_state ) {
     1305                        foreach ( array_keys( $responsive_media_queries ) as $breakpoint_state ) {
    11431306                                $schema_styles_elements[ $element ][ $breakpoint_state ] = $styles_non_top_level;
    11441307                        }
     
    11591322                 */
    11601323                foreach ( $valid_block_names as $block ) {
    1161                         $schema_settings_blocks[ $block ]           = static::VALID_SETTINGS;
     1324                        $schema_settings_blocks[ $block ] = static::VALID_SETTINGS;
     1325                        unset( $schema_settings_blocks[ $block ]['viewport'] );
    11621326                        $schema_styles_blocks[ $block ]             = $styles_non_top_level;
    11631327                        $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
    11641328
    11651329                        // Add responsive breakpoint states for all blocks.
    1166                         foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint_state ) {
     1330                        foreach ( array_keys( $responsive_media_queries ) as $breakpoint_state ) {
    11671331                                $schema_styles_blocks[ $block ][ $breakpoint_state ]             = $styles_non_top_level;
    11681332                                $schema_styles_blocks[ $block ][ $breakpoint_state ]['elements'] = $schema_styles_elements;
     
    12241388
    12251389                                        // Add responsive breakpoint states to block style variations.
    1226                                         foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint_state ) {
     1390                                        foreach ( array_keys( $responsive_media_queries ) as $breakpoint_state ) {
    12271391                                                $variation_schema[ $breakpoint_state ]             = $styles_non_top_level;
    12281392                                                $variation_schema[ $breakpoint_state ]['elements'] = $schema_styles_elements;
     
    12691433
    12701434                        $result = static::remove_keys_not_in_schema( $input[ $subtree ], $schema[ $subtree ] );
     1435
     1436                        if ( 'settings' === $subtree && array_key_exists( 'viewport', $input[ $subtree ] ) ) {
     1437                                $result['viewport'] = static::sanitize_viewport_settings( $input[ $subtree ]['viewport'] );
     1438                        }
    12711439
    12721440                        if ( empty( $result ) ) {
     
    31633331                }
    31643332
    3165                 $include_variations      = $options['include_block_style_variations'] ?? false;
    3166                 $include_node_paths_only = $options['include_node_paths_only'] ?? false;
     3333                $include_variations       = $options['include_block_style_variations'] ?? false;
     3334                $include_node_paths_only  = $options['include_node_paths_only'] ?? false;
     3335                $responsive_media_queries = static::get_viewport_media_queries( $theme_json['settings']['viewport'] ?? null );
    31673336
    31683337                // If only node paths are to be returned, skip selector assignment.
     
    32313400                                // These are rendered immediately after the base block node so that
    32323401                                // the cascade order is: .block{} → @media{.block{}}
    3233                                 foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     3402                                foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    32343403                                        if ( isset( $theme_json['styles']['blocks'][ $name ][ $breakpoint ] ) ) {
    32353404                                                $nodes[] = array(
    32363405                                                        'name'        => $name,
    32373406                                                        'path'        => array( 'styles', 'blocks', $name, $breakpoint ),
    3238                                                         'media_query' => static::RESPONSIVE_BREAKPOINTS[ $breakpoint ],
     3407                                                        'media_query' => $responsive_media_queries[ $breakpoint ],
    32393408                                                        'selector'    => $selector,
    32403409                                                        'selectors'   => $feature_selectors,
     
    32513420                                                $has_pseudo            = isset( $theme_json['styles']['blocks'][ $name ][ $pseudo_selector ] );
    32523421                                                $has_responsive_pseudo = false;
    3253                                                 foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     3422                                                foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    32543423                                                        if ( isset( $theme_json['styles']['blocks'][ $name ][ $breakpoint ][ $pseudo_selector ] ) ) {
    32553424                                                                $has_responsive_pseudo = true;
     
    32963465                                                // this pseudo state, immediately after the default pseudo node.
    32973466                                                // Cascade order: .block:hover{} → @media{.block:hover{}}
    3298                                                 foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     3467                                                foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    32993468                                                        if ( isset( $theme_json['styles']['blocks'][ $name ][ $breakpoint ][ $pseudo_selector ] ) ) {
    33003469                                                                $nodes[] = array(
    33013470                                                                        'name'        => $name,
    33023471                                                                        'path'        => array( 'styles', 'blocks', $name, $breakpoint, $pseudo_selector ),
    3303                                                                         'media_query' => static::RESPONSIVE_BREAKPOINTS[ $breakpoint ],
     3472                                                                        'media_query' => $responsive_media_queries[ $breakpoint ],
    33043473                                                                        'selector'    => static::append_to_selector( $selector, $pseudo_selector ),
    33053474                                                                        'selectors'   => $pseudo_feature_selectors,
     
    33733542                                        // Responsive element nodes: one node per breakpoint that has
    33743543                                        // styles for this element. Cascade: a{} → @media{a{}}
    3375                                         foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     3544                                        foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    33763545                                                if ( isset( $theme_json['styles']['blocks'][ $name ][ $breakpoint ]['elements'][ $element ] ) ) {
    33773546                                                        $nodes[] = array(
    33783547                                                                'path'        => array( 'styles', 'blocks', $name, $breakpoint, 'elements', $element ),
    33793548                                                                'selector'    => $element_selector,
    3380                                                                 'media_query' => static::RESPONSIVE_BREAKPOINTS[ $breakpoint ],
     3549                                                                'media_query' => $responsive_media_queries[ $breakpoint ],
    33813550                                                        );
    33823551                                                }
     
    33893558                                                        $has_element_pseudo = isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] );
    33903559                                                        if ( ! $has_element_pseudo ) {
    3391                                                                 foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $bp ) {
     3560                                                                foreach ( array_keys( $responsive_media_queries ) as $bp ) {
    33923561                                                                        if ( isset( $theme_json['styles']['blocks'][ $name ][ $bp ]['elements'][ $element ][ $pseudo_selector ] ) ) {
    33933562                                                                                $has_element_pseudo = true;
     
    34143583                                                                // that has this pseudo state for this element.
    34153584                                                                // Cascade: a:hover{} → @media{a:hover{}}
    3416                                                                 foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     3585                                                                foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    34173586                                                                        if ( isset( $theme_json['styles']['blocks'][ $name ][ $breakpoint ]['elements'][ $element ][ $pseudo_selector ] ) ) {
    34183587                                                                                $nodes[] = array(
    34193588                                                                                        'path'        => array( 'styles', 'blocks', $name, $breakpoint, 'elements', $element ),
    34203589                                                                                        'selector'    => static::append_to_selector( $element_selector, $pseudo_selector ),
    3421                                                                                         'media_query' => static::RESPONSIVE_BREAKPOINTS[ $breakpoint ],
     3590                                                                                        'media_query' => $responsive_media_queries[ $breakpoint ],
    34223591                                                                                );
    34233592                                                                        }
     
    34453614         */
    34463615        public function get_styles_for_block( $block_metadata ) {
    3447                 $node                 = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
    3448                 $use_root_padding     = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];
    3449                 $selector             = $block_metadata['selector'];
    3450                 $settings             = $this->theme_json['settings'] ?? array();
    3451                 $feature_declarations = static::get_feature_declarations_for_node( $block_metadata, $node );
    3452                 $is_root_selector     = static::ROOT_BLOCK_SELECTOR === $selector;
    3453                 $media_query          = $block_metadata['media_query'] ?? null;
     3616                $node                     = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
     3617                $use_root_padding         = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];
     3618                $selector                 = $block_metadata['selector'];
     3619                $settings                 = $this->theme_json['settings'] ?? array();
     3620                $feature_declarations     = static::get_feature_declarations_for_node( $block_metadata, $node );
     3621                $is_root_selector         = static::ROOT_BLOCK_SELECTOR === $selector;
     3622                $media_query              = $block_metadata['media_query'] ?? null;
     3623                $responsive_media_queries = static::get_viewport_media_queries( $settings['viewport'] ?? null );
    34543624
    34553625                // Update text indent selector for paragraph blocks based on the textIndent setting.
     
    35183688                                $variation_responsive_pseudo_css = '';
    35193689
    3520                                 foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     3690                                foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    35213691                                        if ( ! isset( $style_variation_node[ $breakpoint ] ) ) {
    35223692                                                continue;
     
    35243694
    35253695                                        $breakpoint_node  = $style_variation_node[ $breakpoint ];
    3526                                         $breakpoint_media = static::RESPONSIVE_BREAKPOINTS[ $breakpoint ];
     3696                                        $breakpoint_media = $responsive_media_queries[ $breakpoint ];
    35273697                                        // Process feature-level declarations for this breakpoint.
    35283698                                        $breakpoint_feature_declarations = static::get_feature_declarations_for_node( $block_metadata, $breakpoint_node );
     
    42884458                $theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names, $valid_variations );
    42894459
    4290                 $blocks_metadata = static::get_blocks_metadata();
    4291                 $style_options   = array( 'include_block_style_variations' => true ); // Allow variations data.
    4292                 $style_nodes     = static::get_style_nodes( $theme_json, $blocks_metadata, $style_options );
     4460                $blocks_metadata          = static::get_blocks_metadata();
     4461                $style_options            = array( 'include_block_style_variations' => true ); // Allow variations data.
     4462                $style_nodes              = static::get_style_nodes( $theme_json, $blocks_metadata, $style_options );
     4463                $responsive_media_queries = static::get_viewport_media_queries( $theme_json['settings']['viewport'] ?? null );
    42934464
    42944465                foreach ( $style_nodes as $metadata ) {
     
    43284499
    43294500                        // Re-add and process responsive breakpoint styles.
    4330                         foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     4501                        foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    43314502                                if ( isset( $input[ $breakpoint ] ) ) {
    43324503                                        $output[ $breakpoint ] = static::remove_insecure_styles( $input[ $breakpoint ] );
    43334504
    43344505                                        if ( isset( $input[ $breakpoint ]['elements'] ) ) {
    4335                                                 $output[ $breakpoint ]['elements'] = static::remove_insecure_element_styles( $input[ $breakpoint ]['elements'] );
     4506                                                $output[ $breakpoint ]['elements'] = static::remove_insecure_element_styles( $input[ $breakpoint ]['elements'], $responsive_media_queries );
    43364507                                        }
    43374508
    43384509                                        if ( isset( $input[ $breakpoint ]['blocks'] ) ) {
    4339                                                 $output[ $breakpoint ]['blocks'] = static::remove_insecure_inner_block_styles( $input[ $breakpoint ]['blocks'] );
     4510                                                $output[ $breakpoint ]['blocks'] = static::remove_insecure_inner_block_styles( $input[ $breakpoint ]['blocks'], $responsive_media_queries );
    43404511                                        }
    43414512
     
    43694540
    43704541                                        if ( isset( $variation_input['blocks'] ) ) {
    4371                                                 $variation_output['blocks'] = static::remove_insecure_inner_block_styles( $variation_input['blocks'] );
     4542                                                $variation_output['blocks'] = static::remove_insecure_inner_block_styles( $variation_input['blocks'], $responsive_media_queries );
    43724543                                        }
    43734544
    43744545                                        if ( isset( $variation_input['elements'] ) ) {
    4375                                                 $variation_output['elements'] = static::remove_insecure_element_styles( $variation_input['elements'] );
     4546                                                $variation_output['elements'] = static::remove_insecure_element_styles( $variation_input['elements'], $responsive_media_queries );
    43764547                                        }
    43774548
    43784549                                        // Re-add and process responsive breakpoint styles for variations.
    4379                                         foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
     4550                                        foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
    43804551                                                if ( isset( $variation_input[ $breakpoint ] ) ) {
    43814552                                                        $variation_output[ $breakpoint ] = static::remove_insecure_styles( $variation_input[ $breakpoint ] );
    43824553
    43834554                                                        if ( isset( $variation_input[ $breakpoint ]['elements'] ) ) {
    4384                                                                 $variation_output[ $breakpoint ]['elements'] = static::remove_insecure_element_styles( $variation_input[ $breakpoint ]['elements'] );
     4555                                                                $variation_output[ $breakpoint ]['elements'] = static::remove_insecure_element_styles( $variation_input[ $breakpoint ]['elements'], $responsive_media_queries );
    43854556                                                        }
    43864557
    43874558                                                        if ( isset( $variation_input[ $breakpoint ]['blocks'] ) ) {
    4388                                                                 $variation_output[ $breakpoint ]['blocks'] = static::remove_insecure_inner_block_styles( $variation_input[ $breakpoint ]['blocks'] );
     4559                                                                $variation_output[ $breakpoint ]['blocks'] = static::remove_insecure_inner_block_styles( $variation_input[ $breakpoint ]['blocks'], $responsive_media_queries );
    43894560                                                        }
    43904561
     
    44184589                        }
    44194590
    4420                         $output = static::remove_insecure_settings( $input );
     4591                        $output = static::remove_insecure_settings( $input, array( 'settings' ) === $metadata['path'] );
    44214592                        if ( ! empty( $output ) ) {
    44224593                                _wp_array_set( $sanitized, $metadata['path'], $output );
     
    44424613         * Remove insecure element styles within a variation or block.
    44434614         *
     4615         *  * When responsive media queries are provided, nested responsive state styles
     4616         * matching those viewport state keys are re-added after the base sanitization pass.
     4617         *
    44444618         * @since 6.8.0
    4445          *
    4446          * @param array $elements The elements to process.
     4619         * @since 7.1.0 Added the `$responsive_media_queries` parameter.
     4620         *
     4621         * @param array      $elements                 The elements to process.
     4622         * @param array|null $responsive_media_queries Optional. Media queries whose keys define allowed
     4623         *                                             viewport states. Default null.
    44474624         * @return array The sanitized elements styles.
    44484625         */
    4449         protected static function remove_insecure_element_styles( $elements ) {
     4626        protected static function remove_insecure_element_styles( $elements, $responsive_media_queries = null ) {
    44504627                $sanitized           = array();
    44514628                $valid_element_names = array_keys( static::ELEMENTS );
     
    44644641                                }
    44654642
    4466                                 // Re-add and process responsive breakpoint styles for elements.
    4467                                 foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
    4468                                         if ( isset( $element_input[ $breakpoint ] ) ) {
    4469                                                 $element_output[ $breakpoint ] = static::remove_insecure_styles( $element_input[ $breakpoint ] );
    4470 
    4471                                                 if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
    4472                                                         foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
    4473                                                                 if ( isset( $element_input[ $breakpoint ][ $pseudo_selector ] ) ) {
    4474                                                                         $element_output[ $breakpoint ][ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $breakpoint ][ $pseudo_selector ] );
     4643                                if ( null !== $responsive_media_queries ) {
     4644                                        // Re-add and process responsive breakpoint styles for elements.
     4645                                        foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
     4646                                                if ( isset( $element_input[ $breakpoint ] ) ) {
     4647                                                        $element_output[ $breakpoint ] = static::remove_insecure_styles( $element_input[ $breakpoint ] );
     4648
     4649                                                        if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
     4650                                                                foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
     4651                                                                        if ( isset( $element_input[ $breakpoint ][ $pseudo_selector ] ) ) {
     4652                                                                                $element_output[ $breakpoint ][ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $breakpoint ][ $pseudo_selector ] );
     4653                                                                        }
    44754654                                                                }
    44764655                                                        }
     
    44884667         * Remove insecure styles from inner blocks and their elements.
    44894668         *
     4669         * When responsive media queries are provided, nested responsive state styles
     4670         * for those media-query keys are re-added after the base sanitization pass.
     4671         *
    44904672         * @since 6.8.0
    4491          *
    4492          * @param array $blocks The block styles to process.
     4673         * @since 7.1.0 Added the `$responsive_media_queries` parameter.
     4674         *
     4675         * @param array      $blocks                   The block styles to process.
     4676         * @param array|null $responsive_media_queries Optional. Media queries whose keys define allowed
     4677         *                                             viewport states. Default null.
    44934678         * @return array Sanitized block type styles.
    44944679         */
    4495         protected static function remove_insecure_inner_block_styles( $blocks ) {
     4680        protected static function remove_insecure_inner_block_styles( $blocks, $responsive_media_queries = null ) {
    44964681                $sanitized = array();
    44974682                foreach ( $blocks as $block_type => $block_input ) {
     
    44994684
    45004685                        if ( isset( $block_input['elements'] ) ) {
    4501                                 $block_output['elements'] = static::remove_insecure_element_styles( $block_input['elements'] );
    4502                         }
    4503 
    4504                         // Re-add and process responsive breakpoint styles for inner blocks.
    4505                         foreach ( array_keys( static::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) {
    4506                                 if ( isset( $block_input[ $breakpoint ] ) ) {
    4507                                         $block_output[ $breakpoint ] = static::remove_insecure_styles( $block_input[ $breakpoint ] );
    4508 
    4509                                         if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_type ] ) ) {
    4510                                                 foreach ( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_type ] as $pseudo_selector ) {
    4511                                                         if ( isset( $block_input[ $breakpoint ][ $pseudo_selector ] ) ) {
    4512                                                                 $block_output[ $breakpoint ][ $pseudo_selector ] = static::remove_insecure_styles( $block_input[ $breakpoint ][ $pseudo_selector ] );
     4686                                $block_output['elements'] = static::remove_insecure_element_styles( $block_input['elements'], $responsive_media_queries );
     4687                        }
     4688
     4689                        if ( null !== $responsive_media_queries ) {
     4690                                // Re-add and process responsive breakpoint styles for inner blocks.
     4691                                foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) {
     4692                                        if ( isset( $block_input[ $breakpoint ] ) ) {
     4693                                                $block_output[ $breakpoint ] = static::remove_insecure_styles( $block_input[ $breakpoint ] );
     4694
     4695                                                if ( isset( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_type ] ) ) {
     4696                                                        foreach ( static::VALID_BLOCK_PSEUDO_SELECTORS[ $block_type ] as $pseudo_selector ) {
     4697                                                                if ( isset( $block_input[ $breakpoint ][ $pseudo_selector ] ) ) {
     4698                                                                        $block_output[ $breakpoint ][ $pseudo_selector ] = static::remove_insecure_styles( $block_input[ $breakpoint ][ $pseudo_selector ] );
     4699                                                                }
    45134700                                                        }
    45144701                                                }
     
    45564743         *
    45574744         * @since 5.9.0
    4558          *
    4559          * @param array $input Node to process.
     4745         * @since 7.1.0 Added the `$is_root` parameter.
     4746         *
     4747         * @param array $input   Node to process.
     4748         * @param bool  $is_root Optional. Whether the node is the root settings node. Default false.
    45604749         * @return array
    45614750         */
    4562         protected static function remove_insecure_settings( $input ) {
     4751        protected static function remove_insecure_settings( $input, $is_root = false ) {
    45634752                $output = array();
    45644753                foreach ( static::PRESETS_METADATA as $preset_metadata ) {
     
    46124801                // Preserve all valid settings that have type markers in VALID_SETTINGS.
    46134802                self::preserve_valid_typed_settings( $input, $output, static::VALID_SETTINGS );
     4803
     4804                if ( $is_root && array_key_exists( 'viewport', $input ) ) {
     4805                        $output['viewport'] = static::sanitize_viewport_settings( $input['viewport'] );
     4806                }
    46144807
    46154808                return $output;
Note: See TracChangeset for help on using the changeset viewer.