Make WordPress Core

Changeset 55986


Ignore:
Timestamp:
06/22/2023 08:42:42 AM (3 years 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.