Make WordPress Core

Changeset 54159


Ignore:
Timestamp:
09/14/2022 02:19:16 PM (4 years ago)
Author:
audrasjb
Message:

Editor: Backport foundation for Layout block support refactor (part 1).

This change backports the following changes from Gutenberg repository:

  • [WordPress/gutenberg#40875 gutenberg#40875] Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json
  • [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
  • [WordPress/gutenberg#42087 gutenberg#42087] Theme.json: Add block support feature level selectors for blocks gutenberg#42087
  • [WordPress/gutenberg#43792 gutenberg#43792] Global Styles: Split root layout rules into a different function gutenberg#43792
  • [WordPress/gutenberg#42544 gutenberg#42544] Layout: Add a disable-layout-styles theme supports flag to opt out of all layout styles gutenberg#42544
  • [WordPress/gutenberg#42665 gutenberg#42665] Layout: Reduce specificity of fallback blockGap styles gutenberg#42665
  • [WordPress/gutenberg#42085 gutenberg#42085] Core CSS support for root padding and alignfull blocks gutenberg#42085

Note that it doesn't entirely port over PR40875 — the remaining PHP changes for that PR will be explored in a separate PR targeting layout.php.

Props andrewserong, aaronrobertshaw, isabel_brison.
See #56467.

Location:
trunk
Files:
9 edited

Legend:

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

    r54155 r54159  
    210210                'disableCustomFontSizes'           => get_theme_support( 'disable-custom-font-sizes' ),
    211211                'disableCustomGradients'           => get_theme_support( 'disable-custom-gradients' ),
     212                'disableLayoutStyles'              => get_theme_support( 'disable-layout-styles' ),
    212213                'enableCustomLineHeight'           => get_theme_support( 'custom-line-height' ),
    213214                'enableCustomSpacing'              => get_theme_support( 'custom-spacing' ),
    … …  
    418419                        $global_styles[]      = $block_classes;
    419420                }
     421        } else {
     422                // If there is no `theme.json` file, ensure base layout styles are still available.
     423                $block_classes = array(
     424                        'css'            => 'base-layout-styles',
     425                        '__unstableType' => 'base-layout',
     426                        'isGlobalStyles' => true,
     427                );
     428                $actual_css    = wp_get_global_stylesheet( array( $block_classes['css'] ) );
     429                if ( '' !== $actual_css ) {
     430                        $block_classes['css'] = $actual_css;
     431                        $global_styles[]  = $block_classes;
     432                }
    420433        }
    421434
    … …  
    475488                unset( $editor_settings['__experimentalFeatures']['spacing']['padding'] );
    476489        }
     490        if ( isset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] ) ) {
     491                $editor_settings['disableCustomSpacingSizes'] = ! $editor_ettings['__experimentalFeatures']['spacing']['customSpacingSize'];
     492                unset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] );
     493        }
     494        if ( isset( $editor_settings['__experimentalFeatures']['spacing']['spacingSizes'] ) ) {
     495                $spacing_sizes_by_origin  = $editor_settings['__experimentalFeatures']['spacing']['spacingSizes'];
     496                $editor_settings['spacingSizes'] = isset( $spacing_sizes_by_origin['custom'] ) ?
     497                        $spacing_sizes_by_origin['custom'] : (
     498                                isset( $spacing_sizes_by_origin['theme'] ) ?
     499                                        $spacing_sizes_by_origin['theme'] :
     500                                        $spacing_sizes_by_origin['default']
     501                        );
     502        }
    477503
    478504        $editor_settings['__unstableResolvedAssets']         = _wp_get_iframed_editor_assets();
    479505        $editor_settings['localAutosaveInterval']            = 15;
     506        $editor_settings['disableLayoutStyles']              = current_theme_supports( 'disable-layout-styles' );
    480507        $editor_settings['__experimentalDiscussionSettings'] = array(
    481508                'commentOrder'         => get_option( 'comment_order' ),
  • trunk/src/wp-includes/class-wp-theme-json-resolver.php

    r54133 r54159  
    231231
    232232                return $with_theme_supports;
     233        }
     234
     235        /**
     236         * Gets the styles for blocks from the block.json file.
     237         *
     238         * @since 6.1.0
     239         *
     240         * @return WP_Theme_JSON
     241         */
     242        public static function get_block_data() {
     243                $registry = WP_Block_Type_Registry::get_instance();
     244                $blocks   = $registry->get_all_registered();
     245                $config   = array( 'version' => 1 );
     246                foreach ( $blocks as $block_name => $block_type ) {
     247                        if ( isset( $block_type->supports['__experimentalStyle'] ) ) {
     248                                $config['styles']['blocks'][ $block_name ] = static::remove_json_comments( $block_type->supports['__experimentalStyle'] );
     249                        }
     250
     251                        if (
     252                                isset( $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ) &&
     253                                null === _wp_array_get( $config, array( 'styles', 'blocks', $block_name, 'spacing', 'blockGap' ), null )
     254                        ) {
     255                                // Ensure an empty placeholder value exists for the block, if it provides a default blockGap value.
     256                                // The real blockGap value to be used will be determined when the styles are rendered for output.
     257                                $config['styles']['blocks'][ $block_name ]['spacing']['blockGap'] = null;
     258                        }
     259                }
     260
     261                // Core here means it's the lower level part of the styles chain.
     262                // It can be a core or a third-party block.
     263                return new WP_Theme_JSON( $config, 'core' );
     264        }
     265
     266        /**
     267         * When given an array, this will remove any keys with the name `//`.
     268         *
     269         * @param array $array The array to filter.
     270         * @return array The filtered array.
     271         */
     272        private static function remove_json_comments( $array ) {
     273                unset( $array['//'] );
     274                foreach ( $array as $k => $v ) {
     275                        if ( is_array( $v ) ) {
     276                                $array[ $k ] = static::remove_json_comments( $v );
     277                        }
     278                }
     279
     280                return $array;
    233281        }
    234282
    … …  
    371419         * @since 5.9.0 Added user data, removed the `$settings` parameter,
    372420         *              added the `$origin` parameter.
     421         * @since 6.1.0 Added block data.
    373422         *
    374423         * @param string $origin Optional. To what level should we merge data.
    … …  
    383432                $result = new WP_Theme_JSON();
    384433                $result->merge( static::get_core_data() );
     434                $result->merge( static::get_block_data() );
    385435                $result->merge( static::get_theme_data() );
    386436
  • trunk/src/wp-includes/class-wp-theme-json.php

    r54133 r54159  
    178178         *              `text-decoration`, `text-transform`, and `filter` properties,
    179179         *              simplified the metadata structure.
     180         * @since 6.1.0 Added the `border-*-color`, `border-*-width`, `border-*-style`,
     181         *              `--wp--style--root--padding-*`, and `box-shadow` properties,
     182         *              removed the `--wp--style--block-gap` property.
    180183         * @var array
    181184         */
    182185        const PROPERTIES_METADATA = array(
    183                 'background'                 => array( 'color', 'gradient' ),
    184                 'background-color'           => array( 'color', 'background' ),
    185                 'border-radius'              => array( 'border', 'radius' ),
    186                 'border-top-left-radius'     => array( 'border', 'radius', 'topLeft' ),
    187                 'border-top-right-radius'    => array( 'border', 'radius', 'topRight' ),
    188                 'border-bottom-left-radius'  => array( 'border', 'radius', 'bottomLeft' ),
    189                 'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ),
    190                 'border-color'               => array( 'border', 'color' ),
    191                 'border-width'               => array( 'border', 'width' ),
    192                 'border-style'               => array( 'border', 'style' ),
    193                 'color'                      => array( 'color', 'text' ),
    194                 'font-family'                => array( 'typography', 'fontFamily' ),
    195                 'font-size'                  => array( 'typography', 'fontSize' ),
    196                 'font-style'                 => array( 'typography', 'fontStyle' ),
    197                 'font-weight'                => array( 'typography', 'fontWeight' ),
    198                 'letter-spacing'             => array( 'typography', 'letterSpacing' ),
    199                 'line-height'                => array( 'typography', 'lineHeight' ),
    200                 'margin'                     => array( 'spacing', 'margin' ),
    201                 'margin-top'                 => array( 'spacing', 'margin', 'top' ),
    202                 'margin-right'               => array( 'spacing', 'margin', 'right' ),
    203                 'margin-bottom'              => array( 'spacing', 'margin', 'bottom' ),
    204                 'margin-left'                => array( 'spacing', 'margin', 'left' ),
    205                 'padding'                    => array( 'spacing', 'padding' ),
    206                 'padding-top'                => array( 'spacing', 'padding', 'top' ),
    207                 'padding-right'              => array( 'spacing', 'padding', 'right' ),
    208                 'padding-bottom'             => array( 'spacing', 'padding', 'bottom' ),
    209                 'padding-left'               => array( 'spacing', 'padding', 'left' ),
    210                 '--wp--style--block-gap'     => array( 'spacing', 'blockGap' ),
    211                 'text-decoration'            => array( 'typography', 'textDecoration' ),
    212                 'text-transform'             => array( 'typography', 'textTransform' ),
    213                 'filter'                     => array( 'filter', 'duotone' ),
     186                'background'                        => array( 'color', 'gradient' ),
     187                'background-color'                  => array( 'color', 'background' ),
     188                'border-radius'                     => array( 'border', 'radius' ),
     189                'border-top-left-radius'            => array( 'border', 'radius', 'topLeft' ),
     190                'border-top-right-radius'           => array( 'border', 'radius', 'topRight' ),
     191                'border-bottom-left-radius'         => array( 'border', 'radius', 'bottomLeft' ),
     192                'border-bottom-right-radius'        => array( 'border', 'radius', 'bottomRight' ),
     193                'border-color'                      => array( 'border', 'color' ),
     194                'border-width'                      => array( 'border', 'width' ),
     195                'border-style'                      => array( 'border', 'style' ),
     196                'border-top-color'                  => array( 'border', 'top', 'color' ),
     197                'border-top-width'                  => array( 'border', 'top', 'width' ),
     198                'border-top-style'                  => array( 'border', 'top', 'style' ),
     199                'border-right-color'                => array( 'border', 'right', 'color' ),
     200                'border-right-width'                => array( 'border', 'right', 'width' ),
     201                'border-right-style'                => array( 'border', 'right', 'style' ),
     202                'border-bottom-color'               => array( 'border', 'bottom', 'color' ),
     203                'border-bottom-width'               => array( 'border', 'bottom', 'width' ),
     204                'border-bottom-style'               => array( 'border', 'bottom', 'style' ),
     205                'border-left-color'                 => array( 'border', 'left', 'color' ),
     206                'border-left-width'                 => array( 'border', 'left', 'width' ),
     207                'border-left-style'                 => array( 'border', 'left', 'style' ),
     208                'color'                             => array( 'color', 'text' ),
     209                'font-family'                       => array( 'typography', 'fontFamily' ),
     210                'font-size'                         => array( 'typography', 'fontSize' ),
     211                'font-style'                        => array( 'typography', 'fontStyle' ),
     212                'font-weight'                       => array( 'typography', 'fontWeight' ),
     213                'letter-spacing'                    => array( 'typography', 'letterSpacing' ),
     214                'line-height'                       => array( 'typography', 'lineHeight' ),
     215                'margin'                            => array( 'spacing', 'margin' ),
     216                'margin-top'                        => array( 'spacing', 'margin', 'top' ),
     217                'margin-right'                      => array( 'spacing', 'margin', 'right' ),
     218                'margin-bottom'                     => array( 'spacing', 'margin', 'bottom' ),
     219                'margin-left'                       => array( 'spacing', 'margin', 'left' ),
     220                'padding'                           => array( 'spacing', 'padding' ),
     221                'padding-top'                       => array( 'spacing', 'padding', 'top' ),
     222                'padding-right'                     => array( 'spacing', 'padding', 'right' ),
     223                'padding-bottom'                    => array( 'spacing', 'padding', 'bottom' ),
     224                'padding-left'                      => array( 'spacing', 'padding', 'left' ),
     225                '--wp--style--root--padding'        => array( 'spacing', 'padding' ),
     226                '--wp--style--root--padding-top'    => array( 'spacing', 'padding', 'top' ),
     227                '--wp--style--root--padding-right'  => array( 'spacing', 'padding', 'right' ),
     228                '--wp--style--root--padding-bottom' => array( 'spacing', 'padding', 'bottom' ),
     229                '--wp--style--root--padding-left'   => array( 'spacing', 'padding', 'left' ),
     230                'text-decoration'                   => array( 'typography', 'textDecoration' ),
     231                'text-transform'                    => array( 'typography', 'textTransform' ),
     232                'filter'                            => array( 'filter', 'duotone' ),
     233                'box-shadow'                        => array( 'shadow' ),
    214234        );
    215235
    … …  
    255275         *              and `typography`, and renamed others according to the new schema.
    256276         * @since 6.0.0 Added `color.defaultDuotone`.
     277         * @since 6.1.0 Added `layout.definitions` and `useRootPaddingAwareAlignments`.
    257278         * @var array
    258279         */
    259280        const VALID_SETTINGS = array(
    260                 'appearanceTools' => null,
    261                 'border'          => array(
     281                'appearanceTools'               => null,
     282                'useRootPaddingAwareAlignments' => null,
     283                'border'                        => array(
    262284                        'color'  => null,
    263285                        'radius' => null,
    … …  
    265287                        'width'  => null,
    266288                ),
    267                 'color'           => array(
     289                'color'                         => array(
    268290                        'background'       => null,
    269291                        'custom'           => null,
    … …  
    279301                        'text'             => null,
    280302                ),
    281                 'custom'          => null,
    282                 'layout'          => array(
     303                'custom'                        => null,
     304                'layout'                        => array(
    283305                        'contentSize' => null,
    284306                        'wideSize'    => null,
    285307                ),
    286                 'spacing'         => array(
     308                'spacing'                       => array(
    287309                        'blockGap' => null,
    288310                        'margin'   => null,
    … …  
    290312                        'units'    => null,
    291313                ),
    292                 'typography'      => array(
     314                'typography'                    => array(
    293315                        'customFontSize' => null,
    294316                        'dropCap'        => null,
    … …  
    311333         *              added new properties for `border`, `filter`, `spacing`,
    312334         *              and `typography`.
     335         * @since 6.1.0 Added new side properties for `border`,
     336         *              updated `blockGap` to be allowed at any level.
    313337         * @var array
    314338         */
    … …  
    319343                        'style'  => null,
    320344                        'width'  => null,
     345                        'top'    => null,
     346                        'right'  => null,
     347                        'bottom' => null,
     348                        'left'   => null,
    321349                ),
    322350                'color'      => array(
    … …  
    331359                        'margin'   => null,
    332360                        'padding'  => null,
    333                         'blockGap' => 'top',
     361                        'blockGap' => null,
    334362                ),
    335363                'typography' => array(
    … …  
    382410                'button'  => 'wp-element-button',
    383411                'caption' => 'wp-element-caption',
     412        );
     413
     414        /**
     415         * List of block support features that can have their related styles
     416         * generated under their own feature level selector rather than the block's.
     417         *
     418         * @since 6.1.0
     419         * @var string[]
     420         */
     421        const BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS = array(
     422                '__experimentalBorder' => 'border',
     423                'color'                => 'color',
     424                'spacing'              => 'spacing',
     425                'typography'           => 'typography',
    384426        );
    385427
    … …  
    657699         * @since 5.8.0
    658700         * @since 5.9.0 Added `duotone` key with CSS selector.
     701         * @since 6.1.0 Added `features` key with block support feature level selectors.
    659702         *
    660703         * @return array Block metadata.
    … …  
    684727                        ) {
    685728                                static::$blocks_metadata[ $block_name ]['duotone'] = $block_type->supports['color']['__experimentalDuotone'];
     729                        }
     730
     731                        // Generate block support feature level selectors if opted into
     732                        // for the current block.
     733                        $features = array();
     734                        foreach ( static::BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS as $key => $feature ) {
     735                                if (
     736                                        isset( $block_type->supports[ $key ]['__experimentalSelector'] ) &&
     737                                        $block_type->supports[ $key ]['__experimentalSelector']
     738                                ) {
     739                                        $features[ $feature ] = static::scope_selector(
     740                                                static::$blocks_metadata[ $block_name ]['selector'],
     741                                                $block_type->supports[ $key ]['__experimentalSelector']
     742                                        );
     743                                }
     744                        }
     745
     746                        if ( ! empty( $features ) ) {
     747                                static::$blocks_metadata[ $block_name ]['features'] = $features;
    686748                        }
    687749
    … …  
    811873
    812874                if ( in_array( 'styles', $types, true ) ) {
     875                        $root_block_key = array_search( static::ROOT_BLOCK_SELECTOR, array_column( $style_nodes, 'selector' ), true );
     876
     877                        if ( false !== $root_block_key ) {
     878                                $stylesheet .= $this->get_root_layout_rules( static::ROOT_BLOCK_SELECTOR, $style_nodes[ $root_block_key ] );
     879                        }
    813880                        $stylesheet .= $this->get_block_classes( $style_nodes );
     881                } elseif ( in_array( 'base-layout-styles', $types, true ) ) {
     882                        // Base layout styles are provided as part of `styles`, so only output separately if explicitly requested.
     883                        // For backwards compatibility, the Columns block is explicitly included, to support a different default gap value.
     884                        $base_styles_nodes = array(
     885                                array(
     886                                        'path'     => array( 'styles' ),
     887                                        'selector' => static::ROOT_BLOCK_SELECTOR,
     888                                ),
     889                                array(
     890                                        'path'     => array( 'styles', 'blocks', 'core/columns' ),
     891                                        'selector' => '.wp-block-columns',
     892                                        'name'     => 'core/columns',
     893                                ),
     894                        );
     895
     896                        foreach ( $base_styles_nodes as $base_style_node ) {
     897                                $stylesheet .= $this->get_layout_styles( $base_style_node );
     898                        }
    814899                }
    815900
    … …  
    885970         *              and no longer returns preset classes.
    886971         *              Removed the `$setting_nodes` parameter.
     972         * @since 6.1.0 Moved most internal logic to `get_styles_for_block()`.
    887973         *
    888974         * @param array $style_nodes Nodes with styles.
    … …  
    899985                }
    900986
     987                return $block_rules;
     988        }
     989
     990        /**
     991         * Get the CSS layout rules for a particular block from theme.json layout definitions.
     992         *
     993         * @since 6.1.0
     994         *
     995         * @param array $block_metadata Metadata about the block to get styles for.
     996         *
     997         * @return string Layout styles for the block.
     998         */
     999        protected function get_layout_styles( $block_metadata ) {
     1000                $block_rules = '';
     1001                $block_type  = null;
     1002
     1003                // Skip outputting layout styles if explicitly disabled.
     1004                if ( current_theme_supports( 'disable-layout-styles' ) ) {
     1005                        return $block_rules;
     1006                }
     1007
     1008                if ( isset( $block_metadata['name'] ) ) {
     1009                        $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_metadata['name'] );
     1010                        if ( ! block_has_support( $block_type, array( '__experimentalLayout' ), false ) ) {
     1011                                return $block_rules;
     1012                        }
     1013                }
     1014
     1015                $selector                 = isset( $block_metadata['selector'] ) ? $block_metadata['selector'] : '';
     1016                $has_block_gap_support    = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
     1017                $has_fallback_gap_support = ! $has_block_gap_support; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback gap styles support.
     1018                $node                     = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
     1019                $layout_definitions       = _wp_array_get( $this->theme_json, array( 'settings', 'layout', 'definitions' ), array() );
     1020                $layout_selector_pattern  = '/^[a-zA-Z0-9\-\.\ *+>:\(\)]*$/'; // Allow alphanumeric classnames, spaces, wildcard, sibling, child combinator and pseudo class selectors.
     1021
     1022                // Gap styles will only be output if the theme has block gap support, or supports a fallback gap.
     1023                // Default layout gap styles will be skipped for themes that do not explicitly opt-in to blockGap with a `true` or `false` value.
     1024                if ( $has_block_gap_support || $has_fallback_gap_support ) {
     1025                        $block_gap_value = null;
     1026                        // Use a fallback gap value if block gap support is not available.
     1027                        if ( ! $has_block_gap_support ) {
     1028                                $block_gap_value = static::ROOT_BLOCK_SELECTOR === $selector ? '0.5em' : null;
     1029                                if ( ! empty( $block_type ) ) {
     1030                                        $block_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), null );
     1031                                }
     1032                        } else {
     1033                                $block_gap_value = static::get_property_value( $node, array( 'spacing', 'blockGap' ) );
     1034                        }
     1035
     1036                        // Support split row / column values and concatenate to a shorthand value.
     1037                        if ( is_array( $block_gap_value ) ) {
     1038                                if ( isset( $block_gap_value['top'] ) && isset( $block_gap_value['left'] ) ) {
     1039                                        $gap_row         = static::get_property_value( $node, array( 'spacing', 'blockGap', 'top' ) );
     1040                                        $gap_column      = static::get_property_value( $node, array( 'spacing', 'blockGap', 'left' ) );
     1041                                        $block_gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column;
     1042                                } else {
     1043                                        // Skip outputting gap value if not all sides are provided.
     1044                                        $block_gap_value = null;
     1045                                }
     1046                        }
     1047
     1048                        // If the block should have custom gap, add the gap styles.
     1049                        if ( null !== $block_gap_value && false !== $block_gap_value && '' !== $block_gap_value ) {
     1050                                foreach ( $layout_definitions as $layout_definition_key => $layout_definition ) {
     1051                                        // Allow outputting fallback gap styles for flex layout type when block gap support isn't available.
     1052                                        if ( ! $has_block_gap_support && 'flex' !== $layout_definition_key ) {
     1053                                                continue;
     1054                                        }
     1055
     1056                                        $class_name    = sanitize_title( _wp_array_get( $layout_definition, array( 'className' ), false ) );
     1057                                        $spacing_rules = _wp_array_get( $layout_definition, array( 'spacingStyles' ), array() );
     1058
     1059                                        if (
     1060                                                ! empty( $class_name ) &&
     1061                                                ! empty( $spacing_rules )
     1062                                        ) {
     1063                                                foreach ( $spacing_rules as $spacing_rule ) {
     1064                                                        $declarations = array();
     1065                                                        if (
     1066                                                                isset( $spacing_rule['selector'] ) &&
     1067                                                                preg_match( $layout_selector_pattern, $spacing_rule['selector'] ) &&
     1068                                                                ! empty( $spacing_rule['rules'] )
     1069                                                        ) {
     1070                                                                // Iterate over each of the styling rules and substitute non-string values such as `null` with the real `blockGap` value.
     1071                                                                foreach ( $spacing_rule['rules'] as $css_property => $css_value ) {
     1072                                                                        $current_css_value = is_string( $css_value ) ? $css_value : $block_gap_value;
     1073                                                                        if ( static::is_safe_css_declaration( $css_property, $current_css_value ) ) {
     1074                                                                                $declarations[] = array(
     1075                                                                                        'name'  => $css_property,
     1076                                                                                        'value' => $current_css_value,
     1077                                                                                );
     1078                                                                        }
     1079                                                                }
     1080
     1081                                                                if ( ! $has_block_gap_support ) {
     1082                                                                        // For fallback gap styles, use lower specificity, to ensure styles do not unintentionally override theme styles.
     1083                                                                        $format          = static::ROOT_BLOCK_SELECTOR === $selector ? ':where(.%2$s%3$s)' : ':where(%1$s.%2$s%3$s)';
     1084                                                                        $layout_selector = sprintf(
     1085                                                                                $format,
     1086                                                                                $selector,
     1087                                                                                $class_name,
     1088                                                                                $spacing_rule['selector']
     1089                                                                        );
     1090                                                                } else {
     1091                                                                        $format          = static::ROOT_BLOCK_SELECTOR === $selector ? '%s .%s%s' : '%s.%s%s';
     1092                                                                        $layout_selector = sprintf(
     1093                                                                                $format,
     1094                                                                                $selector,
     1095                                                                                $class_name,
     1096                                                                                $spacing_rule['selector']
     1097                                                                        );
     1098                                                                }
     1099                                                                $block_rules .= static::to_ruleset( $layout_selector, $declarations );
     1100                                                        }
     1101                                                }
     1102                                        }
     1103                                }
     1104                        }
     1105                }
     1106
     1107                // Output base styles.
     1108                if (
     1109                        static::ROOT_BLOCK_SELECTOR === $selector
     1110                ) {
     1111                        $valid_display_modes = array( 'block', 'flex', 'grid' );
     1112                        foreach ( $layout_definitions as $layout_definition ) {
     1113                                $class_name       = sanitize_title( _wp_array_get( $layout_definition, array( 'className' ), false ) );
     1114                                $base_style_rules = _wp_array_get( $layout_definition, array( 'baseStyles' ), array() );
     1115
     1116                                if (
     1117                                        ! empty( $class_name ) &&
     1118                                        ! empty( $base_style_rules )
     1119                                ) {
     1120                                        // Output display mode. This requires special handling as `display` is not exposed in `safe_style_css_filter`.
     1121                                        if (
     1122                                                ! empty( $layout_definition['displayMode'] ) &&
     1123                                                is_string( $layout_definition['displayMode'] ) &&
     1124                                                in_array( $layout_definition['displayMode'], $valid_display_modes, true )
     1125                                        ) {
     1126                                                $layout_selector = sprintf(
     1127                                                        '%s .%s',
     1128                                                        $selector,
     1129                                                        $class_name
     1130                                                );
     1131                                                $block_rules    .= static::to_ruleset(
     1132                                                        $layout_selector,
     1133                                                        array(
     1134                                                                array(
     1135                                                                        'name'  => 'display',
     1136                                                                        'value' => $layout_definition['displayMode'],
     1137                                                                ),
     1138                                                        )
     1139                                                );
     1140                                        }
     1141
     1142                                        foreach ( $base_style_rules as $base_style_rule ) {
     1143                                                $declarations = array();
     1144
     1145                                                if (
     1146                                                        isset( $base_style_rule['selector'] ) &&
     1147                                                        preg_match( $layout_selector_pattern, $base_style_rule['selector'] ) &&
     1148                                                        ! empty( $base_style_rule['rules'] )
     1149                                                ) {
     1150                                                        foreach ( $base_style_rule['rules'] as $css_property => $css_value ) {
     1151                                                                if ( static::is_safe_css_declaration( $css_property, $css_value ) ) {
     1152                                                                        $declarations[] = array(
     1153                                                                                'name'  => $css_property,
     1154                                                                                'value' => $css_value,
     1155                                                                        );
     1156                                                                }
     1157                                                        }
     1158
     1159                                                        $layout_selector = sprintf(
     1160                                                                '%s .%s%s',
     1161                                                                $selector,
     1162                                                                $class_name,
     1163                                                                $base_style_rule['selector']
     1164                                                        );
     1165                                                        $block_rules    .= static::to_ruleset( $layout_selector, $declarations );
     1166                                                }
     1167                                        }
     1168                                }
     1169                        }
     1170                }
    9011171                return $block_rules;
    9021172        }
    … …  
    13281598         * @since 5.8.0
    13291599         * @since 5.9.0 Added the `$settings` and `$properties` parameters.
    1330          * @since 6.1.0 Added the `$theme_json` parameter.
    1331          *
    1332          * @param array $styles    Styles to process.
    1333          * @param array $settings  Theme settings.
    1334          * @param array $properties Properties metadata.
    1335          * @param array $theme_json Theme JSON array.
    1336          * @return array Returns the modified $declarations.
    1337          */
    1338         protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) {
     1600         * @since 6.1.0 Added `$theme_json`, `$selector`, and `$use_root_padding` parameters.
     1601         *
     1602         * @param array   $styles Styles to process.
     1603         * @param array   $settings Theme settings.
     1604         * @param array   $properties Properties metadata.
     1605         * @param array   $theme_json Theme JSON array.
     1606         * @param string  $selector The style block selector.
     1607         * @param boolean $use_root_padding Whether to add custom properties at root level.
     1608         * @return array  Returns the modified $declarations.
     1609         */
     1610        protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null, $selector = null, $use_root_padding = null ) {
    13391611                if ( null === $properties ) {
    13401612                        $properties = static::PROPERTIES_METADATA;
    … …  
    13461618                }
    13471619
     1620                $root_variable_duplicates = array();
     1621
    13481622                foreach ( $properties as $css_property => $value_path ) {
    13491623                        $value = static::get_property_value( $styles, $value_path, $theme_json );
     1624
     1625                        if ( str_starts_with( $css_property, '--wp--style--root--' ) && ( static::ROOT_BLOCK_SELECTOR !== $selector || ! $use_root_padding ) ) {
     1626                                continue;
     1627                        }
     1628                        // Root-level padding styles don't currently support strings with CSS shorthand values.
     1629                        // This may change: https://github.com/WordPress/gutenberg/issues/40132.
     1630                        if ( '--wp--style--root--padding' === $css_property && is_string( $value ) ) {
     1631                                continue;
     1632                        }
     1633
     1634                        if ( str_starts_with( $css_property, '--wp--style--root--' ) && $use_root_padding ) {
     1635                                $root_variable_duplicates[] = substr( $css_property, strlen( '--wp--style--root--' ) );
     1636                        }
    13501637
    13511638                        // Look up protected properties, keyed by value path.
    … …  
    13731660                }
    13741661
     1662                // If a variable value is added to the root, the corresponding property should be removed.
     1663                foreach ( $root_variable_duplicates as $duplicate ) {
     1664                        $discard = array_search( $duplicate, array_column( $declarations, 'name' ), true );
     1665                        if ( is_numeric( $discard ) ) {
     1666                                array_splice( $declarations, $discard, 1 );
     1667                        }
     1668                }
     1669
    13751670                return $declarations;
    13761671        }
    … …  
    13971692         */
    13981693        protected static function get_property_value( $styles, $path, $theme_json = null ) {
    1399                 $value = _wp_array_get( $styles, $path, '' );
     1694                $value = _wp_array_get( $styles, $path );
    14001695
    14011696                /*
    … …  
    14301725                }
    14311726
    1432                 if ( '' === $value || is_array( $value ) ) {
     1727                if ( is_array( $value ) ) {
    14331728                        return $value;
    14341729                }
    … …  
    16231918                        }
    16241919
     1920                        $feature_selectors = null;
     1921                        if ( isset( $selectors[ $name ]['features'] ) ) {
     1922                                $feature_selectors = $selectors[ $name ]['features'];
     1923                        }
     1924
    16251925                        $nodes[] = array(
    16261926                                'name'     => $name,
    … …  
    16281928                                'selector' => $selector,
    16291929                                'duotone'  => $duotone_selector,
     1930                                'features' => $feature_selectors,
    16301931                        );
    16311932
    … …  
    16601961         * @since 6.1.0
    16611962         *
    1662          * @param array $block_metadata Meta data about the block to get styles for.
     1963         * @param array $block_metadata Metadata about the block to get styles for.
     1964         *
    16631965         * @return array Styles for the block.
    16641966         */
    16651967        public function get_styles_for_block( $block_metadata ) {
    1666 
    1667                 $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
    1668 
    1669                 $selector = $block_metadata['selector'];
    1670                 $settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
     1968                $node             = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
     1969                $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];
     1970                $selector         = $block_metadata['selector'];
     1971                $settings         = _wp_array_get( $this->theme_json, array( 'settings' ) );
     1972
     1973                /*
     1974                 * Process style declarations for block support features the current
     1975                 * block contains selectors for. Values for a feature with a custom
     1976                 * selector are filtered from the theme.json node before it is
     1977                 * processed as normal.
     1978                */
     1979                $feature_declarations = array();
     1980
     1981                if ( ! empty( $block_metadata['features'] ) ) {
     1982                        foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) {
     1983                                if ( ! empty( $node[ $feature_name ] ) ) {
     1984                                        // Create temporary node containing only the feature data
     1985                                        // to leverage existing `compute_style_properties` function.
     1986                                        $feature = array( $feature_name => $node[ $feature_name ] );
     1987                                        // Generate the feature's declarations only.
     1988                                        $new_feature_declarations = static::compute_style_properties( $feature, $settings, null, $this->theme_json );
     1989
     1990                                        // Merge new declarations with any that already exist for
     1991                                        // the feature selector. This may occur when multiple block
     1992                                        // support features use the same custom selector.
     1993                                        if ( isset( $feature_declarations[ $feature_selector ] ) ) {
     1994                                                $feature_declarations[ $feature_selector ] = array_merge( $feature_declarations[ $feature_selector ], $new_feature_declarations );
     1995                                        } else {
     1996                                                $feature_declarations[ $feature_selector ] = $new_feature_declarations;
     1997                                        }
     1998                                        // Remove the feature from the block's node now the
     1999                                        // styles will be included under the feature level selector.
     2000                                        unset( $node[ $feature_name ] );
     2001                                }
     2002                        }
     2003                }
    16712004
    16722005                /*
    … …  
    17102043                        && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true )
    17112044                ) {
    1712                         $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json );
     2045                        $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json, $selector, $use_root_padding );
    17132046                } else {
    1714                         $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json );
     2047                        $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json, $selector, $use_root_padding );
    17152048                }
    17162049
    … …  
    17292062                }
    17302063
    1731                 /*
    1732                  * Reset default browser margin on the root body element.
    1733                  * This is set on the root selector **before** generating the ruleset
    1734                  * from the `theme.json`. This is to ensure that if the `theme.json` declares
    1735                  * `margin` in its `spacing` declaration for the `body` element then these
    1736                  * user-generated values take precedence in the CSS cascade.
    1737                  * @link https://github.com/WordPress/gutenberg/issues/36147.
    1738                  */
    1739                 if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
    1740                         $block_rules .= 'body { margin: 0; }';
    1741                 }
    1742 
    17432064                // 2. Generate and append the rules that use the general selector.
    17442065                $block_rules .= static::to_ruleset( $selector, $declarations );
    … …  
    17502071                }
    17512072
    1752                 if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
    1753                         $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
    1754                         $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
    1755                         $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
    1756 
    1757                         $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
    1758                         if ( $has_block_gap_support ) {
    1759                                 $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
    1760                                 $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
    1761                         }
     2073                // 4. Generate Layout block gap styles.
     2074                if (
     2075                        static::ROOT_BLOCK_SELECTOR !== $selector &&
     2076                        ! empty( $block_metadata['name'] )
     2077                ) {
     2078                        $block_rules .= $this->get_layout_styles( $block_metadata );
     2079                }
     2080
     2081                // 5. Generate and append the feature level rulesets.
     2082                foreach ( $feature_declarations as $feature_selector => $individual_feature_declarations ) {
     2083                        $block_rules .= static::to_ruleset( $feature_selector, $individual_feature_declarations );
    17622084                }
    17632085
    17642086                return $block_rules;
     2087        }
     2088
     2089        /**
     2090         * Outputs the CSS for layout rules on the root.
     2091         *
     2092         * @since 6.1.0
     2093         *
     2094         * @param string $selector The root node selector.
     2095         * @param array  $block_metadata The metadata for the root block.
     2096         * @return string The additional root rules CSS.
     2097         */
     2098        public function get_root_layout_rules( $selector, $block_metadata ) {
     2099                $css              = '';
     2100                $settings         = _wp_array_get( $this->theme_json, array( 'settings' ) );
     2101                $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];
     2102
     2103                /*
     2104                * Reset default browser margin on the root body element.
     2105                * This is set on the root selector **before** generating the ruleset
     2106                * from the `theme.json`. This is to ensure that if the `theme.json` declares
     2107                * `margin` in its `spacing` declaration for the `body` element then these
     2108                * user-generated values take precedence in the CSS cascade.
     2109                * @link https://github.com/WordPress/gutenberg/issues/36147.
     2110                */
     2111                $css .= 'body { margin: 0;';
     2112
     2113                /*
     2114                * If there are content and wide widths in theme.json, output them
     2115                * as custom properties on the body element so all blocks can use them.
     2116                */
     2117                if ( isset( $settings['layout']['contentSize'] ) || isset( $settings['layout']['wideSize'] ) ) {
     2118                        $content_size = isset( $settings['layout']['contentSize'] ) ? $settings['layout']['contentSize'] : $settings['layout']['wideSize'];
     2119                        $content_size = static::is_safe_css_declaration( 'max-width', $content_size ) ? $content_size : 'initial';
     2120                        $wide_size    = isset( $settings['layout']['wideSize'] ) ? $settings['layout']['wideSize'] : $settings['layout']['contentSize'];
     2121                        $wide_size    = static::is_safe_css_declaration( 'max-width', $wide_size ) ? $wide_size : 'initial';
     2122                        $css         .= '--wp--style--global--content-size: ' . $content_size . ';';
     2123                        $css         .= '--wp--style--global--wide-size: ' . $wide_size . ';';
     2124                }
     2125
     2126                $css .= ' }';
     2127
     2128                if ( $use_root_padding ) {
     2129                        // Top and bottom padding are applied to the outer block container.
     2130                        $css .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }';
     2131                        // Right and left padding are applied to the first container with `.has-global-padding` class.
     2132                        $css .= '.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }';
     2133                        // Nested containers with `.has-global-padding` class do not get padding.
     2134                        $css .= '.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }';
     2135                        // Alignfull children of the container with left and right padding have negative margins so they can still be full width.
     2136                        $css .= '.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }';
     2137                        // The above rule is negated for alignfull children of nested containers.
     2138                        $css .= '.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }';
     2139                        // Some of the children of alignfull blocks without content width should also get padding: text blocks and non-alignfull container blocks.
     2140                        $css .= '.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }';
     2141                        // The above rule also has to be negated for blocks inside nested `.has-global-padding` blocks.
     2142                        $css .= '.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }';
     2143                }
     2144
     2145                $css .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
     2146                $css .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
     2147                $css .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
     2148
     2149                $block_gap_value       = _wp_array_get( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ), '0.5em' );
     2150                $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
     2151                if ( $has_block_gap_support ) {
     2152                        $block_gap_value = static::get_property_value( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ) );
     2153                        $css            .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
     2154                        $css            .= ".wp-site-blocks > * + * { margin-block-start: $block_gap_value; }";
     2155
     2156                        // For backwards compatibility, ensure the legacy block gap CSS variable is still available.
     2157                        $css .= "$selector { --wp--style--block-gap: $block_gap_value; }";
     2158                }
     2159                $css .= $this->get_layout_styles( $block_metadata );
     2160
     2161                return $css;
    17652162        }
    17662163
  • trunk/src/wp-includes/global-styles-and-settings.php

    r54118 r54159  
    108108        $supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support();
    109109        if ( empty( $types ) && ! $supports_theme_json ) {
    110                 $types = array( 'variables', 'presets' );
     110                $types = array( 'variables', 'presets', 'base-layout-styles' );
    111111        } elseif ( empty( $types ) ) {
    112112                $types = array( 'variables', 'styles', 'presets' );
  • trunk/src/wp-includes/theme.json

    r53134 r54159  
    33        "settings": {
    44                "appearanceTools": false,
     5                "useRootPaddingAwareAlignments": false,
    56                "border": {
    67                        "color": false,
    … …  
    1314                        "custom": true,
    1415                        "customDuotone": true,
    15                         "customGradient": true,
    16                         "defaultDuotone": true,
     16                        "customGradient": true,
     17                        "defaultDuotone": true,
    1718                        "defaultGradients": true,
    1819                        "defaultPalette": true,
    … …  
    185186                        ],
    186187                        "text": true
     188                },
     189                "layout": {
     190                        "definitions": {
     191                                "default": {
     192                                        "name": "default",
     193                                        "slug": "flow",
     194                                        "className": "is-layout-flow",
     195                                        "baseStyles": [
     196                                                {
     197                                                        "selector": " > .alignleft",
     198                                                        "rules": {
     199                                                                "float": "left",
     200                                                                "margin-inline-start": "0",
     201                                                                "margin-inline-end": "2em"
     202                                                        }
     203                                                },
     204                                                {
     205                                                        "selector": " > .alignright",
     206                                                        "rules": {
     207                                                                "float": "right",
     208                                                                "margin-inline-start": "2em",
     209                                                                "margin-inline-end": "0"
     210                                                        }
     211                                                },
     212                                                {
     213                                                        "selector": " > .aligncenter",
     214                                                        "rules": {
     215                                                                "margin-left": "auto !important",
     216                                                                "margin-right": "auto !important"
     217                                                        }
     218                                                }
     219                                        ],
     220                                        "spacingStyles": [
     221                                                {
     222                                                        "selector": " > *",
     223                                                        "rules": {
     224                                                                "margin-block-start": "0",
     225                                                                "margin-block-end": "0"
     226                                                        }
     227                                                },
     228                                                {
     229                                                        "selector": " > * + *",
     230                                                        "rules": {
     231                                                                "margin-block-start": null,
     232                                                                "margin-block-end": "0"
     233                                                        }
     234                                                }
     235                                        ]
     236                                },
     237                                "constrained": {
     238                                        "name": "constrained",
     239                                        "slug": "constrained",
     240                                        "className": "is-layout-constrained",
     241                                        "baseStyles": [
     242                                                {
     243                                                        "selector": " > .alignleft",
     244                                                        "rules": {
     245                                                                "float": "left",
     246                                                                "margin-inline-start": "0",
     247                                                                "margin-inline-end": "2em"
     248                                                        }
     249                                                },
     250                                                {
     251                                                        "selector": " > .alignright",
     252                                                        "rules": {
     253                                                                "float": "right",
     254                                                                "margin-inline-start": "2em",
     255                                                                "margin-inline-end": "0"
     256                                                        }
     257                                                },
     258                                                {
     259                                                        "selector": " > .aligncenter",
     260                                                        "rules": {
     261                                                                "margin-left": "auto !important",
     262                                                                "margin-right": "auto !important"
     263                                                        }
     264                                                },
     265                                                {
     266                                                        "selector": " > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
     267                                                        "rules": {
     268                                                                "max-width": "var(--wp--style--global--content-size)",
     269                                                                "margin-left": "auto !important",
     270                                                                "margin-right": "auto !important"
     271                                                        }
     272                                                },
     273                                                {
     274                                                        "selector": " > .alignwide",
     275                                                        "rules": {
     276                                                                "max-width": "var(--wp--style--global--wide-size)"
     277                                                        }
     278                                                }
     279                                        ],
     280                                        "spacingStyles": [
     281                                                {
     282                                                        "selector": " > *",
     283                                                        "rules": {
     284                                                                "margin-block-start": "0",
     285                                                                "margin-block-end": "0"
     286                                                        }
     287                                                },
     288                                                {
     289                                                        "selector": " > * + *",
     290                                                        "rules": {
     291                                                                "margin-block-start": null,
     292                                                                "margin-block-end": "0"
     293                                                        }
     294                                                }
     295                                        ]
     296                                },
     297                                "flex": {
     298                                        "name": "flex",
     299                                        "slug": "flex",
     300                                        "className": "is-layout-flex",
     301                                        "displayMode": "flex",
     302                                        "baseStyles": [
     303                                                {
     304                                                        "selector": "",
     305                                                        "rules": {
     306                                                                "flex-wrap": "wrap",
     307                                                                "align-items": "center"
     308                                                        }
     309                                                },
     310                                                {
     311                                                        "selector": " > *",
     312                                                        "rules": {
     313                                                                "margin": "0"
     314                                                        }
     315                                                }
     316                                        ],
     317                                        "spacingStyles": [
     318                                                {
     319                                                        "selector": "",
     320                                                        "rules": {
     321                                                                "gap": null
     322                                                        }
     323                                                }
     324                                        ]
     325                                }
     326                        }
    187327                },
    188328                "spacing": {
    … …  
    190330                        "margin": false,
    191331                        "padding": false,
    192                         "units": [ "px", "em", "rem", "vh", "vw", "%" ]
     332                        "customSpacingSize": true,
     333                        "units": [ "px", "em", "rem", "vh", "vw", "%" ],
     334                        "spacingScale": {
     335                                "operator": "*",
     336                                "increment": 1.5,
     337                                "steps": 7,
     338                                "mediumStep": 1.5,
     339                                "unit": "rem"
     340                        }
    193341                },
    194342                "typography": {
    … …  
    241389        },
    242390        "styles": {
    243                 "spacing": { "blockGap": "24px" }
     391                "elements": {
     392                        "button": {
     393                                "color": {
     394                                        "text": "#fff",
     395                                        "background": "#32373c"
     396                                },
     397                                "spacing": {
     398                                        "padding": "calc(0.667em + 2px) calc(1.333em + 2px)"
     399                                },
     400                                "typography": {
     401                                        "fontSize": "inherit",
     402                                        "fontFamily": "inherit",
     403                                        "lineHeight": "inherit",
     404                                        "textDecoration": "none"
     405                                },
     406                                "border": {
     407                                        "width": "0"
     408                                }
     409                        },
     410                        "link": {
     411                                "typography": {
     412                                        "textDecoration": "underline"
     413                                }
     414                        }
     415                },
     416                "spacing": {
     417                        "blockGap": "24px",
     418                        "padding": {
     419                                "top": "0px",
     420                                "right": "0px",
     421                                "bottom": "0px",
     422                                "left": "0px"
     423                        }
     424                }
    244425        }
    245426}
  • trunk/src/wp-includes/theme.php

    r53842 r54159  
    40284028        );
    40294029        register_theme_feature(
     4030                'disable-layout-styles',
     4031                array(
     4032                        'description'  => __( 'Whether the theme disables generated layout styles.' ),
     4033                        'show_in_rest' => true,
     4034                )
     4035        );
     4036        register_theme_feature(
    40304037                'editor-color-palette',
    40314038                array(
  • trunk/tests/phpunit/tests/blocks/editor.php

    r54088 r54159  
    203203                $settings = get_default_block_editor_settings();
    204204
    205                 $this->assertCount( 18, $settings );
     205                $this->assertCount( 19, $settings );
    206206                $this->assertFalse( $settings['alignWide'] );
    207207                $this->assertIsArray( $settings['allowedMimeTypes'] );
    … …  
    250250                $this->assertFalse( $settings['disableCustomFontSizes'] );
    251251                $this->assertFalse( $settings['disableCustomGradients'] );
     252                $this->assertFalse( $settings['disableLayoutStyles'] );
    252253                $this->assertFalse( $settings['enableCustomLineHeight'] );
    253254                $this->assertFalse( $settings['enableCustomSpacing'] );
  • trunk/tests/phpunit/tests/rest-api/rest-themes-controller.php

    r54058 r54159  
    397397                $this->assertArrayHasKey( 'disable-custom-font-sizes', $theme_supports );
    398398                $this->assertArrayHasKey( 'disable-custom-gradients', $theme_supports );
     399                $this->assertArrayHasKey( 'disable-layout-styles', $theme_supports );
    399400                $this->assertArrayHasKey( 'editor-color-palette', $theme_supports );
    400401                $this->assertArrayHasKey( 'editor-font-sizes', $theme_supports );
    … …  
    407408                $this->assertArrayHasKey( 'title-tag', $theme_supports );
    408409                $this->assertArrayHasKey( 'wp-block-styles', $theme_supports );
    409                 $this->assertCount( 21, $theme_supports );
     410                $this->assertCount( 22, $theme_supports );
    410411        }
    411412
  • trunk/tests/phpunit/tests/theme/wpThemeJson.php

    r54118 r54159  
    424424                );
    425425
    426                 $expected = 'body { margin: 0; }body{--wp--style--block-gap: 1em;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
     426                $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1em; }body { --wp--style--block-gap: 1em; }';
    427427                $this->assertSame( $expected, $theme_json->get_stylesheet() );
    428428                $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
    … …  
    545545                                                ),
    546546                                        ),
     547                                        'spacing'  => array(
     548                                                'blockGap' => '24px',
     549                                        ),
    547550                                ),
    548551                                'misc'     => 'value',
    … …  
    551554
    552555                $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}';
    553                 $styles    = 'body { margin: 0; }body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}';
     556                $styles    = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}';
    554557                $presets   = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}';
    555558                $all       = $variables . $styles . $presets;
    … …  
    26762679                                                'core/group' => array(
    26772680                                                        'spacing' => array(
    2678                                                                 'margin'   => 'valid value',
    2679                                                                 'blockGap' => 'invalid value',
     2681                                                                'margin'  => 'valid value',
     2682                                                                'display' => 'none',
    26802683                                                        ),
    26812684                                                ),
    … …  
    29902993                );
    29912994
    2992                 $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #000000;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}';
     2995                $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;color: #000000;}.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}';
    29932996                $this->assertSame( $expected, $theme_json->get_stylesheet() );
    29942997        }
    … …  
    30223025                );
    30233026
    3024                 $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}';
     3027                $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';
    30253028                $this->assertSame( $expected, $theme_json->get_stylesheet() );
    30263029        }
    … …  
    30543057                );
    30553058
    3056                 $expected = 'body { margin: 0; }body{background-color: #ffffff;color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-element-button, .wp-block-button__link{color: #ffffff;}';
     3059                $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';
    30573060                $this->assertSame( $expected, $theme_json->get_stylesheet() );
    30583061        }
    … …  
    30783081                );
    30793082
    3080                 $expected = 'body { margin: 0; }body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
     3083                $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;}';
    30813084                $this->assertSame( $expected, $theme_json->get_stylesheet() );
    30823085        }
    30833086
     3087        /**
     3088         * @dataProvider data_get_layout_definitions
     3089         *
     3090         * @ticket 56467
     3091         *
     3092         * @param array $layout_definitions Layout definitions as stored in core theme.json.
     3093         */
     3094        public function test_get_stylesheet_generates_layout_styles( $layout_definitions ) {
     3095                $theme_json = new WP_Theme_JSON(
     3096                        array(
     3097                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3098                                'settings' => array(
     3099                                        'layout'  => array(
     3100                                                'definitions' => $layout_definitions,
     3101                                        ),
     3102                                        'spacing' => array(
     3103                                                'blockGap' => true,
     3104                                        ),
     3105                                ),
     3106                                'styles'   => array(
     3107                                        'spacing' => array(
     3108                                                'blockGap' => '1em',
     3109                                        ),
     3110                                ),
     3111                        ),
     3112                        'default'
     3113                );
     3114
     3115                // Results also include root site blocks styles.
     3116                $this->assertSame(
     3117                        'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1em; }body { --wp--style--block-gap: 1em; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1em;margin-block-end: 0;}body .is-layout-flex{gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}',
     3118                        $theme_json->get_stylesheet( array( 'styles' ) )
     3119                );
     3120        }
     3121
     3122        /**
     3123         * @dataProvider data_get_layout_definitions
     3124         *
     3125         * @ticket 56467
     3126         *
     3127         * @param array $layout_definitions Layout definitions as stored in core theme.json.
     3128         */
     3129        public function test_get_stylesheet_generates_layout_styles_with_spacing_presets( $layout_definitions ) {
     3130                $theme_json = new WP_Theme_JSON(
     3131                        array(
     3132                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3133                                'settings' => array(
     3134                                        'layout'  => array(
     3135                                                'definitions' => $layout_definitions,
     3136                                        ),
     3137                                        'spacing' => array(
     3138                                                'blockGap' => true,
     3139                                        ),
     3140                                ),
     3141                                'styles'   => array(
     3142                                        'spacing' => array(
     3143                                                'blockGap' => 'var:preset|spacing|60',
     3144                                        ),
     3145                                ),
     3146                        ),
     3147                        'default'
     3148                );
     3149
     3150                // Results also include root site blocks styles.
     3151                $this->assertSame(
     3152                        'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var(--wp--preset--spacing--60); }body { --wp--style--block-gap: var(--wp--preset--spacing--60); }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}body .is-layout-flex{gap: var(--wp--preset--spacing--60);}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}',
     3153                        $theme_json->get_stylesheet( array( 'styles' ) )
     3154                );
     3155        }
     3156
     3157        /**
     3158         * @dataProvider data_get_layout_definitions
     3159         *
     3160         * @ticket 56467
     3161         *
     3162         * @param array $layout_definitions Layout definitions as stored in core theme.json.
     3163         */
     3164        public function test_get_stylesheet_generates_fallback_gap_layout_styles( $layout_definitions ) {
     3165                $theme_json = new WP_Theme_JSON(
     3166                        array(
     3167                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3168                                'settings' => array(
     3169                                        'layout'  => array(
     3170                                                'definitions' => $layout_definitions,
     3171                                        ),
     3172                                        'spacing' => array(
     3173                                                'blockGap' => null,
     3174                                        ),
     3175                                ),
     3176                                'styles'   => array(
     3177                                        'spacing' => array(
     3178                                                'blockGap' => '1em',
     3179                                        ),
     3180                                ),
     3181                        ),
     3182                        'default'
     3183                );
     3184                $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) );
     3185
     3186                // Results also include root site blocks styles.
     3187                $this->assertSame(
     3188                        'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}',
     3189                        $stylesheet
     3190                );
     3191        }
     3192
     3193        /**
     3194         * @dataProvider data_get_layout_definitions
     3195         *
     3196         * @ticket 56467
     3197         *
     3198         * @param array $layout_definitions Layout definitions as stored in core theme.json.
     3199         */
     3200        public function test_get_stylesheet_generates_base_fallback_gap_layout_styles( $layout_definitions ) {
     3201                $theme_json = new WP_Theme_JSON(
     3202                        array(
     3203                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3204                                'settings' => array(
     3205                                        'layout'  => array(
     3206                                                'definitions' => $layout_definitions,
     3207                                        ),
     3208                                        'spacing' => array(
     3209                                                'blockGap' => null,
     3210                                        ),
     3211                                ),
     3212                        ),
     3213                        'default'
     3214                );
     3215                $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) );
     3216
     3217                // Note the `base-layout-styles` includes a fallback gap for the Columns block for backwards compatibility.
     3218                $this->assertSame(
     3219                        ':where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}',
     3220                        $stylesheet
     3221                );
     3222        }
     3223
     3224        /**
     3225         * @dataProvider data_get_layout_definitions
     3226         *
     3227         * @ticket 56467
     3228         *
     3229         * @param array $layout_definitions Layout definitions as stored in core theme.json.
     3230         */
     3231        public function test_get_stylesheet_skips_layout_styles( $layout_definitions ) {
     3232                add_theme_support( 'disable-layout-styles' );
     3233                $theme_json = new WP_Theme_JSON(
     3234                        array(
     3235                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3236                                'settings' => array(
     3237                                        'layout'  => array(
     3238                                                'definitions' => $layout_definitions,
     3239                                        ),
     3240                                        'spacing' => array(
     3241                                                'blockGap' => null,
     3242                                        ),
     3243                                ),
     3244                        ),
     3245                        'default'
     3246                );
     3247                $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) );
     3248                remove_theme_support( 'disable-layout-styles' );
     3249
     3250                // All Layout styles should be skipped.
     3251                $this->assertSame(
     3252                        '',
     3253                        $stylesheet
     3254                );
     3255        }
     3256
     3257        /**
     3258         * @dataProvider data_get_layout_definitions
     3259         *
     3260         * @ticket 56467
     3261         *
     3262         * @param array $layout_definitions Layout definitions as stored in core theme.json.
     3263         */
     3264        public function test_get_stylesheet_generates_valid_block_gap_values_and_skips_null_or_false_values( $layout_definitions ) {
     3265                $theme_json = new WP_Theme_JSON(
     3266                        array(
     3267                                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     3268                                'settings' => array(
     3269                                        'layout'  => array(
     3270                                                'definitions' => $layout_definitions,
     3271                                        ),
     3272                                        'spacing' => array(
     3273                                                'blockGap' => true,
     3274                                        ),
     3275                                ),
     3276                                'styles'   => array(
     3277                                        'spacing' => array(
     3278                                                'blockGap' => '1rem',
     3279                                        ),
     3280                                        'blocks'  => array(
     3281                                                'core/post-content' => array(
     3282                                                        'color' => array(
     3283                                                                'text' => 'gray', // This value should not render block layout styles.
     3284                                                        ),
     3285                                                ),
     3286                                                'core/social-links' => array(
     3287                                                        'spacing' => array(
     3288                                                                'blockGap' => '0', // This value should render block layout gap as zero.
     3289                                                        ),
     3290                                                ),
     3291                                                'core/buttons'      => array(
     3292                                                        'spacing' => array(
     3293                                                                'blockGap' => 0, // This value should render block layout gap as zero.
     3294                                                        ),
     3295                                                ),
     3296                                                'core/columns'      => array(
     3297                                                        'spacing' => array(
     3298                                                                'blockGap' => false, // This value should be ignored. The block will use the global layout value.
     3299                                                        ),
     3300                                                ),
     3301                                        ),
     3302                                ),
     3303                        ),
     3304                        'default'
     3305                );
     3306
     3307                $this->assertEquals(
     3308                        'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1rem; }body { --wp--style--block-gap: 1rem; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1rem;margin-block-end: 0;}body .is-layout-flex{gap: 1rem;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}.wp-block-post-content{color: gray;}.wp-block-social-links.is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links.is-layout-flow > * + *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links.is-layout-flex{gap: 0;}.wp-block-buttons.is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons.is-layout-flow > * + *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons.is-layout-flex{gap: 0;}',
     3309                        $theme_json->get_stylesheet()
     3310                );
     3311        }
     3312
     3313        /**
     3314         * Data provider for layout tests.
     3315         *
     3316         * @ticket 56467
     3317         *
     3318         * @return array
     3319         */
     3320        public function data_get_layout_definitions() {
     3321                return array(
     3322                        'layout definitions' => array(
     3323                                array(
     3324                                        'default' => array(
     3325                                                'name'          => 'default',
     3326                                                'slug'          => 'flow',
     3327                                                'className'     => 'is-layout-flow',
     3328                                                'baseStyles'    => array(
     3329                                                        array(
     3330                                                                'selector' => ' > .alignleft',
     3331                                                                'rules'    => array(
     3332                                                                        'float'               => 'left',
     3333                                                                        'margin-inline-start' => '0',
     3334                                                                        'margin-inline-end'   => '2em',
     3335                                                                ),
     3336                                                        ),
     3337                                                        array(
     3338                                                                'selector' => ' > .alignright',
     3339                                                                'rules'    => array(
     3340                                                                        'float'               => 'right',
     3341                                                                        'margin-inline-start' => '2em',
     3342                                                                        'margin-inline-end'   => '0',
     3343                                                                ),
     3344                                                        ),
     3345                                                        array(
     3346                                                                'selector' => ' > .aligncenter',
     3347                                                                'rules'    => array(
     3348                                                                        'margin-left'  => 'auto !important',
     3349                                                                        'margin-right' => 'auto !important',
     3350                                                                ),
     3351                                                        ),
     3352                                                ),
     3353                                                'spacingStyles' => array(
     3354                                                        array(
     3355                                                                'selector' => ' > *',
     3356                                                                'rules'    => array(
     3357                                                                        'margin-block-start' => '0',
     3358                                                                        'margin-block-end'   => '0',
     3359                                                                ),
     3360                                                        ),
     3361                                                        array(
     3362                                                                'selector' => ' > * + *',
     3363                                                                'rules'    => array(
     3364                                                                        'margin-block-start' => null,
     3365                                                                        'margin-block-end'   => '0',
     3366                                                                ),
     3367                                                        ),
     3368                                                ),
     3369                                        ),
     3370                                        'flex'    => array(
     3371                                                'name'          => 'flex',
     3372                                                'slug'          => 'flex',
     3373                                                'className'     => 'is-layout-flex',
     3374                                                'displayMode'   => 'flex',
     3375                                                'baseStyles'    => array(
     3376                                                        array(
     3377                                                                'selector' => '',
     3378                                                                'rules'    => array(
     3379                                                                        'flex-wrap'   => 'wrap',
     3380                                                                        'align-items' => 'center',
     3381                                                                ),
     3382                                                        ),
     3383                                                ),
     3384                                                'spacingStyles' => array(
     3385                                                        array(
     3386                                                                'selector' => '',
     3387                                                                'rules'    => array(
     3388                                                                        'gap' => null,
     3389                                                                ),
     3390                                                        ),
     3391                                                ),
     3392                                        ),
     3393                                ),
     3394                        ),
     3395                );
     3396        }
     3397
     3398        /**
     3399         * @ticket 56467
     3400         */
     3401        function test_get_styles_for_block_with_padding_aware_alignments() {
     3402                $theme_json = new WP_Theme_JSON(
     3403                        array(
     3404                                'version'  => 2,
     3405                                'styles'   => array(
     3406                                        'spacing' => array(
     3407                                                'padding' => array(
     3408                                                        'top'    => '10px',
     3409                                                        'right'  => '12px',
     3410                                                        'bottom' => '10px',
     3411                                                        'left'   => '12px',
     3412                                                ),
     3413                                        ),
     3414                                ),
     3415                                'settings' => array(
     3416                                        'useRootPaddingAwareAlignments' => true,
     3417                                ),
     3418                        )
     3419                );
     3420
     3421                $metadata = array(
     3422                        'path'     => array(
     3423                                '0' => 'styles',
     3424                        ),
     3425                        'selector' => 'body',
     3426                );
     3427
     3428                $expected    = 'body { margin: 0; }.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{--wp--style--root--padding-top: 10px;--wp--style--root--padding-right: 12px;--wp--style--root--padding-bottom: 10px;--wp--style--root--padding-left: 12px;}';
     3429                $root_rules  = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata );
     3430                $style_rules = $theme_json->get_styles_for_block( $metadata );
     3431                $this->assertSame( $expected, $root_rules . $style_rules );
     3432        }
     3433
     3434        /**
     3435         * @ticket 56467
     3436         */
     3437        function test_get_styles_for_block_without_padding_aware_alignments() {
     3438                $theme_json = new WP_Theme_JSON(
     3439                        array(
     3440                                'version' => 2,
     3441                                'styles'  => array(
     3442                                        'spacing' => array(
     3443                                                'padding' => array(
     3444                                                        'top'    => '10px',
     3445                                                        'right'  => '12px',
     3446                                                        'bottom' => '10px',
     3447                                                        'left'   => '12px',
     3448                                                ),
     3449                                        ),
     3450                                ),
     3451                        )
     3452                );
     3453
     3454                $metadata = array(
     3455                        'path'     => array(
     3456                                '0' => 'styles',
     3457                        ),
     3458                        'selector' => 'body',
     3459                );
     3460
     3461                $expected    = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}';
     3462                $root_rules  = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata );
     3463                $style_rules = $theme_json->get_styles_for_block( $metadata );
     3464                $this->assertSame( $expected, $root_rules . $style_rules );
     3465        }
     3466
     3467        /**
     3468         * @ticket 56467
     3469         */
     3470        function test_get_styles_for_block_with_content_width() {
     3471                $theme_json = new WP_Theme_JSON(
     3472                        array(
     3473                                'version'  => 2,
     3474                                'settings' => array(
     3475                                        'layout' => array(
     3476                                                'contentSize' => '800px',
     3477                                                'wideSize'    => '1000px',
     3478                                        ),
     3479                                ),
     3480                        )
     3481                );
     3482
     3483                $metadata = array(
     3484                        'path'     => array(
     3485                                '0' => 'settings',
     3486                        ),
     3487                        'selector' => 'body',
     3488                );
     3489
     3490                $expected    = 'body { margin: 0;--wp--style--global--content-size: 800px;--wp--style--global--wide-size: 1000px; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
     3491                $root_rules  = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata );
     3492                $style_rules = $theme_json->get_styles_for_block( $metadata );
     3493                $this->assertSame( $expected, $root_rules . $style_rules );
     3494        }
    30843495}
Note: See TracChangeset for help on using the changeset viewer.