Make WordPress Core

Changeset 58264


Ignore:
Timestamp:
05/31/2024 05:47:23 AM (7 weeks ago)
Author:
noisysocks
Message:

Block Themes: Add section styling via extended block style variations

Provide users with the ability to style entire sections of a page without
having to tediously reapply the same sets of styles.

This is done by extending block style variations to apply to nested blocks.

See https://github.com/WordPress/gutenberg/pull/57908.

Fixes #61312.
Props aaronrobertshaw, talldanwp, ramonopoly, isabel_brison, andrewserong.

Location:
trunk
Files:
11 added
5 edited

Legend:

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

    r58263 r58264  
    702702    }
    703703
     704    /**
     705     * Determines if a supplied style variation matches the provided scope.
     706     *
     707     * For backwards compatibility, if a variation does not define any scope
     708     * related property, e.g. `blockTypes`, it is assumed to be a theme style
     709     * variation.
     710     *
     711     * @since 6.6.0
     712     *
     713     * @param array  $variation Theme.json shaped style variation object.
     714     * @param string $scope     Scope to check e.g. theme, block etc.
     715     *
     716     * @return boolean
     717     */
     718    private static function style_variation_has_scope( $variation, $scope ) {
     719        if ( 'block' === $scope ) {
     720            return isset( $variation['blockTypes'] );
     721        }
     722
     723        if ( 'theme' === $scope ) {
     724            return ! isset( $variation['blockTypes'] );
     725        }
     726
     727        return false;
     728    }
    704729
    705730    /**
     
    708733     * @since 6.0.0
    709734     * @since 6.2.0 Returns parent theme variations if theme is a child.
     735     * @since 6.6.0 Added configurable scope parameter to allow filtering
     736     *              theme.json partial files by the scope to which they
     737     *              can be applied e.g. theme vs block etc.
     738     *
     739     * @param string $scope The scope or type of style variation to retrieve e.g. theme, block etc.
    710740     *
    711741     * @return array
    712742     */
    713     public static function get_style_variations() {
     743    public static function get_style_variations( $scope = 'theme' ) {
    714744        $variation_files    = array();
    715745        $variations         = array();
     
    734764        foreach ( $variation_files as $path => $file ) {
    735765            $decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
    736             if ( is_array( $decoded_file ) ) {
     766            if ( is_array( $decoded_file ) && static::style_variation_has_scope( $decoded_file, $scope ) ) {
    737767                $translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
    738768                $variation  = ( new WP_Theme_JSON( $translated ) )->get_raw_data();
  • trunk/src/wp-includes/class-wp-theme-json.php

    r58245 r58264  
    347347     *              added the `customTemplates` and `templateParts` values.
    348348     * @since 6.3.0 Added the `description` value.
     349     * @since 6.6.0 Added `blockTypes` to support block style variation theme.json partials.
    349350     * @var string[]
    350351     */
    351352    const VALID_TOP_LEVEL_KEYS = array(
     353        'blockTypes',
    352354        'customTemplates',
    353355        'description',
     
    824826     * @since 5.9.0 Added the `$valid_block_names` and `$valid_element_name` parameters.
    825827     * @since 6.3.0 Added the `$valid_variations` parameter.
     828     * @since 6.6.0 Updated schema to allow extended block style variations.
    826829     *
    827830     * @param array $input               Structure to sanitize.
     
    882885        $schema_styles_blocks   = array();
    883886        $schema_settings_blocks = array();
     887
     888        /*
     889         * Generate a schema for blocks.
     890         * - Block styles can contain `elements` & `variations` definitions.
     891         * - Variations definitions cannot be nested.
     892         * - Variations can contain styles for inner `blocks`.
     893         * - Variation inner `blocks` styles can contain `elements`.
     894         *
     895         * As each variation needs a `blocks` schema but further nested
     896         * inner `blocks`, the overall schema will be generated in multiple passes.
     897         */
     898        foreach ( $valid_block_names as $block ) {
     899            $schema_settings_blocks[ $block ]           = static::VALID_SETTINGS;
     900            $schema_styles_blocks[ $block ]             = $styles_non_top_level;
     901            $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
     902        }
     903
     904        $block_style_variation_styles             = static::VALID_STYLES;
     905        $block_style_variation_styles['blocks']   = $schema_styles_blocks;
     906        $block_style_variation_styles['elements'] = $schema_styles_elements;
     907
    884908        foreach ( $valid_block_names as $block ) {
    885909            // Build the schema for each block style variation.
     
    898922            $schema_styles_variations = array();
    899923            if ( ! empty( $style_variation_names ) ) {
    900                 $schema_styles_variations = array_fill_keys( $style_variation_names, $styles_non_top_level );
    901             }
    902 
    903             $schema_settings_blocks[ $block ]             = static::VALID_SETTINGS;
    904             $schema_styles_blocks[ $block ]               = $styles_non_top_level;
    905             $schema_styles_blocks[ $block ]['elements']   = $schema_styles_elements;
     924                $schema_styles_variations = array_fill_keys( $style_variation_names, $block_style_variation_styles );
     925            }
     926
    906927            $schema_styles_blocks[ $block ]['variations'] = $schema_styles_variations;
    907928        }
     
    913934        $schema['settings']['blocks']                     = $schema_settings_blocks;
    914935        $schema['settings']['typography']['fontFamilies'] = static::schema_in_root_and_per_origin( static::FONT_FAMILY_SCHEMA );
     936
     937        /*
     938         * Shared block style variations can be registered from the theme.json data so we can't
     939         * validate them against pre-registered block style variations.
     940         */
     941        $schema['styles']['blocks']['variations'] = null;
    915942
    916943        // Remove anything that's not present in the schema.
     
    10171044     * @since 6.1.0 Added `features` key with block support feature level selectors.
    10181045     * @since 6.3.0 Refactored and stabilized selectors API.
     1046     * @since 6.6.0 Updated to include block style variations from the block styles registry.
    10191047     *
    10201048     * @return array Block metadata.
    10211049     */
    10221050    protected static function get_blocks_metadata() {
    1023         $registry = WP_Block_Type_Registry::get_instance();
    1024         $blocks   = $registry->get_all_registered();
     1051        $registry       = WP_Block_Type_Registry::get_instance();
     1052        $blocks         = $registry->get_all_registered();
     1053        $style_registry = WP_Block_Styles_Registry::get_instance();
    10251054
    10261055        // Is there metadata for all currently registered blocks?
    10271056        $blocks = array_diff_key( $blocks, static::$blocks_metadata );
    10281057        if ( empty( $blocks ) ) {
     1058            /*
     1059             * New block styles may have been registered within WP_Block_Styles_Registry.
     1060             * Update block metadata for any new block style variations.
     1061             */
     1062            $registered_styles = $style_registry->get_all_registered();
     1063            foreach ( static::$blocks_metadata as $block_name => $block_metadata ) {
     1064                if ( ! empty( $registered_styles[ $block_name ] ) ) {
     1065                    $style_selectors = $block_metadata['styleVariations'] ?? array();
     1066
     1067                    foreach ( $registered_styles[ $block_name ] as $block_style ) {
     1068                        if ( ! isset( $style_selectors[ $block_style['name'] ] ) ) {
     1069                            $style_selectors[ $block_style['name'] ] = static::get_block_style_variation_selector( $block_style['name'], $block_metadata['selector'] );
     1070                        }
     1071                    }
     1072
     1073                    static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
     1074                }
     1075            }
    10291076            return static::$blocks_metadata;
    10301077        }
     
    10611108
    10621109            // If the block has style variations, append their selectors to the block metadata.
     1110            $style_selectors = array();
    10631111            if ( ! empty( $block_type->styles ) ) {
    1064                 $style_selectors = array();
    10651112                foreach ( $block_type->styles as $style ) {
    10661113                    $style_selectors[ $style['name'] ] = static::get_block_style_variation_selector( $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
    10671114                }
     1115            }
     1116
     1117            // Block style variations can be registered through the WP_Block_Styles_Registry as well as block.json.
     1118            $registered_styles = $style_registry->get_registered_styles_for_block( $block_name );
     1119            foreach ( $registered_styles as $style ) {
     1120                $style_selectors[ $style['name'] ] = static::get_block_style_variation_selector( $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
     1121            }
     1122
     1123            if ( ! empty( $style_selectors ) ) {
    10681124                static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
    10691125            }
     
    11591215     * @since 5.9.0 Removed the `$type` parameter, added the `$types` and `$origins` parameters.
    11601216     * @since 6.3.0 Add fallback layout styles for Post Template when block gap support isn't available.
     1217     * @since 6.6.0 Added `skip_root_layout_styles` option to omit layout styles if desired.
    11611218     *
    11621219     * @param string[] $types   Types of styles to load. Will load all by default. It accepts:
     
    11661223     * @param string[] $origins A list of origins to include. By default it includes VALID_ORIGINS.
    11671224     * @param array    $options An array of options for now used for internal purposes only (may change without notice).
    1168      *                          The options currently supported are 'scope' that makes sure all style are scoped to a
    1169      *                          given selector, and root_selector which overwrites and forces a given selector to be
    1170      *                          used on the root node.
     1225     *                       The options currently supported are:
     1226     *                       - 'scope' that makes sure all style are scoped to a given selector
     1227     *                       - `root_selector` which overwrites and forces a given selector to be used on the root node
     1228     *                       - `skip_root_layout_styles` which omits root layout styles from the generated stylesheet.
    11711229     * @return string The resulting stylesheet.
    11721230     */
     
    12211279
    12221280        if ( in_array( 'styles', $types, true ) ) {
    1223             if ( false !== $root_style_key ) {
     1281            if ( false !== $root_style_key && empty( $options['skip_root_layout_styles'] ) ) {
    12241282                $stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] );
    12251283            }
     
    31153173     * @since 5.9.0
    31163174     * @since 6.3.2 Preserves global styles block variations when securing styles.
     3175     * @since 6.6.0 Updated to allow variation element styles.
    31173176     *
    31183177     * @param array $theme_json Structure to sanitize.
     
    31763235
    31773236                    $variation_output = static::remove_insecure_styles( $variation_input );
     3237
     3238                    // Process a variation's elements and element pseudo selector styles.
     3239                    if ( isset( $variation_input['elements'] ) ) {
     3240                        foreach ( $valid_element_names as $element_name ) {
     3241                            $element_input = $variation_input['elements'][ $element_name ] ?? null;
     3242                            if ( $element_input ) {
     3243                                $element_output = static::remove_insecure_styles( $element_input );
     3244
     3245                                if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
     3246                                    foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
     3247                                        if ( isset( $element_input[ $pseudo_selector ] ) ) {
     3248                                            $element_output[ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $pseudo_selector ] );
     3249                                        }
     3250                                    }
     3251                                }
     3252
     3253                                if ( ! empty( $element_output ) ) {
     3254                                    _wp_array_set( $variation_output, array( 'elements', $element_name ), $element_output );
     3255                                }
     3256                            }
     3257                        }
     3258                    }
     3259
    31783260                    if ( ! empty( $variation_output ) ) {
    31793261                        _wp_array_set( $sanitized, $variation['path'], $variation_output );
  • trunk/src/wp-settings.php

    r58225 r58264  
    367367require ABSPATH . WPINC . '/block-supports/align.php';
    368368require ABSPATH . WPINC . '/block-supports/background.php';
     369require ABSPATH . WPINC . '/block-supports/block-style-variations.php';
    369370require ABSPATH . WPINC . '/block-supports/border.php';
    370371require ABSPATH . WPINC . '/block-supports/colors.php';
  • trunk/tests/phpunit/tests/theme/themeDir.php

    r56765 r58264  
    178178            'Block Theme Child Theme',
    179179            'Block Theme Child Deprecated Path',
     180            'Block Theme Child With Block Style Variations Theme',
    180181            'Block Theme Child with no theme.json',
    181182            'Block Theme Child Theme With Fluid Layout',
  • trunk/tests/phpunit/tests/theme/wpThemeJsonResolver.php

    r58262 r58264  
    10241024
    10251025    /**
    1026      * Tests that get_style_variations returns all variations, including parent theme variations if the theme is a child,
    1027      * and that the child variation overwrites the parent variation of the same name.
     1026     * Tests that `get_style_variations` returns all the appropriate variations,
     1027     * including parent variations if the theme is a child, and that the child
     1028     * variation overwrites the parent variation of the same name.
     1029     *
     1030     * Note: This covers both theme and block style variations.
    10281031     *
    10291032     * @ticket 57545
     1033     * @ticket 61312
    10301034     *
    10311035     * @covers WP_Theme_JSON_Resolver::get_style_variations
    1032      */
    1033     public function test_get_style_variations_returns_all_variations() {
    1034         // Switch to a child theme.
    1035         switch_theme( 'block-theme-child' );
     1036     *
     1037     * @dataProvider data_get_style_variations
     1038     *
     1039     * @param string $theme               Name of the theme to use.
     1040     * @param string $scope               Scope to filter variations by e.g. theme vs block.
     1041     * @param array  $expected_variations Collection of expected variations.
     1042     */
     1043    public function test_get_style_variations( $theme, $scope, $expected_variations ) {
     1044        switch_theme( $theme );
    10361045        wp_set_current_user( self::$administrator_id );
    10371046
    1038         $actual_settings   = WP_Theme_JSON_Resolver::get_style_variations();
    1039         $expected_settings = array(
    1040             array(
    1041                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    1042                 'title'    => 'variation-a',
    1043                 'settings' => array(
    1044                     'blocks' => array(
    1045                         'core/paragraph' => array(
     1047        $actual_variations = WP_Theme_JSON_Resolver::get_style_variations( $scope );
     1048
     1049        wp_recursive_ksort( $actual_variations );
     1050        wp_recursive_ksort( $expected_variations );
     1051
     1052        $this->assertSame( $expected_variations, $actual_variations );
     1053    }
     1054
     1055    /**
     1056     * Data provider for test_get_style_variations
     1057     *
     1058     * @return array
     1059     */
     1060    public function data_get_style_variations() {
     1061        return array(
     1062            // @ticket 57545
     1063            'theme_style_variations' => array(
     1064                'theme'               => 'block-theme-child',
     1065                'scope'               => 'theme',
     1066                'expected_variations' => array(
     1067                    array(
     1068                        'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1069                        'title'    => 'variation-a',
     1070                        'settings' => array(
     1071                            'blocks' => array(
     1072                                'core/paragraph' => array(
     1073                                    'color' => array(
     1074                                        'palette' => array(
     1075                                            'theme' => array(
     1076                                                array(
     1077                                                    'slug' => 'dark',
     1078                                                    'name' => 'Dark',
     1079                                                    'color' => '#010101',
     1080                                                ),
     1081                                            ),
     1082                                        ),
     1083                                    ),
     1084                                ),
     1085                            ),
     1086                        ),
     1087                    ),
     1088                    array(
     1089                        'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1090                        'title'    => 'variation-b',
     1091                        'settings' => array(
     1092                            'blocks' => array(
     1093                                'core/post-title' => array(
     1094                                    'color' => array(
     1095                                        'palette' => array(
     1096                                            'theme' => array(
     1097                                                array(
     1098                                                    'slug' => 'dark',
     1099                                                    'name' => 'Dark',
     1100                                                    'color' => '#010101',
     1101                                                ),
     1102                                            ),
     1103                                        ),
     1104                                    ),
     1105                                ),
     1106                            ),
     1107                        ),
     1108                    ),
     1109                    array(
     1110                        'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     1111                        'title'    => 'Block theme variation',
     1112                        'settings' => array(
    10461113                            'color' => array(
    10471114                                'palette' => array(
    10481115                                    'theme' => array(
    10491116                                        array(
    1050                                             'slug'  => 'dark',
    1051                                             'name'  => 'Dark',
    1052                                             'color' => '#010101',
     1117                                            'slug'  => 'foreground',
     1118                                            'name'  => 'Foreground',
     1119                                            'color' => '#3F67C6',
    10531120                                        ),
    10541121                                    ),
     
    10561123                            ),
    10571124                        ),
    1058                     ),
    1059                 ),
    1060             ),
    1061             array(
    1062                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    1063                 'title'    => 'variation-b',
    1064                 'settings' => array(
    1065                     'blocks' => array(
    1066                         'core/post-title' => array(
    1067                             'color' => array(
    1068                                 'palette' => array(
    1069                                     'theme' => array(
    1070                                         array(
    1071                                             'slug'  => 'dark',
    1072                                             'name'  => 'Dark',
    1073                                             'color' => '#010101',
    1074                                         ),
     1125                        'styles'   => array(
     1126                            'blocks' => array(
     1127                                'core/post-title' => array(
     1128                                    'typography' => array(
     1129                                        'fontWeight' => '700',
    10751130                                    ),
    10761131                                ),
     
    10801135                ),
    10811136            ),
    1082             array(
    1083                 'version'  => WP_Theme_JSON::LATEST_SCHEMA,
    1084                 'title'    => 'Block theme variation',
    1085                 'settings' => array(
    1086                     'color' => array(
    1087                         'palette' => array(
    1088                             'theme' => array(
    1089                                 array(
    1090                                     'slug'  => 'foreground',
    1091                                     'name'  => 'Foreground',
    1092                                     'color' => '#3F67C6',
    1093                                 ),
    1094                             ),
    1095                         ),
    1096                     ),
    1097                 ),
    1098                 'styles'   => array(
    1099                     'blocks' => array(
    1100                         'core/post-title' => array(
    1101                             'typography' => array(
    1102                                 'fontWeight' => '700',
    1103                             ),
    1104                         ),
    1105                     ),
    1106                 ),
    1107             ),
    1108         );
    1109 
    1110         wp_recursive_ksort( $actual_settings );
    1111         wp_recursive_ksort( $expected_settings );
    1112 
    1113         $this->assertSame(
    1114             $expected_settings,
    1115             $actual_settings
     1137            'block_style_variations' => array(
     1138                'theme'               => 'block-theme-child-with-block-style-variations',
     1139                'scope'               => 'block',
     1140                'expected_variations' => array(
     1141                    array(
     1142                        'blockTypes' => array( 'core/group', 'core/columns', 'core/media-text' ),
     1143                        'version'    => 3,
     1144                        'title'      => 'block-style-variation-a',
     1145                        'styles'     => array(
     1146                            'color' => array(
     1147                                'background' => 'darkcyan',
     1148                                'text'       => 'aliceblue',
     1149                            ),
     1150                        ),
     1151                    ),
     1152                    array(
     1153                        'blockTypes' => array( 'core/group', 'core/columns' ),
     1154                        'version'    => 3,
     1155                        'title'      => 'block-style-variation-b',
     1156                        'styles'     => array(
     1157                            'color' => array(
     1158                                'background' => 'midnightblue',
     1159                                'text'       => 'lightblue',
     1160                            ),
     1161                        ),
     1162                    ),
     1163                ),
     1164            ),
    11161165        );
    11171166    }
Note: See TracChangeset for help on using the changeset viewer.