From aa6bb1d800af1500838ffadb46ac81ef8243b94a Mon Sep 17 00:00:00 2001 From: ramon Date: Tue, 30 Jul 2024 22:16:12 +1000 Subject: [PATCH] initial commit: - ensures ref values are resolved before they hit the style engine - adds tests Resolve refs before they're passed to the style engine. --- lib/class-wp-theme-json-gutenberg.php | 21 ++++++--- .../test/use-global-styles-output.js | 16 +++++++ .../global-styles/use-global-styles-output.js | 43 +++++++++++++---- .../src/styles/background/index.ts | 26 +++++------ phpunit/class-wp-theme-json-test.php | 46 +++++++++++++++++-- 5 files changed, 118 insertions(+), 34 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 65a5e5fe4b957..f7bd80c7d8341 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -2309,7 +2309,7 @@ protected static function flatten_tree( $tree, $prefix = '', $token = '--' ) { * ```php * array( * 'name' => 'property_name', - * 'value' => 'property_value, + * 'value' => 'property_value', * ) * ``` * @@ -2318,6 +2318,7 @@ protected static function flatten_tree( $tree, $prefix = '', $token = '--' ) { * @since 6.1.0 Added `$theme_json`, `$selector`, and `$use_root_padding` parameters. * @since 6.5.0 Output a `min-height: unset` rule when `aspect-ratio` is set. * @since 6.6.0 Passing current theme JSON settings to wp_get_typography_font_size_value(). Using style engine to correctly fetch background CSS values. + * @since 6.7.0 Allow ref resolution of background properties. * * @param array $styles Styles to process. * @param array $settings Theme settings. @@ -2361,10 +2362,13 @@ protected static function compute_style_properties( $styles, $settings = array() $root_variable_duplicates[] = substr( $css_property, $root_style_length ); } - // Processes background styles. - if ( 'background' === $value_path[0] && isset( $styles['background'] ) ) { - $background_styles = gutenberg_style_engine_get_styles( array( 'background' => $styles['background'] ) ); - $value = $background_styles['declarations'][ $css_property ] ?? $value; + // Processes background image styles. + if ( 'background-image' === $css_property && ! empty( $value ) ) { + $background_styles = gutenberg_style_engine_get_styles( + array( 'background' => array( 'backgroundImage' => $value ) ), + ); + + $value = $background_styles['declarations'][ $css_property ]; } // Skip if empty and not "0" or value represents array of longhand values. @@ -2452,11 +2456,14 @@ protected static function get_property_value( $styles, $path, $theme_json = null * where the values is an array with a "ref" key, pointing to a path. * For example: { "ref": "style.color.background" } => "#fff". */ + if ( is_array( $value ) && isset( $value['ref'] ) ) { $value_path = explode( '.', $value['ref'] ); - $ref_value = _wp_array_get( $theme_json, $value_path ); + $ref_value = _wp_array_get( $theme_json, $value_path, null ); + // Background Image refs can refer to a string or an array containing a URL string. + $ref_value_url = $ref_value['url'] ?? null; // Only use the ref value if we find anything. - if ( ! empty( $ref_value ) && is_string( $ref_value ) ) { + if ( ! empty( $ref_value ) && ( is_string( $ref_value ) || is_string( $ref_value_url ) ) ) { $value = $ref_value; } diff --git a/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js index 525a8a1d53d07..589e9fa7b1d45 100644 --- a/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js @@ -1008,9 +1008,23 @@ describe( 'global styles renderer', () => { ref: 'styles.elements.h1.typography.letterSpacing', }, }, + background: { + backgroundImage: { + ref: 'styles.background.backgroundImage', + }, + backgroundSize: { + ref: 'styles.background.backgroundSize', + }, + }, }; const tree = { styles: { + background: { + backgroundImage: { + url: 'http://my-image.org/image.gif', + }, + backgroundSize: 'cover', + }, elements: { h1: { typography: { @@ -1026,6 +1040,8 @@ describe( 'global styles renderer', () => { ).toEqual( [ 'font-size: var(--wp--preset--font-size--xx-large)', 'letter-spacing: 2px', + "background-image: url( 'http://my-image.org/image.gif' )", + 'background-size: cover', ] ); } ); } ); diff --git a/packages/block-editor/src/components/global-styles/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/use-global-styles-output.js index 63d6a2fb22dd7..6e4827dc2ded7 100644 --- a/packages/block-editor/src/components/global-styles/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/use-global-styles-output.js @@ -395,17 +395,40 @@ export function getStylesDeclarations( ); /* - * Set background defaults. - * Applies to all background styles except the top-level site background. + * Preprocess background image values. + * 1. Sets default values for blocks (not root). + * 2. . + * + * Note: A refactor is for the style engine to handle ref resolution (and possibly defaults) + * via a public util used internally and externally. Theme.json tree and defaults could be passed + * as options. */ - if ( ! isRoot && !! blockStyles.background ) { - blockStyles = { - ...blockStyles, - background: { - ...blockStyles.background, - ...setBackgroundStyleDefaults( blockStyles.background ), - }, - }; + if ( !! blockStyles.background ) { + // 1. Set default values for block styles except the top-level site background + if ( ! isRoot ) { + blockStyles = { + ...blockStyles, + background: { + ...blockStyles.background, + ...setBackgroundStyleDefaults( blockStyles.background ), + }, + }; + } + + /* + * 2. Resolve dynamic values before they are compiled by the style engine, + * which doesn't (yet) resolve dynamic values. + */ + if ( blockStyles.background?.backgroundImage?.ref ) { + if ( typeof blockStyles.background.backgroundImage !== 'string' ) { + const refPath = + blockStyles.background.backgroundImage.ref.split( '.' ); + blockStyles.background.backgroundImage = getValueFromObjectPath( + tree, + refPath + ); + } + } } // The goal is to move everything to server side generated engine styles diff --git a/packages/style-engine/src/styles/background/index.ts b/packages/style-engine/src/styles/background/index.ts index 211b97343d89c..b943032f9c441 100644 --- a/packages/style-engine/src/styles/background/index.ts +++ b/packages/style-engine/src/styles/background/index.ts @@ -8,6 +8,12 @@ const backgroundImage = { name: 'backgroundImage', generate: ( style: Style, options: StyleOptions ) => { const _backgroundImage = style?.background?.backgroundImage; + + /* + * The background image can be a string or an object. + * If the background image is a string, it could already contain a url() function, + * or have a linear-gradient value. + */ if ( typeof _backgroundImage === 'object' && _backgroundImage?.url ) { return [ { @@ -21,20 +27,12 @@ const backgroundImage = { ]; } - /* - * If the background image is a string, it could already contain a url() function, - * or have a linear-gradient value. - */ - if ( typeof _backgroundImage === 'string' ) { - return generateRule( - style, - options, - [ 'background', 'backgroundImage' ], - 'backgroundImage' - ); - } - - return []; + return generateRule( + style, + options, + [ 'background', 'backgroundImage' ], + 'backgroundImage' + ); }, }; diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 2f76ec7a5d473..ea853983e0183 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -4809,7 +4809,16 @@ public function test_get_block_background_image_styles() { array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, 'styles' => array( - 'blocks' => array( + 'background' => array( + 'backgroundImage' => array( + 'url' => 'http://example.org/top.png', + ), + 'backgroundSize' => 'contain', + 'backgroundRepeat' => 'repeat', + 'backgroundPosition' => '10% 20%', + 'backgroundAttachment' => 'scroll', + ), + 'blocks' => array( 'core/group' => array( 'background' => array( 'backgroundImage' => "url('http://example.org/group.png')", @@ -4829,6 +4838,25 @@ public function test_get_block_background_image_styles() { 'backgroundPosition' => 'center center', ), ), + 'core/verse' => array( + 'background' => array( + 'backgroundImage' => array( + 'ref' => 'styles.background.backgroundImage', + ), + 'backgroundSize' => array( + 'ref' => 'styles.background.backgroundSize', + ), + 'backgroundRepeat' => array( + 'ref' => 'styles.background.backgroundRepeat', + ), + 'backgroundPosition' => array( + 'ref' => 'styles.background.backgroundPosition', + ), + 'backgroundAttachment' => array( + 'ref' => 'styles.background.backgroundAttachment', + ), + ), + ), ), ), ) @@ -4844,7 +4872,7 @@ public function test_get_block_background_image_styles() { ); $quote_styles = ":root :where(.wp-block-quote){background-image: url('http://example.org/quote.png');background-position: center center;background-repeat: no-repeat;background-size: cover;}"; - $this->assertSame( $quote_styles, $theme_json->get_styles_for_block( $quote_node ), 'Styles returned from "::get_styles_for_block()" with block-level background styles do not match expectations' ); + $this->assertSame( $quote_styles, $theme_json->get_styles_for_block( $quote_node ), 'Styles returned from "::get_styles_for_block()" with core/quote background styles do not match expectations' ); $group_node = array( 'name' => 'core/group', @@ -4856,7 +4884,19 @@ public function test_get_block_background_image_styles() { ); $group_styles = ":root :where(.wp-block-group){background-image: url('http://example.org/group.png');background-position: center center;background-repeat: no-repeat;background-size: cover;background-attachment: fixed;}"; - $this->assertSame( $group_styles, $theme_json->get_styles_for_block( $group_node ), 'Styles returned from "::get_styles_for_block()" with block-level background styles as string type do not match expectations' ); + $this->assertSame( $group_styles, $theme_json->get_styles_for_block( $group_node ), 'Styles returned from "::get_styles_for_block()" with core/group background styles as string type do not match expectations' ); + + $verse_node = array( + 'name' => 'core/verse', + 'path' => array( 'styles', 'blocks', 'core/verse' ), + 'selector' => '.wp-block-verse', + 'selectors' => array( + 'root' => '.wp-block-verse', + ), + ); + + $verse_styles = ":root :where(.wp-block-verse){background-image: url('http://example.org/top.png');background-position: 10% 20%;background-repeat: repeat;background-size: contain;background-attachment: scroll;}"; + $this->assertSame( $verse_styles, $theme_json->get_styles_for_block( $verse_node ), 'Styles returned from "::get_styles_for_block()" with core/verse background ref styles as string type do not match expectations' ); } /**