diff --git a/wp-includes/class-wp-theme-json.php b/wp-includes/class-wp-theme-json.php index cddb8a2821..cf56000f87 100644 --- a/wp-includes/class-wp-theme-json.php +++ b/wp-includes/class-wp-theme-json.php @@ -3529,4 +3529,77 @@ class WP_Theme_JSON { return $tree; } + /** + * Replaces CSS variables with their values in place. + * + * @since 6.3.0 + * @param array $styles CSS declarations to convert. + * @param array $values key => value pairs to use for replacement. + * @return array + */ + private static function convert_variables_to_value( $styles, $values ) { + foreach ( $styles as $key => $style ) { + if ( is_array( $style ) ) { + $styles[ $key ] = self::convert_variables_to_value( $style, $values ); + continue; + } + + if ( 0 <= strpos( $style, 'var(' ) ) { + // find all the variables in the string in the form of var(--variable-name, fallback), with fallback in the second capture group. + + $has_matches = preg_match_all( '/var\(([^),]+)?,?\s?(\S+)?\)/', $style, $var_parts ); + + if ( $has_matches ) { + $resolved_style = $styles[ $key ]; + foreach ( $var_parts[1] as $index => $var_part ) { + $key_in_values = 'var(' . $var_part . ')'; + $rule_to_replace = $var_parts[0][ $index ]; // the css rule to replace e.g. var(--wp--preset--color--vivid-green-cyan). + $fallback = $var_parts[2][ $index ]; // the fallback value. + $resolved_style = str_replace( + array( + $rule_to_replace, + $fallback, + ), + array( + isset( $values[ $key_in_values ] ) ? $values[ $key_in_values ] : $rule_to_replace, + isset( $values[ $fallback ] ) ? $values[ $fallback ] : $fallback, + ), + $resolved_style + ); + } + $styles[ $key ] = $resolved_style; + } + } + } + + return $styles; + } + + /** + * Resolves the values of CSS variables in the given styles. + * + * @since 6.3.0 + * @param WP_Theme_JSON $theme_json The theme json resolver. + * + * @return WP_Theme_JSON The $theme_json with resolved variables. + */ + public static function resolve_variables( $theme_json ) { + $settings = $theme_json->get_settings(); + $styles = $theme_json->get_raw_data()['styles']; + $preset_vars = static::compute_preset_vars( $settings, static::VALID_ORIGINS ); + $theme_vars = static::compute_theme_vars( $settings ); + $vars = array_reduce( + array_merge( $preset_vars, $theme_vars ), + function( $carry, $item ) { + $name = $item['name']; + $carry[ "var({$name})" ] = $item['value']; + return $carry; + }, + array() + ); + + $theme_json->theme_json['styles'] = self::convert_variables_to_value( $styles, $vars ); + return $theme_json; + } + } diff --git a/wp-includes/global-styles-and-settings.php b/wp-includes/global-styles-and-settings.php index 81fc9679c6..4895b6daa9 100644 --- a/wp-includes/global-styles-and-settings.php +++ b/wp-includes/global-styles-and-settings.php @@ -92,8 +92,10 @@ function wp_get_global_settings( $path = array(), $context = array() ) { * Gets the styles resulting of merging core, theme, and user data. * * @since 5.9.0 - * @since 6.3.0 the internal format "var:preset|color|secondary" is always resolved - * to the standard form "var(--wp--preset--font-size--small)". + * @since 6.3.0 the internal link format "var:preset|color|secondary" is resolved + * to "var(--wp--preset--font-size--small)" so consumers don't have to. + * @since 6.3.0 `transforms` is now usable in the `context` parameter. In case [`transforms`]['resolve_variables'] + * is defined, variables are resolved to their value in the styles. * * @param array $path Path to the specific style to retrieve. Optional. * If empty, will return all styles. @@ -105,6 +107,9 @@ function wp_get_global_settings( $path = array(), $context = array() ) { * @type string $origin Which origin to take data from. * Valid values are 'all' (core, theme, and user) or 'base' (core and theme). * If empty or unknown, 'all' is used. + * @type array $transforms Which transformation(s) to apply. + * Valid value is array( 'resolve-variables' ). + * If defined, variables are resolved to their value in the styles. * } * @return mixed The styles array or individual style value to retrieve. */ @@ -117,11 +122,20 @@ function wp_get_global_styles( $path = array(), $context = array() ) { if ( isset( $context['origin'] ) && 'base' === $context['origin'] ) { $origin = 'theme'; } - $styles = WP_Theme_JSON_Resolver::get_merged_data( $origin )->get_raw_data()['styles']; + $resolve_variables = isset( $context['transforms'] ) + && is_array( $context['transforms'] ) + && in_array( 'resolve-variables', $context['transforms'], true ); + + $merged_data = WP_Theme_JSON_Resolver::get_merged_data( $origin ); + if ( $resolve_variables ) { + $merged_data = WP_Theme_JSON::resolve_variables( $merged_data ); + } + $styles = $merged_data->get_raw_data()['styles']; return _wp_array_get( $styles, $path, $styles ); } + /** * Returns the stylesheet resulting of merging core, theme, and user data. * diff --git a/wp-includes/version.php b/wp-includes/version.php index 7d8e7696dc..3fc98c403d 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.3-alpha-55985'; +$wp_version = '6.3-alpha-55986'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.