From 1debf45660fb9e352b4ea98e20a0d151143c669e Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 17 Jun 2025 17:38:49 -0700 Subject: [PATCH 01/10] Backport https://github.com/WordPress/gutenberg/pull/70428 --- src/wp-includes/deprecated.php | 2 +- src/wp-includes/script-loader.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 97183f86479a5..c8af5d401b280 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6372,7 +6372,7 @@ function wp_get_global_styles_custom_css() { */ function wp_enqueue_global_styles_custom_css() { _deprecated_function( __FUNCTION__, '6.7.0', 'wp_enqueue_global_styles' ); - if ( ! wp_is_block_theme() ) { + if ( ! wp_is_block_theme() || is_customize_preview() ) { return; } diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index cd2c06e4cc4d3..d0b0e8c0dd8b3 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2533,10 +2533,13 @@ function wp_enqueue_global_styles() { $stylesheet = wp_get_global_stylesheet(); - if ( $is_block_theme ) { + if ( $is_block_theme && ! is_customize_preview() ) { /* * Dequeue the Customizer's custom CSS * and add it before the global styles custom CSS. + * This is not done in the Customizer preview to + * facilitate live previewing changes via + * wp-includes/js/customize-preview.js. */ remove_action( 'wp_head', 'wp_custom_css_cb', 101 ); // Get the custom CSS from the Customizer and add it to the global stylesheet. From 66a2496d58324f638c66873bedb3592b59b42913 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 7 Jul 2025 19:38:28 -0700 Subject: [PATCH 02/10] Revert change to deprecated function --- src/wp-includes/deprecated.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index c8af5d401b280..97183f86479a5 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6372,7 +6372,7 @@ function wp_get_global_styles_custom_css() { */ function wp_enqueue_global_styles_custom_css() { _deprecated_function( __FUNCTION__, '6.7.0', 'wp_enqueue_global_styles' ); - if ( ! wp_is_block_theme() || is_customize_preview() ) { + if ( ! wp_is_block_theme() ) { return; } From a2ffdd0f283f9d99c1a0a639fbe41015e7310fda Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 7 Jul 2025 19:44:58 -0700 Subject: [PATCH 03/10] Ensure global styles are shown in Customizer preview and override Customizer styles in cascade --- src/wp-includes/script-loader.php | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index c9802c6a9e3a6..a9d837b9b4865 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2535,18 +2535,27 @@ function wp_enqueue_global_styles() { $stylesheet = wp_get_global_stylesheet(); - if ( $is_block_theme && ! is_customize_preview() ) { + if ( $is_block_theme ) { /* - * Dequeue the Customizer's custom CSS - * and add it before the global styles custom CSS. - * This is not done in the Customizer preview to - * facilitate live previewing changes via - * wp-includes/js/customize-preview.js. + * Remove the Customizer's Custom CSS from being printed as a separate stylesheet in a block theme since it is + * merged into the global styles. */ remove_action( 'wp_head', 'wp_custom_css_cb', 101 ); - // Get the custom CSS from the Customizer and add it to the global stylesheet. - $custom_css = wp_get_custom_css(); - $stylesheet .= $custom_css; + + if ( is_customize_preview() ) { + /* + * In the Customizer preview, re-add the Customizer's Custom CSS so it is printed in a separate stylesheet + * and before the global styles. A separate stylesheet needs to be printed for the sake of the Customizer's + * live preview which updates the text contents of the STYLE tag. A priority of 7 is used because other + * styles (including global styles) are printed at priority 8 with wp_print_styles(). This better preserves + * the order in the CSS cascade at least for global styles, although it may not have the expected cascade + * for other stylesheets enqueued by the theme or plugins. + */ + add_action( 'wp_head', 'wp_custom_css_cb', 7 ); + } else { + // Get the custom CSS from the Customizer and add it to the global stylesheet. + $stylesheet .= wp_get_custom_css(); + } // Add the global styles custom CSS at the end. $stylesheet .= wp_get_global_stylesheet( array( 'custom-css' ) ); From 5f6ec6fe1912cec06e868e499b8a670a29f0e55a Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 7 Jul 2025 19:53:11 -0700 Subject: [PATCH 04/10] Add Customizer details to the comment --- src/wp-includes/script-loader.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index a9d837b9b4865..23f4577f93f5b 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2547,9 +2547,11 @@ function wp_enqueue_global_styles() { * In the Customizer preview, re-add the Customizer's Custom CSS so it is printed in a separate stylesheet * and before the global styles. A separate stylesheet needs to be printed for the sake of the Customizer's * live preview which updates the text contents of the STYLE tag. A priority of 7 is used because other - * styles (including global styles) are printed at priority 8 with wp_print_styles(). This better preserves + * styles (including global styles) are printed at priority 8 via wp_print_styles(). This better preserves * the order in the CSS cascade at least for global styles, although it may not have the expected cascade - * for other stylesheets enqueued by the theme or plugins. + * for other stylesheets enqueued by themes and plugins. Originally Custom CSS was printed at wp_head with + * a priority of 101 so that it could all other styles. In this way, the Custom CSS in the Customizer is + * de-prioritized when using a block theme, both inside and outside the Customizer. */ add_action( 'wp_head', 'wp_custom_css_cb', 7 ); } else { From e371206917084ad45d39d9e0bead315a0b9c5c94 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 27 Jul 2025 21:34:05 -0700 Subject: [PATCH 05/10] Adopt alternative approach for updating Customizer CSS embedded among global styles --- src/js/_enqueues/wp/customize/preview.js | 15 ++++++++++-- .../class-wp-customize-manager.php | 5 ++-- src/wp-includes/script-loader.php | 23 ++++++++----------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/js/_enqueues/wp/customize/preview.js b/src/js/_enqueues/wp/customize/preview.js index bcff0bc25166c..8253a2a703f1b 100644 --- a/src/js/_enqueues/wp/customize/preview.js +++ b/src/js/_enqueues/wp/customize/preview.js @@ -635,11 +635,22 @@ /** * Preview changes to custom css. * - * @param {string} value Custom CSS.. + * @param {string} value Custom CSS. * @return {void} */ custom_css: function( value ) { - $( '#wp-custom-css' ).text( value ); + var style; + // TODO: If none of the logic in this function resulted in a CSS update (e.g. due to some optimizer plugin that concatenates/minifies CSS), then a message should be sent to the controls to initiate a reload. + if ( api.settings.theme.isBlockTheme ) { + style = $( 'style#global-styles-inline-css' ); + var textContent = style.text().replace( /(\/\*BEGIN_CUSTOMIZER_CUSTOM_CSS\*\/)((?:.|\s)*?)(\/\*END_CUSTOMIZER_CUSTOM_CSS\*\/)/, function ( match, beforeComment, oldValue, afterComment ) { + return beforeComment + value + afterComment; + } ); + style.text( textContent ); + } else { + style = $( 'style#wp-custom-css' ); + style.text( value ); + } }, /** diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index 0d41d4a09bdcb..6a656808ae5a1 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -2161,8 +2161,9 @@ public function customize_preview_settings() { 'keepAliveSend' => 1000, ), 'theme' => array( - 'stylesheet' => $this->get_stylesheet(), - 'active' => $this->is_theme_active(), + 'stylesheet' => $this->get_stylesheet(), + 'active' => $this->is_theme_active(), + 'isBlockTheme' => wp_is_block_theme(), ), 'url' => array( 'self' => $self_url, diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 23f4577f93f5b..a9e19e31e242c 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2542,21 +2542,16 @@ function wp_enqueue_global_styles() { */ remove_action( 'wp_head', 'wp_custom_css_cb', 101 ); + /* + * Get the custom CSS from the Customizer and add it to the global stylesheet. + * When in the Customizer preview, add milestone comments to allow customize-preview.js inject the CSS updates. + */ if ( is_customize_preview() ) { - /* - * In the Customizer preview, re-add the Customizer's Custom CSS so it is printed in a separate stylesheet - * and before the global styles. A separate stylesheet needs to be printed for the sake of the Customizer's - * live preview which updates the text contents of the STYLE tag. A priority of 7 is used because other - * styles (including global styles) are printed at priority 8 via wp_print_styles(). This better preserves - * the order in the CSS cascade at least for global styles, although it may not have the expected cascade - * for other stylesheets enqueued by themes and plugins. Originally Custom CSS was printed at wp_head with - * a priority of 101 so that it could all other styles. In this way, the Custom CSS in the Customizer is - * de-prioritized when using a block theme, both inside and outside the Customizer. - */ - add_action( 'wp_head', 'wp_custom_css_cb', 7 ); - } else { - // Get the custom CSS from the Customizer and add it to the global stylesheet. - $stylesheet .= wp_get_custom_css(); + $stylesheet .= "\n/*BEGIN_CUSTOMIZER_CUSTOM_CSS*/\n"; + } + $stylesheet .= wp_get_custom_css(); + if ( is_customize_preview() ) { + $stylesheet .= "\n/*END_CUSTOMIZER_CUSTOM_CSS*/\n"; } // Add the global styles custom CSS at the end. From 10180bfe73f11461937522b0447e2a8d58821924 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 27 Jul 2025 21:41:21 -0700 Subject: [PATCH 06/10] Prevent milestone comments from appearing in Custom CSS which would break live preview --- src/js/_enqueues/wp/customize/preview.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/_enqueues/wp/customize/preview.js b/src/js/_enqueues/wp/customize/preview.js index 8253a2a703f1b..64bf664ab99d4 100644 --- a/src/js/_enqueues/wp/customize/preview.js +++ b/src/js/_enqueues/wp/customize/preview.js @@ -643,6 +643,7 @@ // TODO: If none of the logic in this function resulted in a CSS update (e.g. due to some optimizer plugin that concatenates/minifies CSS), then a message should be sent to the controls to initiate a reload. if ( api.settings.theme.isBlockTheme ) { style = $( 'style#global-styles-inline-css' ); + value = value.replace( /\/\*(BEGIN|END)_CUSTOMIZER_CUSTOM_CSS\*\//g, '' ); // Forbid milestone comments from appearing in Custom CSS which would break live preview. var textContent = style.text().replace( /(\/\*BEGIN_CUSTOMIZER_CUSTOM_CSS\*\/)((?:.|\s)*?)(\/\*END_CUSTOMIZER_CUSTOM_CSS\*\/)/, function ( match, beforeComment, oldValue, afterComment ) { return beforeComment + value + afterComment; } ); From 6ce405e4a552fae68607efdbe85857a311087395 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 27 Jul 2025 22:23:07 -0700 Subject: [PATCH 07/10] Improve code organization to reduce redundancy and the overall diff --- src/wp-includes/script-loader.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index a9e19e31e242c..68ccebd9b5e0e 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2537,22 +2537,21 @@ function wp_enqueue_global_styles() { if ( $is_block_theme ) { /* - * Remove the Customizer's Custom CSS from being printed as a separate stylesheet in a block theme since it is - * merged into the global styles. + * Dequeue the Customizer's custom CSS + * and add it before the global styles custom CSS. */ remove_action( 'wp_head', 'wp_custom_css_cb', 101 ); - /* - * Get the custom CSS from the Customizer and add it to the global stylesheet. - * When in the Customizer preview, add milestone comments to allow customize-preview.js inject the CSS updates. - */ - if ( is_customize_preview() ) { - $stylesheet .= "\n/*BEGIN_CUSTOMIZER_CUSTOM_CSS*/\n"; - } - $stylesheet .= wp_get_custom_css(); + // Get the custom CSS from the Customizer and add it to the global stylesheet. + $custom_css = wp_get_custom_css(); if ( is_customize_preview() ) { - $stylesheet .= "\n/*END_CUSTOMIZER_CUSTOM_CSS*/\n"; + /* + * When in the Customizer preview, wrap the Custom CSS in milestone comments to allow customize-preview.js + * to locate the CSS to replace for live previewing. + */ + $custom_css = "\n/*BEGIN_CUSTOMIZER_CUSTOM_CSS*/\n{$custom_css}\n/*END_CUSTOMIZER_CUSTOM_CSS*/\n"; } + $stylesheet .= $custom_css; // Add the global styles custom CSS at the end. $stylesheet .= wp_get_global_stylesheet( array( 'custom-css' ) ); From 513687022454a3daff244d562b7ae491bd041ab4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 27 Jul 2025 22:32:40 -0700 Subject: [PATCH 08/10] Make sure saved milestone comments are removed from stored CSS when previewing --- src/wp-includes/script-loader.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 68ccebd9b5e0e..a60dc406e81a0 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2547,9 +2547,14 @@ function wp_enqueue_global_styles() { if ( is_customize_preview() ) { /* * When in the Customizer preview, wrap the Custom CSS in milestone comments to allow customize-preview.js - * to locate the CSS to replace for live previewing. + * to locate the CSS to replace for live previewing. Make sure that the milestone comments are omitted from + * the stored Custom CSS if by chance someone tried to add them, which would be highly unlikely, but it + * would break live previewing. */ - $custom_css = "\n/*BEGIN_CUSTOMIZER_CUSTOM_CSS*/\n{$custom_css}\n/*END_CUSTOMIZER_CUSTOM_CSS*/\n"; + $before_milestone = '/*BEGIN_CUSTOMIZER_CUSTOM_CSS*/'; + $after_milestone = '/*END_CUSTOMIZER_CUSTOM_CSS*/'; + $custom_css = str_replace( array( $before_milestone, $after_milestone ), '', $custom_css ); + $custom_css = $before_milestone . $custom_css . $after_milestone; } $stylesheet .= $custom_css; From 04a9ac75a03ee1bbb51609773bdd88cb40c9e3c9 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 28 Jul 2025 17:34:56 -0700 Subject: [PATCH 09/10] Add line breaks before/after Custom CSS for readability/debugging Co-authored-by: Peter Wilson --- src/js/_enqueues/wp/customize/preview.js | 2 +- src/wp-includes/script-loader.php | 32 ++++++++++++++---------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/js/_enqueues/wp/customize/preview.js b/src/js/_enqueues/wp/customize/preview.js index 64bf664ab99d4..e15f9bba13b61 100644 --- a/src/js/_enqueues/wp/customize/preview.js +++ b/src/js/_enqueues/wp/customize/preview.js @@ -645,7 +645,7 @@ style = $( 'style#global-styles-inline-css' ); value = value.replace( /\/\*(BEGIN|END)_CUSTOMIZER_CUSTOM_CSS\*\//g, '' ); // Forbid milestone comments from appearing in Custom CSS which would break live preview. var textContent = style.text().replace( /(\/\*BEGIN_CUSTOMIZER_CUSTOM_CSS\*\/)((?:.|\s)*?)(\/\*END_CUSTOMIZER_CUSTOM_CSS\*\/)/, function ( match, beforeComment, oldValue, afterComment ) { - return beforeComment + value + afterComment; + return beforeComment + '\n' + value + '\n' + afterComment; } ); style.text( textContent ); } else { diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index a60dc406e81a0..54193c841c7c3 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2542,19 +2542,25 @@ function wp_enqueue_global_styles() { */ remove_action( 'wp_head', 'wp_custom_css_cb', 101 ); - // Get the custom CSS from the Customizer and add it to the global stylesheet. - $custom_css = wp_get_custom_css(); - if ( is_customize_preview() ) { - /* - * When in the Customizer preview, wrap the Custom CSS in milestone comments to allow customize-preview.js - * to locate the CSS to replace for live previewing. Make sure that the milestone comments are omitted from - * the stored Custom CSS if by chance someone tried to add them, which would be highly unlikely, but it - * would break live previewing. - */ - $before_milestone = '/*BEGIN_CUSTOMIZER_CUSTOM_CSS*/'; - $after_milestone = '/*END_CUSTOMIZER_CUSTOM_CSS*/'; - $custom_css = str_replace( array( $before_milestone, $after_milestone ), '', $custom_css ); - $custom_css = $before_milestone . $custom_css . $after_milestone; + /* + * Get the custom CSS from the Customizer and add it to the global stylesheet. + * Always do this in Customizer preview for the sake of live preview since it be empty. + */ + $custom_css = trim( wp_get_custom_css() ); + if ( $custom_css || is_customize_preview() ) { + if ( is_customize_preview() ) { + /* + * When in the Customizer preview, wrap the Custom CSS in milestone comments to allow customize-preview.js + * to locate the CSS to replace for live previewing. Make sure that the milestone comments are omitted from + * the stored Custom CSS if by chance someone tried to add them, which would be highly unlikely, but it + * would break live previewing. + */ + $before_milestone = '/*BEGIN_CUSTOMIZER_CUSTOM_CSS*/'; + $after_milestone = '/*END_CUSTOMIZER_CUSTOM_CSS*/'; + $custom_css = str_replace( array( $before_milestone, $after_milestone ), '', $custom_css ); + $custom_css = $before_milestone . "\n" . $custom_css . "\n" . $after_milestone; + } + $custom_css = "\n" . $custom_css; } $stylesheet .= $custom_css; From 398f9bea29105fb8b1ff0f84904341aa3804ee66 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 28 Jul 2025 17:39:14 -0700 Subject: [PATCH 10/10] Remove TODO comment in favor of leaving in Trac comment Co-authored-by: t-hamano --- src/js/_enqueues/wp/customize/preview.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/_enqueues/wp/customize/preview.js b/src/js/_enqueues/wp/customize/preview.js index e15f9bba13b61..2055b5e792ee5 100644 --- a/src/js/_enqueues/wp/customize/preview.js +++ b/src/js/_enqueues/wp/customize/preview.js @@ -640,7 +640,6 @@ */ custom_css: function( value ) { var style; - // TODO: If none of the logic in this function resulted in a CSS update (e.g. due to some optimizer plugin that concatenates/minifies CSS), then a message should be sent to the controls to initiate a reload. if ( api.settings.theme.isBlockTheme ) { style = $( 'style#global-styles-inline-css' ); value = value.replace( /\/\*(BEGIN|END)_CUSTOMIZER_CUSTOM_CSS\*\//g, '' ); // Forbid milestone comments from appearing in Custom CSS which would break live preview.