Make WordPress Core

Changeset 55986


Ignore:
Timestamp:
06/22/2023 08:42:42 AM (11 months ago)
Author:
oandregal
Message:

wp_get_global_styles: allow transforming the CSS Custom Properties into the values they represent.

Props samnajian, ramonopoly, isabel_brison.
Fixes #58588.

Location:
trunk
Files:
3 edited

Legend:

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

    r55985 r55986  
    35303530    }
    35313531
     3532    /**
     3533     * Replaces CSS variables with their values in place.
     3534     *
     3535     * @since 6.3.0
     3536     * @param array $styles CSS declarations to convert.
     3537     * @param array $values key => value pairs to use for replacement.
     3538     * @return array
     3539     */
     3540    private static function convert_variables_to_value( $styles, $values ) {
     3541        foreach ( $styles as $key => $style ) {
     3542            if ( is_array( $style ) ) {
     3543                $styles[ $key ] = self::convert_variables_to_value( $style, $values );
     3544                continue;
     3545            }
     3546
     3547            if ( 0 <= strpos( $style, 'var(' ) ) {
     3548                // find all the variables in the string in the form of var(--variable-name, fallback), with fallback in the second capture group.
     3549
     3550                $has_matches = preg_match_all( '/var\(([^),]+)?,?\s?(\S+)?\)/', $style, $var_parts );
     3551
     3552                if ( $has_matches ) {
     3553                    $resolved_style = $styles[ $key ];
     3554                    foreach ( $var_parts[1] as $index => $var_part ) {
     3555                        $key_in_values   = 'var(' . $var_part . ')';
     3556                        $rule_to_replace = $var_parts[0][ $index ]; // the css rule to replace e.g. var(--wp--preset--color--vivid-green-cyan).
     3557                        $fallback        = $var_parts[2][ $index ]; // the fallback value.
     3558                        $resolved_style  = str_replace(
     3559                            array(
     3560                                $rule_to_replace,
     3561                                $fallback,
     3562                            ),
     3563                            array(
     3564                                isset( $values[ $key_in_values ] ) ? $values[ $key_in_values ] : $rule_to_replace,
     3565                                isset( $values[ $fallback ] ) ? $values[ $fallback ] : $fallback,
     3566                            ),
     3567                            $resolved_style
     3568                        );
     3569                    }
     3570                    $styles[ $key ] = $resolved_style;
     3571                }
     3572            }
     3573        }
     3574
     3575        return $styles;
     3576    }
     3577
     3578    /**
     3579     * Resolves the values of CSS variables in the given styles.
     3580     *
     3581     * @since 6.3.0
     3582     * @param WP_Theme_JSON $theme_json The theme json resolver.
     3583     *
     3584     * @return WP_Theme_JSON The $theme_json with resolved variables.
     3585     */
     3586    public static function resolve_variables( $theme_json ) {
     3587        $settings    = $theme_json->get_settings();
     3588        $styles      = $theme_json->get_raw_data()['styles'];
     3589        $preset_vars = static::compute_preset_vars( $settings, static::VALID_ORIGINS );
     3590        $theme_vars  = static::compute_theme_vars( $settings );
     3591        $vars        = array_reduce(
     3592            array_merge( $preset_vars, $theme_vars ),
     3593            function( $carry, $item ) {
     3594                $name                    = $item['name'];
     3595                $carry[ "var({$name})" ] = $item['value'];
     3596                return $carry;
     3597            },
     3598            array()
     3599        );
     3600
     3601        $theme_json->theme_json['styles'] = self::convert_variables_to_value( $styles, $vars );
     3602        return $theme_json;
     3603    }
     3604
    35323605}
  • trunk/src/wp-includes/global-styles-and-settings.php

    r55983 r55986  
    9393 *
    9494 * @since 5.9.0
    95  * @since 6.3.0 the internal format "var:preset|color|secondary" is always resolved
    96  *              to the standard form "var(--wp--preset--font-size--small)".
     95 * @since 6.3.0 the internal link format "var:preset|color|secondary" is resolved
     96 *              to "var(--wp--preset--font-size--small)" so consumers don't have to.
     97 * @since 6.3.0 `transforms` is now usable in the `context` parameter. In case [`transforms`]['resolve_variables']
     98 *              is defined, variables are resolved to their value in the styles.
    9799 *
    98100 * @param array $path    Path to the specific style to retrieve. Optional.
     
    106108 *                              Valid values are 'all' (core, theme, and user) or 'base' (core and theme).
    107109 *                              If empty or unknown, 'all' is used.
     110 *     @type array $transforms Which transformation(s) to apply.
     111 *                              Valid value is array( 'resolve-variables' ).
     112 *                              If defined, variables are resolved to their value in the styles.
    108113 * }
    109114 * @return mixed The styles array or individual style value to retrieve.
     
    118123        $origin = 'theme';
    119124    }
    120     $styles = WP_Theme_JSON_Resolver::get_merged_data( $origin )->get_raw_data()['styles'];
    121 
     125
     126    $resolve_variables = isset( $context['transforms'] )
     127    && is_array( $context['transforms'] )
     128    && in_array( 'resolve-variables', $context['transforms'], true );
     129
     130    $merged_data = WP_Theme_JSON_Resolver::get_merged_data( $origin );
     131    if ( $resolve_variables ) {
     132        $merged_data = WP_Theme_JSON::resolve_variables( $merged_data );
     133    }
     134    $styles = $merged_data->get_raw_data()['styles'];
    122135    return _wp_array_get( $styles, $path, $styles );
    123136}
     137
    124138
    125139/**
  • trunk/tests/phpunit/tests/theme/wpThemeJson.php

    r55985 r55986  
    47784778
    47794779    }
     4780
     4781    public function test_resolve_variables() {
     4782        $primary_color   = '#9DFF20';
     4783        $secondary_color = '#9DFF21';
     4784        $contrast_color  = '#000';
     4785        $raw_color_value = '#efefef';
     4786        $large_font      = '18px';
     4787        $small_font      = '12px';
     4788        $theme_json      = new WP_Theme_JSON(
     4789            array(
     4790                'version'  => WP_Theme_JSON::LATEST_SCHEMA,
     4791                'settings' => array(
     4792                    'color'      => array(
     4793                        'palette' => array(
     4794                            'theme' => array(
     4795                                array(
     4796                                    'color' => $primary_color,
     4797                                    'name'  => 'Primary',
     4798                                    'slug'  => 'primary',
     4799                                ),
     4800                                array(
     4801                                    'color' => $secondary_color,
     4802                                    'name'  => 'Secondary',
     4803                                    'slug'  => 'secondary',
     4804                                ),
     4805                                array(
     4806                                    'color' => $contrast_color,
     4807                                    'name'  => 'Contrast',
     4808                                    'slug'  => 'contrast',
     4809                                ),
     4810                            ),
     4811                        ),
     4812                    ),
     4813                    'typography' => array(
     4814                        'fontSizes' => array(
     4815                            array(
     4816                                'size' => $small_font,
     4817                                'name' => 'Font size small',
     4818                                'slug' => 'small',
     4819                            ),
     4820                            array(
     4821                                'size' => $large_font,
     4822                                'name' => 'Font size large',
     4823                                'slug' => 'large',
     4824                            ),
     4825                        ),
     4826                    ),
     4827                ),
     4828                'styles'   => array(
     4829                    'color'    => array(
     4830                        'background' => 'var(--wp--preset--color--primary)',
     4831                        'text'       => $raw_color_value,
     4832                    ),
     4833                    'elements' => array(
     4834                        'button' => array(
     4835                            'color'      => array(
     4836                                'text' => 'var(--wp--preset--color--contrast)',
     4837                            ),
     4838                            'typography' => array(
     4839                                'fontSize' => 'var(--wp--preset--font-size--small)',
     4840                            ),
     4841                        ),
     4842                    ),
     4843                    'blocks'   => array(
     4844                        'core/post-terms'      => array(
     4845                            'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
     4846                            'color'      => array( 'background' => $raw_color_value ),
     4847                        ),
     4848                        'core/more'            => array(
     4849                            'typography' => array( 'fontSize' => 'var(--undefined--font-size--small)' ),
     4850                            'color'      => array( 'background' => 'linear-gradient(90deg, var(--wp--preset--color--primary) 0%, var(--wp--preset--color--secondary) 35%, var(--wp--undefined--color--secondary) 100%)' ),
     4851                        ),
     4852                        'core/comment-content' => array(
     4853                            'typography' => array( 'fontSize' => 'calc(var(--wp--preset--font-size--small, 12px) + 20px)' ),
     4854                            'color'      => array(
     4855                                'text'       => 'var(--wp--preset--color--primary, red)',
     4856                                'background' => 'var(--wp--preset--color--primary, var(--wp--preset--font-size--secondary))',
     4857                                'link'       => 'var(--undefined--color--primary, var(--wp--preset--font-size--secondary))',
     4858                            ),
     4859                        ),
     4860                        'core/comments'        => array(
     4861                            'color' => array(
     4862                                'text'       => 'var(--undefined--color--primary, var(--wp--preset--font-size--small))',
     4863                                'background' => 'var(--wp--preset--color--primary, var(--undefined--color--primary))',
     4864                            ),
     4865                        ),
     4866                        'core/navigation'      => array(
     4867                            'elements' => array(
     4868                                'link' => array(
     4869                                    'color'      => array(
     4870                                        'background' => 'var(--wp--preset--color--primary)',
     4871                                        'text'       => 'var(--wp--preset--color--secondary)',
     4872                                    ),
     4873                                    'typography' => array(
     4874                                        'fontSize' => 'var(--wp--preset--font-size--large)',
     4875                                    ),
     4876                                ),
     4877                            ),
     4878                        ),
     4879                        'core/quote'           => array(
     4880                            'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--large)' ),
     4881                            'color'      => array( 'background' => 'var(--wp--preset--color--primary)' ),
     4882                            'variations' => array(
     4883                                'plain' => array(
     4884                                    'typography' => array( 'fontSize' => 'var(--wp--preset--font-size--small)' ),
     4885                                    'color'      => array( 'background' => 'var(--wp--preset--color--secondary)' ),
     4886                                ),
     4887                            ),
     4888                        ),
     4889                    ),
     4890                ),
     4891            )
     4892        );
     4893
     4894        $styles = $theme_json::resolve_variables( $theme_json )->get_raw_data()['styles'];
     4895
     4896        $this->assertEquals( $primary_color, $styles['color']['background'], 'Top level: Assert values are converted' );
     4897        $this->assertEquals( $raw_color_value, $styles['color']['text'], 'Top level: Assert raw values stay intact' );
     4898
     4899        $this->assertEquals( $contrast_color, $styles['elements']['button']['color']['text'], 'Elements: color' );
     4900        $this->assertEquals( $small_font, $styles['elements']['button']['typography']['fontSize'], 'Elements: font-size' );
     4901
     4902        $this->assertEquals( $large_font, $styles['blocks']['core/quote']['typography']['fontSize'], 'Blocks: font-size' );
     4903        $this->assertEquals( $primary_color, $styles['blocks']['core/quote']['color']['background'], 'Blocks: color' );
     4904        $this->assertEquals( $raw_color_value, $styles['blocks']['core/post-terms']['color']['background'], 'Blocks: Raw color value stays intact' );
     4905        $this->assertEquals( $small_font, $styles['blocks']['core/post-terms']['typography']['fontSize'], 'Block core/post-terms: font-size' );
     4906        $this->assertEquals(
     4907            "linear-gradient(90deg, $primary_color 0%, $secondary_color 35%, var(--wp--undefined--color--secondary) 100%)",
     4908            $styles['blocks']['core/more']['color']['background'],
     4909            'Blocks: multiple colors and undefined color'
     4910        );
     4911        $this->assertEquals( 'var(--undefined--font-size--small)', $styles['blocks']['core/more']['typography']['fontSize'], 'Blocks: undefined font-size ' );
     4912        $this->assertEquals( "calc($small_font + 20px)", $styles['blocks']['core/comment-content']['typography']['fontSize'], 'Blocks: font-size in random place' );
     4913        $this->assertEquals( $primary_color, $styles['blocks']['core/comment-content']['color']['text'], 'Blocks: text color with fallback' );
     4914        $this->assertEquals( $primary_color, $styles['blocks']['core/comment-content']['color']['background'], 'Blocks: background color with var as fallback' );
     4915        $this->assertEquals( $primary_color, $styles['blocks']['core/navigation']['elements']['link']['color']['background'], 'Block element: background color' );
     4916        $this->assertEquals( $secondary_color, $styles['blocks']['core/navigation']['elements']['link']['color']['text'], 'Block element: text color' );
     4917        $this->assertEquals( $large_font, $styles['blocks']['core/navigation']['elements']['link']['typography']['fontSize'], 'Block element: font-size' );
     4918
     4919        $this->assertEquals(
     4920            "var(--undefined--color--primary, $small_font)",
     4921            $styles['blocks']['core/comments']['color']['text'],
     4922            'Blocks: text color with undefined var and fallback'
     4923        );
     4924        $this->assertEquals(
     4925            $primary_color,
     4926            $styles['blocks']['core/comments']['color']['background'],
     4927            'Blocks: background color with variable and undefined fallback'
     4928        );
     4929
     4930        $this->assertEquals( $small_font, $styles['blocks']['core/quote']['variations']['plain']['typography']['fontSize'], 'Block variations: font-size' );
     4931        $this->assertEquals( $secondary_color, $styles['blocks']['core/quote']['variations']['plain']['color']['background'], 'Block variations: color' );
     4932    }
     4933
    47804934}
Note: See TracChangeset for help on using the changeset viewer.