From 30f4fed8375457f12902b6eebbe201ea2ef52b3a Mon Sep 17 00:00:00 2001 From: ramon Date: Wed, 1 May 2024 13:06:45 +1000 Subject: [PATCH] Resolving urls in theme.json Feature complete, but hacky --- lib/block-supports/background.php | 23 +- lib/class-wp-theme-json-gutenberg.php | 21 +- ...class-wp-theme-json-resolver-gutenberg.php | 3 + packages/block-editor/src/hooks/background.js | 16 +- packages/block-editor/src/hooks/index.js | 2 +- packages/block-editor/src/hooks/style.js | 29 +- packages/style-engine/src/types.ts | 3 - phpunit/block-supports/background-test.php | 271 ------------------ 8 files changed, 42 insertions(+), 326 deletions(-) delete mode 100644 phpunit/block-supports/background-test.php diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index edffecdfbc902c..70957897229595 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -30,27 +30,6 @@ function gutenberg_register_background_support( $block_type ) { } } -/** - * Given a theme.json or block background styles, returns the background styles for a block. - * - * @since 6.6.0 - * - * @param array $background_styles Background style properties. - * @return array Style engine array of CSS string and style declarations. - */ -function gutenberg_get_background_support_styles( $background_styles = array() ) { - $background_image_source = ! empty( $background_styles['backgroundImage']['source'] ) ? $background_styles['backgroundImage']['source'] : null; - - /* - * "theme" source implies relative path to the theme directory - */ - if ( ! empty( $background_styles['backgroundImage']['url'] ) && is_string( $background_styles['backgroundImage']['url'] ) && 'theme' === $background_image_source ) { - $background_styles['backgroundImage']['url'] = esc_url( get_theme_file_uri( $background_styles['backgroundImage']['url'] ) ); - } - return gutenberg_style_engine_get_styles( array( 'background' => $background_styles ) ); -} - - /** * Renders the background styles to the block wrapper. * This block support uses the `render_block` hook to ensure that @@ -87,7 +66,7 @@ function gutenberg_render_background_support( $block_content, $block ) { } } - $styles = gutenberg_get_background_support_styles( $background_styles ); + $styles = gutenberg_style_engine_get_styles( array( 'background' => $background_styles ) ); if ( ! empty( $styles['css'] ) ) { // Inject background styles to the first element, presuming it's the wrapper, if it exists. diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 11a6095c2710fb..0fc9557ca2949d 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -2163,9 +2163,9 @@ protected static function compute_style_properties( $styles, $settings = array() } } - // Processes background styles. + // Processes background styles in order to build any `url()` functions. if ( 'background' === $value_path[0] && isset( $styles['background'] ) ) { - $background_styles = gutenberg_get_background_support_styles( $styles['background'] ); + $background_styles = gutenberg_style_engine_get_styles( array( 'background' => $styles['background'] ) ); $value = $background_styles['declarations'][ $css_property ] ?? $value; } @@ -4052,4 +4052,21 @@ protected static function get_valid_block_style_variations() { return $valid_variations; } + + // @TODO abstract and test this. + public function resolve_relative_paths() { + // Styles backgrounds. + /* + * "theme" source implies relative path to the theme directory + */ + if ( ! empty( $this->theme_json['styles']['background']['backgroundImage']['url'] ) && is_string( $this->theme_json['styles']['background']['backgroundImage']['url'] ) ) { + $background_image_source = ! empty( $this->theme_json['styles']['background']['backgroundImage']['source'] ) ? $this->theme_json['styles']['background']['backgroundImage']['source'] : null; + if ( 'theme' === $background_image_source ) { + $this->theme_json['styles']['background']['backgroundImage']['url'] = esc_url( get_theme_file_uri( $this->theme_json['styles']['background']['backgroundImage']['url'] ) ); + } + } + // Elements... (backgrounds not yet supported) + + // Block variations... (backgrounds not yet supported) + } } diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index dcc0bf8b099c3b..62266d863f62f7 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -355,6 +355,7 @@ public static function get_theme_data( $deprecated = array(), $options = array() $theme_support_data['settings']['appearanceTools'] = true; } } + $with_theme_supports = new WP_Theme_JSON_Gutenberg( $theme_support_data ); $with_theme_supports->merge( static::$theme ); return $with_theme_supports; @@ -615,11 +616,13 @@ public static function get_merged_data( $origin = 'custom' ) { $result->merge( static::get_theme_data() ); if ( 'theme' === $origin ) { $result->set_spacing_sizes(); + $result->resolve_relative_paths(); return $result; } $result->merge( static::get_user_data() ); $result->set_spacing_sizes(); + $result->resolve_relative_paths(); return $result; } diff --git a/packages/block-editor/src/hooks/background.js b/packages/block-editor/src/hooks/background.js index badaaa4b8a025d..a96cd520f9c690 100644 --- a/packages/block-editor/src/hooks/background.js +++ b/packages/block-editor/src/hooks/background.js @@ -181,7 +181,7 @@ function useBlockProps( { name, style } ) { const { backgroundImageURL } = useSelect( ( select ) => { const { getThemeFileURI } = unlock( select( blockEditorStore ) ); - let file; + let file = style?.background?.backgroundImage?.url; if ( !! style?.background?.backgroundImage?.url && style?.background?.backgroundImage?.source === 'theme' @@ -201,14 +201,26 @@ function useBlockProps( { name, style } ) { ) { return; } + const newBackgroundStyles = {}; + if ( ! style?.background?.backgroundSize ) { + newBackgroundStyles.backgroundSize = 'cover'; + } + + if ( + 'contain' === style?.background?.backgroundSize && + ! style?.background?.backgroundPosition + ) { + newBackgroundStyles.backgroundPosition = 'center'; + } return { style: { // @TODO this should be backgroundImage. How to do that? // Also, maybe consider reinstating https://github.com/WordPress/gutenberg/blob/fc98542a7dbba194bb4096d49cd0bd093b63f43e/packages/block-editor/src/hooks/background.js#L82 - background: `url( '${ encodeURI( + backgroundImage: `url( '${ encodeURI( safeDecodeURI( backgroundImageURL ) ) }' )`, + ...newBackgroundStyles, }, }; } diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index 17190f39868a32..d2f4f5fb5ed1ce 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -49,7 +49,6 @@ createBlockEditFilter( ); createBlockListBlockFilter( [ align, - background, textAlign, style, color, @@ -60,6 +59,7 @@ createBlockListBlockFilter( [ border, position, childLayout, + background, ] ); createBlockSaveFilter( [ align, diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index 863e25ff8717e5..dad62bc0594a75 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -10,16 +10,11 @@ import { } from '@wordpress/blocks'; import { useInstanceId } from '@wordpress/compose'; import { getCSSRules, compileCSS } from '@wordpress/style-engine'; -import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import { - BACKGROUND_SUPPORT_KEY, - BackgroundImagePanel, - setBackgroundStyleDefaults, -} from './background'; +import { BACKGROUND_SUPPORT_KEY, BackgroundImagePanel } from './background'; import { BORDER_SUPPORT_KEY, BorderPanel, SHADOW_SUPPORT_KEY } from './border'; import { COLOR_SUPPORT_KEY, ColorEdit } from './color'; import { @@ -39,7 +34,6 @@ import { } from './utils'; import { scopeSelector } from '../components/global-styles/utils'; import { useBlockEditingMode } from '../components/block-editing-mode'; -import { store as blockEditorStore } from '../store'; const styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, @@ -287,13 +281,14 @@ export function omitStyle( style, paths, preserveReference = false ) { * @param {Object|string} blockNameOrType Block type. * @param {Object} attributes Block attributes. * @param {?Record} skipPaths An object of keys and paths to skip serialization. + * * @return {Object} Filtered props applied to save element. */ export function addSaveProps( props, blockNameOrType, attributes, - skipPaths = skipSerializationPathsSave, + skipPaths = skipSerializationPathsSave ) { if ( ! hasStyleSupport( blockNameOrType ) ) { return props; @@ -317,15 +312,6 @@ export function addSaveProps( } } ); - /* - * Set styles defaults. - * Applies default values to the style object based on the block settings. - * Only applies to background styles for now. - */ - if ( !! style.background ) { - style = setBackgroundStyleDefaults( style ); - } - props.style = { ...getInlineStyles( style ), ...props.style, @@ -383,13 +369,6 @@ const elementTypes = [ ]; function useBlockProps( { name, style } ) { - const { stylesheetURI, templateURI } = useSelect( ( select ) => { - const _settings = select( blockEditorStore ).getSettings(); - return { - stylesheetURI: _settings?.__experimentalCurrentTheme?.stylesheetURI, - templateURI: _settings?.__experimentalCurrentTheme?.templateURI, - }; - } ); const blockElementsContainerIdentifier = `wp-elements-${ useInstanceId( useBlockProps ) }`; @@ -476,7 +455,7 @@ function useBlockProps( { name, style } ) { { className: blockElementsContainerIdentifier }, name, { style }, - skipSerializationPathsEdit, + skipSerializationPathsEdit ); } diff --git a/packages/style-engine/src/types.ts b/packages/style-engine/src/types.ts index a3e18b7f24f1cd..5b361836a8e375 100644 --- a/packages/style-engine/src/types.ts +++ b/packages/style-engine/src/types.ts @@ -90,9 +90,6 @@ export interface StyleOptions { * CSS selector for the generated style. */ selector?: string; - templateURI?: string; - stylesheetURI?: string; - isRoot: boolean; } export interface GeneratedCSSRule { diff --git a/phpunit/block-supports/background-test.php b/phpunit/block-supports/background-test.php deleted file mode 100644 index 78aa2cc56a672f..00000000000000 --- a/phpunit/block-supports/background-test.php +++ /dev/null @@ -1,271 +0,0 @@ -test_block_name = null; - $this->theme_root = realpath( __DIR__ . '/../data/themedir1' ); - $this->orig_theme_dir = $GLOBALS['wp_theme_directories']; - - // /themes is necessary as theme.php functions assume /themes is the root if there is only one root. - $GLOBALS['wp_theme_directories'] = array( WP_CONTENT_DIR . '/themes', $this->theme_root ); - - add_filter( 'theme_root', array( $this, 'filter_set_theme_root' ) ); - add_filter( 'stylesheet_root', array( $this, 'filter_set_theme_root' ) ); - add_filter( 'template_root', array( $this, 'filter_set_theme_root' ) ); - - // Clear caches. - wp_clean_themes_cache(); - unset( $GLOBALS['wp_themes'] ); - WP_Style_Engine_CSS_Rules_Store::remove_all_stores(); - } - - public function tear_down() { - $GLOBALS['wp_theme_directories'] = $this->orig_theme_dir; - - // Clear up the filters to modify the theme root. - remove_filter( 'theme_root', array( $this, 'filter_set_theme_root' ) ); - remove_filter( 'stylesheet_root', array( $this, 'filter_set_theme_root' ) ); - remove_filter( 'template_root', array( $this, 'filter_set_theme_root' ) ); - - wp_clean_themes_cache(); - unset( $GLOBALS['wp_themes'] ); - WP_Style_Engine_CSS_Rules_Store::remove_all_stores(); - unregister_block_type( $this->test_block_name ); - $this->test_block_name = null; - parent::tear_down(); - } - - public function filter_set_theme_root() { - return $this->theme_root; - } - - /** - * Tests that background image block support works as expected. - * - * @covers ::gutenberg_render_background_support - * - * @dataProvider data_background_block_support - * - * @param string $theme_name The theme to switch to. - * @param string $block_name The test block name to register. - * @param mixed $background_settings The background block support settings. - * @param mixed $background_style The background styles within the block attributes. - * @param string $expected_wrapper Expected markup for the block wrapper. - * @param string $wrapper Existing markup for the block wrapper. - */ - public function test_background_block_support( $theme_name, $block_name, $background_settings, $background_style, $expected_wrapper, $wrapper ) { - switch_theme( $theme_name ); - $this->test_block_name = $block_name; - - register_block_type( - $this->test_block_name, - array( - 'api_version' => 2, - 'attributes' => array( - 'style' => array( - 'type' => 'object', - ), - ), - 'supports' => array( - 'background' => $background_settings, - ), - ) - ); - - $block = array( - 'blockName' => $block_name, - 'attrs' => array( - 'style' => array( - 'background' => $background_style, - ), - ), - ); - - $actual = gutenberg_render_background_support( $wrapper, $block ); - - $this->assertEquals( - $expected_wrapper, - $actual, - 'Background block wrapper markup should be correct' - ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_background_block_support() { - return array( - 'background image style is applied' => array( - 'theme_name' => 'block-theme-child-with-fluid-typography', - 'block_name' => 'test/background-rules-are-output', - 'background_settings' => array( - 'backgroundImage' => true, - ), - 'background_style' => array( - 'backgroundImage' => array( - 'url' => 'https://example.com/image.jpg', - 'source' => 'file', - ), - ), - 'expected_wrapper' => '
Content
', - 'wrapper' => '
Content
', - ), - 'background image style is applied when backgroundImage is a string' => array( - 'theme_name' => 'block-theme-child-with-fluid-typography', - 'block_name' => 'test/background-rules-are-output', - 'background_settings' => array( - 'backgroundImage' => true, - ), - 'background_style' => array( - 'backgroundImage' => "url('https://example.com/image.jpg')", - ), - 'expected_wrapper' => '
Content
', - 'wrapper' => '
Content
', - ), - 'background image style with contain, position, and repeat is applied' => array( - 'theme_name' => 'block-theme-child-with-fluid-typography', - 'block_name' => 'test/background-rules-are-output', - 'background_settings' => array( - 'backgroundImage' => true, - ), - 'background_style' => array( - 'backgroundImage' => array( - 'url' => 'https://example.com/image.jpg', - 'source' => 'file', - ), - 'backgroundRepeat' => 'no-repeat', - 'backgroundSize' => 'contain', - ), - 'expected_wrapper' => '
Content
', - 'wrapper' => '
Content
', - ), - 'background image style is appended if a style attribute already exists' => array( - 'theme_name' => 'block-theme-child-with-fluid-typography', - 'block_name' => 'test/background-rules-are-output', - 'background_settings' => array( - 'backgroundImage' => true, - ), - 'background_style' => array( - 'backgroundImage' => array( - 'url' => 'https://example.com/image.jpg', - 'source' => 'file', - ), - ), - 'expected_wrapper' => '
Content
', - 'wrapper' => '
Content
', - ), - 'background image style is appended if a style attribute containing multiple styles already exists' => array( - 'theme_name' => 'block-theme-child-with-fluid-typography', - 'block_name' => 'test/background-rules-are-output', - 'background_settings' => array( - 'backgroundImage' => true, - ), - 'background_style' => array( - 'backgroundImage' => array( - 'url' => 'https://example.com/image.jpg', - 'source' => 'file', - ), - ), - 'expected_wrapper' => '
Content
', - 'wrapper' => '
Content
', - ), - 'background image style is not applied if the block does not support background image' => array( - 'theme_name' => 'block-theme-child-with-fluid-typography', - 'block_name' => 'test/background-rules-are-not-output', - 'background_settings' => array( - 'backgroundImage' => false, - ), - 'background_style' => array( - 'backgroundImage' => array( - 'url' => 'https://example.com/image.jpg', - 'source' => 'file', - ), - ), - 'expected_wrapper' => '
Content
', - 'wrapper' => '
Content
', - ), - ); - } - - /** - * Tests generating background styles. - * - * @covers ::gutenberg_get_background_support_styles - * - * @dataProvider data_get_background_support_styles - * - * @param mixed $background_style The background styles within the block attributes. - * @param string $expected_css Expected markup for the block wrapper. - */ - public function test_get_background_support_styles( $background_style, $expected_css ) { - switch_theme( 'block-theme' ); - $actual = gutenberg_get_background_support_styles( $background_style )['css'] ?? null; - - $this->assertEquals( - $expected_css, - $actual, - 'Background CSS should be correct.' - ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_get_background_support_styles() { - return array( - 'no css generated with no block styles' => array( - 'background_style' => array( - 'backgroundImage' => array(), - ), - 'expected_css' => null, - ), - 'css generated with theme background image path' => array( - 'background_style' => array( - 'backgroundImage' => array( - 'url' => '/assets/image/not_there.png', - 'source' => 'theme', - ), - ), - 'expected_css' => "background-image:url('http://localhost:8889/wp-content/plugins/gutenberg/phpunit/data/themedir1/block-theme/assets/image/not_there.png');", - ), - 'css generated with theme background image path and no preceding slash' => array( - 'background_style' => array( - 'backgroundImage' => array( - 'url' => 'assets/image/not_there.png', - 'source' => 'theme', - ), - ), - 'expected_css' => "background-image:url('http://localhost:8889/wp-content/plugins/gutenberg/phpunit/data/themedir1/block-theme/assets/image/not_there.png');", - ), - ); - } -}