diff --git a/lib/block-supports/background.php b/lib/block-supports/background.php index 8e3c06159a120..1455d12fe883c 100644 --- a/lib/block-supports/background.php +++ b/lib/block-supports/background.php @@ -56,9 +56,10 @@ function gutenberg_render_background_support( $block_content, $block ) { $background_styles['backgroundImage'] = isset( $block_attributes['style']['background']['backgroundImage'] ) ? $block_attributes['style']['background']['backgroundImage'] : array(); if ( ! empty( $background_styles['backgroundImage'] ) ) { - $background_styles['backgroundSize'] = isset( $block_attributes['style']['background']['backgroundSize'] ) ? $block_attributes['style']['background']['backgroundSize'] : 'cover'; - $background_styles['backgroundPosition'] = isset( $block_attributes['style']['background']['backgroundPosition'] ) ? $block_attributes['style']['background']['backgroundPosition'] : null; - $background_styles['backgroundRepeat'] = isset( $block_attributes['style']['background']['backgroundRepeat'] ) ? $block_attributes['style']['background']['backgroundRepeat'] : null; + $background_styles['backgroundSize'] = isset( $block_attributes['style']['background']['backgroundSize'] ) ? $block_attributes['style']['background']['backgroundSize'] : 'cover'; + $background_styles['backgroundPosition'] = isset( $block_attributes['style']['background']['backgroundPosition'] ) ? $block_attributes['style']['background']['backgroundPosition'] : null; + $background_styles['backgroundRepeat'] = isset( $block_attributes['style']['background']['backgroundRepeat'] ) ? $block_attributes['style']['background']['backgroundRepeat'] : null; + $background_styles['backgroundAttachment'] = isset( $block_attributes['style']['background']['backgroundAttachment'] ) ? $block_attributes['style']['background']['backgroundAttachment'] : null; // If the background size is set to `contain` and no position is set, set the position to `center`. if ( 'contain' === $background_styles['backgroundSize'] && ! $background_styles['backgroundPosition'] ) { diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index e09dc899a2489..1d289aa583a26 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -234,6 +234,7 @@ class WP_Theme_JSON_Gutenberg { 'background-position' => array( 'background', 'backgroundPosition' ), 'background-repeat' => array( 'background', 'backgroundRepeat' ), 'background-size' => array( 'background', 'backgroundSize' ), + 'background-attachment' => array( 'background', 'backgroundAttachment' ), 'border-radius' => array( 'border', 'radius' ), 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), @@ -503,10 +504,11 @@ class WP_Theme_JSON_Gutenberg { */ const VALID_STYLES = array( 'background' => array( - 'backgroundImage' => 'top', - 'backgroundPosition' => 'top', - 'backgroundRepeat' => 'top', - 'backgroundSize' => 'top', + 'backgroundImage' => 'top', + 'backgroundAttachment' => 'top', + 'backgroundPosition' => 'top', + 'backgroundRepeat' => 'top', + 'backgroundSize' => 'top', ), 'border' => array( 'color' => null, diff --git a/packages/block-editor/src/components/global-styles/background-panel.js b/packages/block-editor/src/components/global-styles/background-panel.js index 6baef04f39b6b..a6c45fac26360 100644 --- a/packages/block-editor/src/components/global-styles/background-panel.js +++ b/packages/block-editor/src/components/global-styles/background-panel.js @@ -447,6 +447,9 @@ function BackgroundSizeControls( { const positionValue = style?.background?.backgroundPosition || inheritedValue?.background?.backgroundPosition; + const attachmentValue = style?.background?.backgroundAttachment || { + ...inheritedValue?.background?.backgroundAttachment, + }; /* * An `undefined` value is replaced with any supplied @@ -542,8 +545,17 @@ function BackgroundSizeControls( { ) ); + const toggleScrollWithPage = () => + onChange( + setImmutably( + style, + [ 'background', 'backgroundAttachment' ], + attachmentValue === 'fixed' ? 'scroll' : 'fixed' + ) + ); + return ( - + + array( - 'backgroundImage' => array( + 'backgroundImage' => array( 'property_keys' => array( 'default' => 'background-image', ), 'value_func' => array( self::class, 'get_url_or_value_css_declaration' ), 'path' => array( 'background', 'backgroundImage' ), ), - 'backgroundPosition' => array( + 'backgroundPosition' => array( 'property_keys' => array( 'default' => 'background-position', ), 'path' => array( 'background', 'backgroundPosition' ), ), - 'backgroundRepeat' => array( + 'backgroundRepeat' => array( 'property_keys' => array( 'default' => 'background-repeat', ), 'path' => array( 'background', 'backgroundRepeat' ), ), - 'backgroundSize' => array( + 'backgroundSize' => array( 'property_keys' => array( 'default' => 'background-size', ), 'path' => array( 'background', 'backgroundSize' ), ), + 'backgroundAttachment' => array( + 'property_keys' => array( + 'default' => 'background-attachment', + ), + 'path' => array( 'background', 'backgroundAttachment' ), + ), ), 'color' => array( 'text' => array( diff --git a/packages/style-engine/src/styles/background/index.ts b/packages/style-engine/src/styles/background/index.ts index 6e79636cfda12..211b97343d89c 100644 --- a/packages/style-engine/src/styles/background/index.ts +++ b/packages/style-engine/src/styles/background/index.ts @@ -74,9 +74,22 @@ const backgroundSize = { }, }; +const backgroundAttachment = { + name: 'backgroundAttachment', + generate: ( style: Style, options: StyleOptions ) => { + return generateRule( + style, + options, + [ 'background', 'backgroundAttachment' ], + 'backgroundAttachment' + ); + }, +}; + export default [ backgroundImage, backgroundPosition, backgroundRepeat, backgroundSize, + backgroundAttachment, ]; diff --git a/packages/style-engine/src/test/index.js b/packages/style-engine/src/test/index.js index fbccc8c48bc92..f7960e19187a2 100644 --- a/packages/style-engine/src/test/index.js +++ b/packages/style-engine/src/test/index.js @@ -231,6 +231,7 @@ describe( 'getCSSRules', () => { backgroundPosition: '50% 50%', backgroundRepeat: 'no-repeat', backgroundSize: '300px', + backgroundAttachment: 'fixed', }, color: { text: '#dddddd', @@ -399,6 +400,11 @@ describe( 'getCSSRules', () => { key: 'backgroundSize', value: '300px', }, + { + selector: '.some-selector', + key: 'backgroundAttachment', + value: 'fixed', + }, ] ); } ); diff --git a/phpunit/block-supports/background-test.php b/phpunit/block-supports/background-test.php index 165a65204793d..c0b87cc988e43 100644 --- a/phpunit/block-supports/background-test.php +++ b/phpunit/block-supports/background-test.php @@ -149,7 +149,7 @@ public function data_background_block_support() { 'expected_wrapper' => '
Content
', 'wrapper' => '
Content
', ), - 'background image style with contain, position, and repeat is applied' => array( + 'background image style with contain, position, attachment, and repeat is applied' => array( 'theme_name' => 'block-theme-child-with-fluid-typography', 'block_name' => 'test/background-rules-are-output', 'background_settings' => array( @@ -160,10 +160,11 @@ public function data_background_block_support() { 'url' => 'https://example.com/image.jpg', 'source' => 'file', ), - 'backgroundRepeat' => 'no-repeat', - 'backgroundSize' => 'contain', + 'backgroundRepeat' => 'no-repeat', + 'backgroundSize' => 'contain', + 'backgroundAttachment' => 'fixed', ), - 'expected_wrapper' => '
Content
', + 'expected_wrapper' => '
Content
', 'wrapper' => '
Content
', ), 'background image style is appended if a style attribute already exists' => array( diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index b188ce4fce6ab..d02b7f2396cee 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -4765,12 +4765,13 @@ public function test_get_top_level_background_image_styles() { 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, 'styles' => array( 'background' => array( - 'backgroundImage' => array( + 'backgroundImage' => array( 'url' => 'http://example.org/image.png', ), - 'backgroundSize' => 'contain', - 'backgroundRepeat' => 'no-repeat', - 'backgroundPosition' => 'center center', + 'backgroundSize' => 'contain', + 'backgroundRepeat' => 'no-repeat', + 'backgroundPosition' => 'center center', + 'backgroundAttachment' => 'fixed', ), ), ) @@ -4781,7 +4782,7 @@ public function test_get_top_level_background_image_styles() { 'selector' => 'body', ); - $expected_styles = "html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:root :where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}"; + $expected_styles = "html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:root :where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;background-attachment: fixed;}"; $this->assertSame( $expected_styles, $theme_json->get_styles_for_block( $body_node ), 'Styles returned from "::get_styles_for_block()" with top-level background styles type does not match expectations' ); $theme_json = new WP_Theme_JSON_Gutenberg( @@ -4789,16 +4790,17 @@ public function test_get_top_level_background_image_styles() { 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, 'styles' => array( 'background' => array( - 'backgroundImage' => "url('http://example.org/image.png')", - 'backgroundSize' => 'contain', - 'backgroundRepeat' => 'no-repeat', - 'backgroundPosition' => 'center center', + 'backgroundImage' => "url('http://example.org/image.png')", + 'backgroundSize' => 'contain', + 'backgroundRepeat' => 'no-repeat', + 'backgroundPosition' => 'center center', + 'backgroundAttachment' => 'fixed', ), ), ) ); - $expected_styles = "html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:root :where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}"; + $expected_styles = "html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}:root :where(body){background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;background-attachment: fixed;}"; $this->assertSame( $expected_styles, $theme_json->get_styles_for_block( $body_node ), 'Styles returned from "::get_styles_for_block()" with top-level background image as string type does not match expectations' ); }