Make WordPress Core

Changeset 55172


Ignore:
Timestamp:
02/01/2023 01:41:16 PM (20 months ago)
Author:
hellofromTonya
Message:

Editor: Add support for editing block style variations in global styles.

To allow editing of block style variations in global styles, this changeset adds the following for server side support:

  • building of block style schema into WP_Theme_JSON::sanitize().
  • appending of style variation selectors to block metadata in WP_Theme_JSON::get_blocks_metadata().
  • building of selectors and variations for nodes in WP_Theme_JSON::get_block_nodes().

Tests for happy and unhappy paths are included.

Reference:

Follow-up to [54118], [50973], [50959].

Props isabel_brison,
Fixes #57583.

Location:
trunk
Files:
2 edited

Legend:

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

    r55142 r55172  
    666666        $schema_settings_blocks = array();
    667667        foreach ( $valid_block_names as $block ) {
    668             $schema_settings_blocks[ $block ]           = static::VALID_SETTINGS;
    669             $schema_styles_blocks[ $block ]             = $styles_non_top_level;
    670             $schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
     668            // Build the schema for each block style variation.
     669            $style_variation_names = array();
     670            if (
     671                ! empty( $input['styles']['blocks'][ $block ]['variations'] ) &&
     672                is_array( $input['styles']['blocks'][ $block ]['variations'] )
     673            ) {
     674                $style_variation_names = array_keys( $input['styles']['blocks'][ $block ]['variations'] );
     675            }
     676
     677            $schema_styles_variations = array();
     678            if ( ! empty( $style_variation_names ) ) {
     679                $schema_styles_variations = array_fill_keys( $style_variation_names, $styles_non_top_level );
     680            }
     681
     682            $schema_settings_blocks[ $block ]             = static::VALID_SETTINGS;
     683            $schema_styles_blocks[ $block ]               = $styles_non_top_level;
     684            $schema_styles_blocks[ $block ]['elements']   = $schema_styles_elements;
     685            $schema_styles_blocks[ $block ]['variations'] = $schema_styles_variations;
    671686        }
    672687
     
    814829                }
    815830                static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector );
     831            }
     832            // If the block has style variations, append their selectors to the block metadata.
     833            if ( ! empty( $block_type->styles ) ) {
     834                $style_selectors = array();
     835                foreach ( $block_type->styles as $style ) {
     836                    // The style variation classname is duplicated in the selector to ensure that it overrides core block styles.
     837                    $style_selectors[ $style['name'] ] = static::append_to_selector( '.is-style-' . $style['name'] . '.is-style-' . $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
     838                }
     839                static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
    816840            }
    817841        }
     
    20402064            }
    20412065
     2066            $variation_selectors = array();
     2067            if ( isset( $node['variations'] ) ) {
     2068                foreach ( $node['variations'] as $variation => $node ) {
     2069                    $variation_selectors[] = array(
     2070                        'path'     => array( 'styles', 'blocks', $name, 'variations', $variation ),
     2071                        'selector' => $selectors[ $name ]['styleVariations'][ $variation ],
     2072                    );
     2073                }
     2074            }
     2075
    20422076            $nodes[] = array(
    2043                 'name'     => $name,
    2044                 'path'     => array( 'styles', 'blocks', $name ),
    2045                 'selector' => $selector,
    2046                 'duotone'  => $duotone_selector,
    2047                 'features' => $feature_selectors,
     2077                'name'       => $name,
     2078                'path'       => array( 'styles', 'blocks', $name ),
     2079                'selector'   => $selector,
     2080                'duotone'    => $duotone_selector,
     2081                'features'   => $feature_selectors,
     2082                'variations' => $variation_selectors,
    20482083            );
    20492084
     
    21252160        }
    21262161
     2162        // If there are style variations, generate the declarations for them, including any feature selectors the block may have.
     2163        $style_variation_declarations = array();
     2164        if ( ! empty( $block_metadata['variations'] ) ) {
     2165            foreach ( $block_metadata['variations'] as $style_variation ) {
     2166                $style_variation_node     = _wp_array_get( $this->theme_json, $style_variation['path'], array() );
     2167                $style_variation_selector = $style_variation['selector'];
     2168
     2169                // If the block has feature selectors, generate the declarations for them within the current style variation.
     2170                if ( ! empty( $block_metadata['features'] ) ) {
     2171                    $clean_style_variation_selector = trim( $style_variation_selector );
     2172                    foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) {
     2173                        if ( empty( $style_variation_node[ $feature_name ] ) ) {
     2174                            continue;
     2175                        }
     2176                        // Prepend the variation selector to the feature selector.
     2177                        $split_feature_selectors    = explode( ',', $feature_selector );
     2178                        $feature_selectors          = array_map(
     2179                            static function( $split_feature_selector ) use ( $clean_style_variation_selector ) {
     2180                                return $clean_style_variation_selector . trim( $split_feature_selector );
     2181                            },
     2182                            $split_feature_selectors
     2183                        );
     2184                        $combined_feature_selectors = implode( ',', $feature_selectors );
     2185
     2186                        // Compute declarations for the feature.
     2187                        $new_feature_declarations = static::compute_style_properties( array( $feature_name => $style_variation_node[ $feature_name ] ), $settings, null, $this->theme_json );
     2188
     2189                        /*
     2190                         * Merge new declarations with any that already exist for
     2191                         * the feature selector. This may occur when multiple block
     2192                         * support features use the same custom selector.
     2193                         */
     2194                        if ( isset( $style_variation_declarations[ $combined_feature_selectors ] ) ) {
     2195                            $style_variation_declarations[ $combined_feature_selectors ] = array_merge( $style_variation_declarations[ $combined_feature_selectors ], $new_feature_declarations );
     2196                        } else {
     2197                            $style_variation_declarations[ $combined_feature_selectors ] = $new_feature_declarations;
     2198                        }
     2199                        /*
     2200                         * Remove the feature from the variation's node now the
     2201                         * styles will be included under the feature level selector.
     2202                         */
     2203                        unset( $style_variation_node[ $feature_name ] );
     2204                    }
     2205                }
     2206                // Compute declarations for remaining styles not covered by feature level selectors.
     2207                $style_variation_declarations[ $style_variation_selector ] = static::compute_style_properties( $style_variation_node, $settings, null, $this->theme_json );
     2208            }
     2209        }
    21272210        /*
    21282211         * Get a reference to element name from path.
     
    22132296        foreach ( $feature_declarations as $feature_selector => $individual_feature_declarations ) {
    22142297            $block_rules .= static::to_ruleset( $feature_selector, $individual_feature_declarations );
     2298        }
     2299
     2300        // 6. Generate and append the style variation rulesets.
     2301        foreach ( $style_variation_declarations as $style_variation_selector => $individual_style_variation_declarations ) {
     2302            $block_rules .= static::to_ruleset( $style_variation_selector, $individual_style_variation_declarations );
    22152303        }
    22162304
  • trunk/tests/phpunit/tests/theme/wpThemeJson.php

    r55146 r55172  
    35973597
    35983598    /**
     3599     * @ticket 57583
     3600     *
     3601     * @dataProvider data_sanitize_for_block_with_style_variations
     3602     *
     3603     * @param array $theme_json_variations Theme.json variations to test.
     3604     * @param array $expected_sanitized    Expected results after sanitizing.
     3605     */
     3606    public function test_sanitize_for_block_with_style_variations( $theme_json_variations, $expected_sanitized ) {
     3607        $theme_json = new WP_Theme_JSON(
     3608            array(
     3609                'version' => 2,
     3610                'styles'  => array(
     3611                    'blocks' => array(
     3612                        'core/quote' => $theme_json_variations,
     3613                    ),
     3614                ),
     3615            )
     3616        );
     3617
     3618        // Validate structure is sanitized.
     3619        $sanitized_theme_json = $theme_json->get_raw_data();
     3620        $this->assertIsArray( $sanitized_theme_json, 'Sanitized theme.json is not an array data type' );
     3621        $this->assertArrayHasKey( 'styles', $sanitized_theme_json, 'Sanitized theme.json does not have an "styles" key' );
     3622        $this->assertSameSetsWithIndex( $expected_sanitized, $sanitized_theme_json['styles'], 'Sanitized theme.json styles does not match' );
     3623    }
     3624
     3625    /**
     3626     * Data provider.
     3627     *
     3628     * @return array
     3629     */
     3630    public function data_sanitize_for_block_with_style_variations() {
     3631        return array(
     3632            '1 variation with 1 invalid property'   => array(
     3633                'theme_json_variations' => array(
     3634                    'variations' => array(
     3635                        'plain' => array(
     3636                            'color' => array(
     3637                                'background' => 'hotpink',
     3638                            ),
     3639                        ),
     3640                    ),
     3641                ),
     3642                'expected_sanitized'    => array(
     3643                    'blocks' => array(
     3644                        'core/quote' => array(
     3645                            'variations' => array(
     3646                                'plain' => array(
     3647                                    'color' => array(
     3648                                        'background' => 'hotpink',
     3649                                    ),
     3650                                ),
     3651                            ),
     3652                        ),
     3653                    ),
     3654                ),
     3655            ),
     3656            '1 variation with 2 invalid properties' => array(
     3657                'theme_json_variations' => array(
     3658                    'variations' => array(
     3659                        'plain' => array(
     3660                            'color'            => array(
     3661                                'background' => 'hotpink',
     3662                            ),
     3663                            'invalidProperty1' => 'value1',
     3664                            'invalidProperty2' => 'value2',
     3665                        ),
     3666                    ),
     3667                ),
     3668                'expected_sanitized'    => array(
     3669                    'blocks' => array(
     3670                        'core/quote' => array(
     3671                            'variations' => array(
     3672                                'plain' => array(
     3673                                    'color' => array(
     3674                                        'background' => 'hotpink',
     3675                                    ),
     3676                                ),
     3677                            ),
     3678                        ),
     3679                    ),
     3680                ),
     3681            ),
     3682            '2 variations with 1 invalid property'  => array(
     3683                'theme_json_variations' => array(
     3684                    'variations' => array(
     3685                        'plain' => array(
     3686                            'color'            => array(
     3687                                'background' => 'hotpink',
     3688                            ),
     3689                            'invalidProperty1' => 'value1',
     3690                        ),
     3691                        'basic' => array(
     3692                            'color' => array(
     3693                                'background' => '#ffffff',
     3694                                'text'       => '#000000',
     3695                            ),
     3696                            'foo'   => 'bar',
     3697                        ),
     3698                    ),
     3699                ),
     3700                'expected_sanitized'    => array(
     3701                    'blocks' => array(
     3702                        'core/quote' => array(
     3703                            'variations' => array(
     3704                                'plain' => array(
     3705                                    'color' => array(
     3706                                        'background' => 'hotpink',
     3707                                    ),
     3708                                ),
     3709                                'basic' => array(
     3710                                    'color' => array(
     3711                                        'background' => '#ffffff',
     3712                                        'text'       => '#000000',
     3713                                    ),
     3714                                ),
     3715                            ),
     3716                        ),
     3717                    ),
     3718                ),
     3719            ),
     3720        );
     3721    }
     3722
     3723    /**
     3724     * @ticket 57583
     3725     *
     3726     * @dataProvider data_sanitize_with_invalid_style_variation
     3727     *
     3728     * @param array $theme_json_variations The theme.json variations to test.
     3729     */
     3730    public function test_sanitize_with_invalid_style_variation( $theme_json_variations ) {
     3731        $theme_json = new WP_Theme_JSON(
     3732            array(
     3733                'version' => 2,
     3734                'styles'  => array(
     3735                    'blocks' => array(
     3736                        'core/quote' => $theme_json_variations,
     3737                    ),
     3738                ),
     3739            )
     3740        );
     3741
     3742        // Validate structure is sanitized.
     3743        $sanitized_theme_json = $theme_json->get_raw_data();
     3744        $this->assertIsArray( $sanitized_theme_json, 'Sanitized theme.json is not an array data type' );
     3745        $this->assertArrayNotHasKey( 'styles', $sanitized_theme_json, 'Sanitized theme.json should not have a "styles" key' );
     3746
     3747    }
     3748
     3749    /**
     3750     * Data provider.
     3751     *
     3752     * @return array
     3753     */
     3754    public function data_sanitize_with_invalid_style_variation() {
     3755        return array(
     3756            'empty string variation' => array(
     3757                array(
     3758                    'variations' => '',
     3759                ),
     3760            ),
     3761            'boolean variation'      => array(
     3762                array(
     3763                    'variations' => false,
     3764                ),
     3765            ),
     3766        );
     3767    }
     3768
     3769    /**
     3770     * @ticket 57583
     3771     *
     3772     * @dataProvider data_get_styles_for_block_with_style_variations
     3773     *
     3774     * @param array  $theme_json_variations Theme.json variations to test.
     3775     * @param string $metadata_variations   Style variations to test.
     3776     * @param string $expected              Expected results for styling.
     3777     */
     3778    public function test_get_styles_for_block_with_style_variations( $theme_json_variations, $metadata_variations, $expected ) {
     3779        $theme_json = new WP_Theme_JSON(
     3780            array(
     3781                'version' => 2,
     3782                'styles'  => array(
     3783                    'blocks' => array(
     3784                        'core/quote' => $theme_json_variations,
     3785                    ),
     3786                ),
     3787            )
     3788        );
     3789
     3790        // Validate styles are generated properly.
     3791        $metadata      = array(
     3792            'path'       => array( 'styles', 'blocks', 'core/quote' ),
     3793            'selector'   => '.wp-block-quote',
     3794            'variations' => $metadata_variations,
     3795        );
     3796        $actual_styles = $theme_json->get_styles_for_block( $metadata );
     3797        $this->assertSame( $expected, $actual_styles );
     3798    }
     3799
     3800    /**
     3801     * Data provider.
     3802     *
     3803     * @return array
     3804     */
     3805    public function data_get_styles_for_block_with_style_variations() {
     3806        $plain = array(
     3807            'metadata' => array(
     3808                'path'     => array( 'styles', 'blocks', 'core/quote', 'variations', 'plain' ),
     3809                'selector' => '.is-style-plain.is-style-plain.wp-block-quote',
     3810            ),
     3811            'styles'   => '.is-style-plain.is-style-plain.wp-block-quote{background-color: hotpink;}',
     3812        );
     3813        $basic = array(
     3814            'metadata' => array(
     3815                'path'     => array( 'styles', 'blocks', 'core/quote', 'variations', 'basic' ),
     3816                'selector' => '.is-style-basic.is-style-basic.wp-block-quote',
     3817            ),
     3818            'styles'   => '.is-style-basic.is-style-basic.wp-block-quote{background-color: #ffffff;color: #000000;}',
     3819        );
     3820
     3821        return array(
     3822            '1 variation with 1 invalid property'   => array(
     3823                'theme_json_variations' => array(
     3824                    'variations' => array(
     3825                        'plain' => array(
     3826                            'color' => array(
     3827                                'background' => 'hotpink',
     3828                            ),
     3829                        ),
     3830                    ),
     3831                ),
     3832                'metadata_variation'    => array( $plain['metadata'] ),
     3833                'expected'              => $plain['styles'],
     3834            ),
     3835            '1 variation with 2 invalid properties' => array(
     3836                'theme_json_variations' => array(
     3837                    'variations' => array(
     3838                        'plain' => array(
     3839                            'color'            => array(
     3840                                'background' => 'hotpink',
     3841                            ),
     3842                            'invalidProperty1' => 'value1',
     3843                            'invalidProperty2' => 'value2',
     3844                        ),
     3845                    ),
     3846                ),
     3847                'metadata_variation'    => array( $plain['metadata'] ),
     3848                'expected'              => $plain['styles'],
     3849            ),
     3850            '2 variations with 1 invalid property'  => array(
     3851                'theme_json_variations' => array(
     3852                    'variations' => array(
     3853                        'plain' => array(
     3854                            'color'            => array(
     3855                                'background' => 'hotpink',
     3856                            ),
     3857                            'invalidProperty1' => 'value1',
     3858                        ),
     3859                        'basic' => array(
     3860                            'color' => array(
     3861                                'background' => '#ffffff',
     3862                                'text'       => '#000000',
     3863                            ),
     3864                            'foo'   => 'bar',
     3865                        ),
     3866                    ),
     3867                ),
     3868                'metadata_variation'    => array( $plain['metadata'], $basic['metadata'] ),
     3869                'expected_styles'       => $plain['styles'] . $basic['styles'],
     3870            ),
     3871            '2 variations with multiple invalid properties' => array(
     3872                'theme_json_variations' => array(
     3873                    'variations' => array(
     3874                        'plain' => array(
     3875                            'color'            => array(
     3876                                'background' => 'hotpink',
     3877                            ),
     3878                            'invalidProperty1' => 'value1',
     3879                            'invalidProperty2' => 'value2',
     3880                        ),
     3881                        'basic' => array(
     3882                            'foo'   => 'foo',
     3883                            'color' => array(
     3884                                'background' => '#ffffff',
     3885                                'text'       => '#000000',
     3886                            ),
     3887                            'bar'   => 'bar',
     3888                            'baz'   => 'baz',
     3889                        ),
     3890                    ),
     3891                ),
     3892                'metadata_variation'    => array( $plain['metadata'], $basic['metadata'] ),
     3893                'expected_styles'       => $plain['styles'] . $basic['styles'],
     3894            ),
     3895        );
     3896    }
     3897
     3898    /**
    35993899     * @ticket 56611
    36003900     */
Note: See TracChangeset for help on using the changeset viewer.