<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[58222] trunk: Block Themes: Allow setting site-wide background images in theme.json</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/58222">58222</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/58222","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>noisysocks</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2024-05-28 06:04:37 +0000 (Tue, 28 May 2024)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Block Themes: Allow setting site-wide background images in theme.json

Syncs the necessary changes from Gutenberg to allow setting site-wide
background images using the top-level `styles.background` key in `theme.json`.

Props ramonopoly.
Fixes <a href="https://core.trac.wordpress.org/ticket/61123">#61123</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesblocksupportsbackgroundphp">trunk/src/wp-includes/block-supports/background.php</a></li>
<li><a href="#trunksrcwpincludesclasswpthemejsonphp">trunk/src/wp-includes/class-wp-theme-json.php</a></li>
<li><a href="#trunktestsphpunittestsblocksupportswpRenderBackgroundSupportphp">trunk/tests/phpunit/tests/block-supports/wpRenderBackgroundSupport.php</a></li>
<li><a href="#trunktestsphpunitteststhemewpThemeJsonphp">trunk/tests/phpunit/tests/theme/wpThemeJson.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesblocksupportsbackgroundphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/block-supports/background.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/block-supports/background.php       2024-05-28 05:25:06 UTC (rev 58221)
+++ trunk/src/wp-includes/block-supports/background.php 2024-05-28 06:04:37 UTC (rev 58222)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -41,6 +41,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 6.4.0
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 6.5.0 Added support for `backgroundPosition` and `backgroundRepeat` output.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.6.0 Removed requirement for `backgroundImage.source`. A file/url is the default.
+ *
</ins><span class="cx" style="display: block; padding: 0 10px">  * @access private
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @param  string $block_content Rendered block content.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -54,52 +56,27 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if (
</span><span class="cx" style="display: block; padding: 0 10px">                ! $has_background_image_support ||
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                wp_should_skip_block_supports_serialization( $block_type, 'background', 'backgroundImage' )
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         wp_should_skip_block_supports_serialization( $block_type, 'background', 'backgroundImage' ) ||
+               ! isset( $block_attributes['style']['background'] )
</ins><span class="cx" style="display: block; padding: 0 10px">         ) {
</span><span class="cx" style="display: block; padding: 0 10px">                return $block_content;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $background_image_source = isset( $block_attributes['style']['background']['backgroundImage']['source'] )
-               ? $block_attributes['style']['background']['backgroundImage']['source']
-               : null;
-       $background_image_url    = isset( $block_attributes['style']['background']['backgroundImage']['url'] )
-               ? $block_attributes['style']['background']['backgroundImage']['url']
-               : null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $background_styles                    = array();
+       $background_styles['backgroundImage'] = isset( $block_attributes['style']['background']['backgroundImage'] ) ? $block_attributes['style']['background']['backgroundImage'] : array();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( ! $background_image_source && ! $background_image_url ) {
-               return $block_content;
-       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 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;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $background_size     = isset( $block_attributes['style']['background']['backgroundSize'] )
-               ? $block_attributes['style']['background']['backgroundSize']
-               : 'cover';
-       $background_position = isset( $block_attributes['style']['background']['backgroundPosition'] )
-               ? $block_attributes['style']['background']['backgroundPosition']
-               : null;
-       $background_repeat   = isset( $block_attributes['style']['background']['backgroundRepeat'] )
-               ? $block_attributes['style']['background']['backgroundRepeat']
-               : null;
-
-       $background_block_styles = array();
-
-       if (
-               'file' === $background_image_source &&
-               $background_image_url
-       ) {
-               // Set file based background URL.
-               $background_block_styles['backgroundImage']['url'] = $background_image_url;
-               // Only output the background size and repeat when an image url is set.
-               $background_block_styles['backgroundSize']     = $background_size;
-               $background_block_styles['backgroundRepeat']   = $background_repeat;
-               $background_block_styles['backgroundPosition'] = $background_position;
-
</del><span class="cx" style="display: block; padding: 0 10px">                 // If the background size is set to `contain` and no position is set, set the position to `center`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( 'contain' === $background_size && ! isset( $background_position ) ) {
-                       $background_block_styles['backgroundPosition'] = 'center';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( 'contain' === $background_styles['backgroundSize'] && ! $background_styles['backgroundPosition'] ) {
+                       $background_styles['backgroundPosition'] = 'center';
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $styles = wp_style_engine_get_styles( array( 'background' => $background_block_styles ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $styles = wp_style_engine_get_styles( array( 'background' => $background_styles ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! empty( $styles['css'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                // Inject background styles to the first element, presuming it's the wrapper, if it exists.
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpthemejsonphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-theme-json.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-theme-json.php     2024-05-28 05:25:06 UTC (rev 58221)
+++ trunk/src/wp-includes/class-wp-theme-json.php       2024-05-28 06:04:37 UTC (rev 58222)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -213,6 +213,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.3.0 Added `column-count` property.
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.4.0 Added `writing-mode` property.
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.5.0 Added `aspect-ratio` property.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added `background-[image|position|repeat|size]` properties.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @var array
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -220,6 +221,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'aspect-ratio'                      => array( 'dimensions', 'aspectRatio' ),
</span><span class="cx" style="display: block; padding: 0 10px">                'background'                        => array( 'color', 'gradient' ),
</span><span class="cx" style="display: block; padding: 0 10px">                'background-color'                  => array( 'color', 'background' ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'background-image'                  => array( 'background', 'backgroundImage' ),
+               'background-position'               => array( 'background', 'backgroundPosition' ),
+               'background-repeat'                 => array( 'background', 'backgroundRepeat' ),
+               'background-size'                   => array( 'background', 'backgroundSize' ),
</ins><span class="cx" style="display: block; padding: 0 10px">                 'border-radius'                     => array( 'border', 'radius' ),
</span><span class="cx" style="display: block; padding: 0 10px">                'border-top-left-radius'            => array( 'border', 'radius', 'topLeft' ),
</span><span class="cx" style="display: block; padding: 0 10px">                'border-top-right-radius'           => array( 'border', 'radius', 'topRight' ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -283,9 +288,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * Indirect properties are not output directly by `compute_style_properties`,
</span><span class="cx" style="display: block; padding: 0 10px">         * but are used elsewhere in the processing of global styles. The indirect
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * property is used to validate whether or not a style value is allowed.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * property is used to validate whether a style value is allowed.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.2.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added background-image properties.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @var array
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -303,6 +309,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        array( 'layout', 'contentSize' ),
</span><span class="cx" style="display: block; padding: 0 10px">                        array( 'layout', 'wideSize' ),
</span><span class="cx" style="display: block; padding: 0 10px">                ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'background-image' => array(
+                       array( 'background', 'backgroundImage', 'url' ),
+               ),
</ins><span class="cx" style="display: block; padding: 0 10px">         );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -482,10 +491,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.2.0 Added `outline`, and `minHeight` properties.
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.3.0 Added support for `typography.textColumns`.
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.5.0 Added support for `dimensions.aspectRatio`.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Added `background` sub properties to top-level only.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @var array
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        const VALID_STYLES = array(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'background' => array(
+                       'backgroundImage'    => 'top',
+                       'backgroundPosition' => 'top',
+                       'backgroundRepeat'   => 'top',
+                       'backgroundSize'     => 'top',
+               ),
</ins><span class="cx" style="display: block; padding: 0 10px">                 'border'     => array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'color'  => null,
</span><span class="cx" style="display: block; padding: 0 10px">                        'radius' => null,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2051,7 +2067,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 5.9.0 Added the `$settings` and `$properties` parameters.
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0 Added `$theme_json`, `$selector`, and `$use_root_padding` parameters.
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.5.0 Output a `min-height: unset` rule when `aspect-ratio` is set.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @since 6.6.0 Passing current theme JSON settings to wp_get_typography_font_size_value().
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  * @since 6.6.0 Pass current theme JSON settings to wp_get_typography_font_size_value(), and process background properties.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param array   $styles Styles to process.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param array   $settings Theme settings.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2105,6 +2121,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        // Processes background styles.
+                       if ( 'background' === $value_path[0] && isset( $styles['background'] ) ) {
+                               $background_styles = wp_style_engine_get_styles( array( 'background' => $styles['background'] ) );
+                               $value             = isset( $background_styles['declarations'][ $css_property ] ) ? $background_styles['declarations'][ $css_property ] : $value;
+                       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         // Skip if empty and not "0" or value represents array of longhand values.
</span><span class="cx" style="display: block; padding: 0 10px">                        $has_missing_value = empty( $value ) && ! is_numeric( $value );
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( $has_missing_value || is_array( $value ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2484,6 +2506,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Gets the CSS rules for a particular block from theme.json.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.1.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 6.6.0 Setting a min-height of HTML when root styles have a background gradient or image.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param array $block_metadata Metadata about the block to get styles for.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2495,6 +2518,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $selector             = $block_metadata['selector'];
</span><span class="cx" style="display: block; padding: 0 10px">                $settings             = isset( $this->theme_json['settings'] ) ? $this->theme_json['settings'] : array();
</span><span class="cx" style="display: block; padding: 0 10px">                $feature_declarations = static::get_feature_declarations_for_node( $block_metadata, $node );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $is_root_selector     = static::ROOT_BLOCK_SELECTOR === $selector;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // If there are style variations, generate the declarations for them, including any feature selectors the block may have.
</span><span class="cx" style="display: block; padding: 0 10px">                $style_variation_declarations = array();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2577,17 +2601,55 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $block_rules = '';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                /*
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                 * 1. Separate the declarations that use the general selector
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          * 1. Bespoke declaration modifiers:
+                * - 'filter': Separate the declarations that use the general selector
</ins><span class="cx" style="display: block; padding: 0 10px">                  * from the ones using the duotone selector.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 * - 'background|background-image': set the html min-height to 100%
+                * to ensure the background covers the entire viewport.
</ins><span class="cx" style="display: block; padding: 0 10px">                  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $declarations_duotone = array();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $declarations_duotone       = array();
+               $should_set_root_min_height = false;
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 foreach ( $declarations as $index => $declaration ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( 'filter' === $declaration['name'] ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                /*
+                                * 'unset' filters happen when a filter is unset
+                                * in the site-editor UI. Because the 'unset' value
+                                * in the user origin overrides the value in the
+                                * theme origin, we can skip rendering anything
+                                * here as no filter needs to be applied anymore.
+                                * So only add declarations to with values other
+                                * than 'unset'.
+                                */
+                               if ( 'unset' !== $declaration['value'] ) {
+                                       $declarations_duotone[] = $declaration;
+                               }
</ins><span class="cx" style="display: block; padding: 0 10px">                                 unset( $declarations[ $index ] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $declarations_duotone[] = $declaration;
</del><span class="cx" style="display: block; padding: 0 10px">                         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       if ( $is_root_selector && ( 'background-image' === $declaration['name'] || 'background' === $declaration['name'] ) ) {
+                               $should_set_root_min_height = true;
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                /*
+                * If root styles has a background-image or a background (gradient) set,
+                * set the min-height to '100%'. Minus `--wp-admin--admin-bar--height` for logged-in view.
+                * Setting the CSS rule on the HTML tag ensures background gradients and images behave similarly,
+                * and matches the behavior of the site editor.
+                */
+               if ( $should_set_root_min_height ) {
+                       $block_rules .= static::to_ruleset(
+                               'html',
+                               array(
+                                       array(
+                                               'name'  => 'min-height',
+                                               'value' => 'calc(100% - var(--wp-admin--admin-bar--height, 0px))',
+                                       ),
+                               )
+                       );
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // Update declarations if there are separators with only background color defined.
</span><span class="cx" style="display: block; padding: 0 10px">                if ( '.wp-block-separator' === $selector ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $declarations = static::update_separator_declarations( $declarations );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2603,7 +2665,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // 4. Generate Layout block gap styles.
</span><span class="cx" style="display: block; padding: 0 10px">                if (
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        static::ROOT_BLOCK_SELECTOR !== $selector &&
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 ! $is_root_selector &&
</ins><span class="cx" style="display: block; padding: 0 10px">                         ! empty( $block_metadata['name'] )
</span><span class="cx" style="display: block; padding: 0 10px">                ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $block_rules .= $this->get_layout_styles( $block_metadata );
</span></span></pre></div>
<a id="trunktestsphpunittestsblocksupportswpRenderBackgroundSupportphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/block-supports/wpRenderBackgroundSupport.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/block-supports/wpRenderBackgroundSupport.php    2024-05-28 05:25:06 UTC (rev 58221)
+++ trunk/tests/phpunit/tests/block-supports/wpRenderBackgroundSupport.php      2024-05-28 06:04:37 UTC (rev 58222)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -68,6 +68,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 59357
</span><span class="cx" style="display: block; padding: 0 10px">         * @ticket 60175
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @ticket 61123
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @covers ::wp_render_background_support
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -132,8 +133,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'background_style'    => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'backgroundImage' => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                'url'    => 'https://example.com/image.jpg',
-                                               'source' => 'file',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         'url' => 'https://example.com/image.jpg',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'expected_wrapper'    => '<div class="has-background" style="background-image:url(&#039;https://example.com/image.jpg&#039;);background-size:cover;">Content</div>',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -147,8 +147,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'background_style'    => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'backgroundImage'  => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                'url'    => 'https://example.com/image.jpg',
-                                               'source' => 'file',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         'url' => 'https://example.com/image.jpg',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'backgroundRepeat' => 'no-repeat',
</span><span class="cx" style="display: block; padding: 0 10px">                                        'backgroundSize'   => 'contain',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -164,8 +163,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'background_style'    => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'backgroundImage' => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                'url'    => 'https://example.com/image.jpg',
-                                               'source' => 'file',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         'url' => 'https://example.com/image.jpg',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'expected_wrapper'    => '<div class="wp-block-test has-background" style="color: red;background-image:url(&#039;https://example.com/image.jpg&#039;);background-size:cover;">Content</div>',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -179,8 +177,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'background_style'    => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'backgroundImage' => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                'url'    => 'https://example.com/image.jpg',
-                                               'source' => 'file',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         'url' => 'https://example.com/image.jpg',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'expected_wrapper'    => '<div class="wp-block-test has-background" style="color: red;font-size: 15px;background-image:url(&#039;https://example.com/image.jpg&#039;);background-size:cover;">Content</div>',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -194,8 +191,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'background_style'    => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'backgroundImage' => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                'url'    => 'https://example.com/image.jpg',
-                                               'source' => 'file',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         'url' => 'https://example.com/image.jpg',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'expected_wrapper'    => '<div>Content</div>',
</span></span></pre></div>
<a id="trunktestsphpunitteststhemewpThemeJsonphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/theme/wpThemeJson.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/theme/wpThemeJson.php   2024-05-28 05:25:06 UTC (rev 58221)
+++ trunk/tests/phpunit/tests/theme/wpThemeJson.php     2024-05-28 06:04:37 UTC (rev 58222)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4985,6 +4985,73 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Tests that theme background image styles are correctly generated.
+        *
+        * @ticket 61123
+        */
+       public function test_get_top_level_background_image_styles() {
+               $theme_json = new WP_Theme_JSON(
+                       array(
+                               'version' => WP_Theme_JSON::LATEST_SCHEMA,
+                               'styles'  => array(
+                                       'background' => array(
+                                               'backgroundImage'    => array(
+                                                       'url' => 'http://example.org/image.png',
+                                               ),
+                                               'backgroundSize'     => 'contain',
+                                               'backgroundRepeat'   => 'no-repeat',
+                                               'backgroundPosition' => 'center center',
+                                       ),
+                                       'blocks'     => array(
+                                               'core/paragraph' => array(
+                                                       'background' => array(
+                                                               'backgroundImage'    => array(
+                                                                       'url' => 'http://example.org/image.png',
+                                                               ),
+                                                               'backgroundSize'     => 'cover',
+                                                               'backgroundRepeat'   => 'no-repeat',
+                                                               'backgroundPosition' => 'center center',
+                                                       ),
+                                               ),
+                                       ),
+                                       'elements'   => array(
+                                               'button' => array(
+                                                       'background' => array(
+                                                               'backgroundImage'    => array(
+                                                                       'url' => 'http://example.org/image.png',
+                                                               ),
+                                                               'backgroundSize'     => 'cover',
+                                                               'backgroundRepeat'   => 'no-repeat',
+                                                               'backgroundPosition' => 'center center',
+                                                       ),
+                                               ),
+                                       ),
+                               ),
+                       )
+               );
+
+               $expected_styles = "body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :wh
 ere(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}body{background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}";
+               $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" with top-level background styles type does not match expectations' );
+
+               $theme_json = new WP_Theme_JSON(
+                       array(
+                               'version' => WP_Theme_JSON::LATEST_SCHEMA,
+                               'styles'  => array(
+                                       'background' => array(
+                                               'backgroundImage'    => "url('http://example.org/image.png')",
+                                               'backgroundSize'     => 'contain',
+                                               'backgroundRepeat'   => 'no-repeat',
+                                               'backgroundPosition' => 'center center',
+                                       ),
+                               ),
+                       )
+               );
+
+               $expected_styles = "body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :wh
 ere(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}body{background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;}";
+               $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" with top-level background image as string type does not match expectations' );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * @ticket 57536
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function test_get_custom_css_handles_global_custom_css() {
</span></span></pre>
</div>
</div>

</body>
</html>