From c124eb5774a2bbaaa1f913a9d8804101e5e9cf1b Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 17 Dec 2025 12:45:32 +0100 Subject: [PATCH 01/13] Update wp_custom_css_cb to rely on HTML API for safe SCRIPT tag printing. --- src/wp-includes/theme.php | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index 558bea6ae9e02..b9c4945fa5e6a 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -1967,17 +1967,18 @@ function _custom_background_cb() { */ function wp_custom_css_cb() { $styles = wp_get_custom_css(); - if ( $styles || is_customize_preview() ) : - $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"'; - ?> - id="wp-custom-css"> - - - ' ); + $processor->next_tag(); + if ( ! current_theme_supports( 'html5', 'style' ) ) { + $processor->set_attribute( 'type', 'text/css' ); + } + $processor->set_attribute( 'id', 'wp-custom-css' ); + $processor->set_modifiable_text( $styles ); + echo $processor->get_updated_html(); } /** From e05515657939360a76195b3c66c0a7cb83e56ff4 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 17 Dec 2025 12:48:39 +0100 Subject: [PATCH 02/13] Wrap customizer CSS test in newlines --- src/wp-includes/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index b9c4945fa5e6a..452b2588ebe9f 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -1977,7 +1977,7 @@ function wp_custom_css_cb() { $processor->set_attribute( 'type', 'text/css' ); } $processor->set_attribute( 'id', 'wp-custom-css' ); - $processor->set_modifiable_text( $styles ); + $processor->set_modifiable_text( "\n{$styles}\n" ); echo $processor->get_updated_html(); } From 33f96169b9dcc21cb9cc919ffc32f2132a5d053f Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 17 Dec 2025 12:55:21 +0100 Subject: [PATCH 03/13] Use HTML API for style tags in script-loader --- src/wp-includes/script-loader.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 56986c3d80a79..e968ecb693758 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2417,10 +2417,12 @@ function _print_styles() { echo "\n"; if ( ! empty( $wp_styles->print_code ) ) { - echo "\n"; - echo $wp_styles->print_code; - echo sprintf( "\n/*# sourceURL=%s */", rawurlencode( $concat_source_url ) ); - echo "\n\n"; + $processor = new WP_HTML_Tag_Processor( "" ); + $processor->next_tag(); + $style_tag_contents = "\n{$wp_styles->print_code}\n" + . sprintf( "/*# sourceURL=%s */\n", rawurlencode( $concat_source_url ) ); + $processor->set_modifiable_text( $style_tag_contents ); + echo $processor->get_updated_html(); } } @@ -3217,7 +3219,10 @@ function wp_enqueue_block_support_styles( $style, $priority = 10 ) { add_action( $action_hook_name, static function () use ( $style ) { - echo "\n"; + $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor->next_tag(); + $processor->set_modifiable_text( $style ); + echo $processor->get_updated_html(); }, $priority ); From 606539ea18065a60b3181752705c7376c6a29e9a Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 17 Dec 2025 13:06:48 +0100 Subject: [PATCH 04/13] Use HTML Tag Processor to produce WP_Styles style tags --- src/wp-includes/class-wp-styles.php | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/wp-includes/class-wp-styles.php b/src/wp-includes/class-wp-styles.php index 9b210b2df9d30..6d47bc15d56fd 100644 --- a/src/wp-includes/class-wp-styles.php +++ b/src/wp-includes/class-wp-styles.php @@ -183,12 +183,11 @@ public function do_item( $handle, $group = false ) { $inline_style = $this->print_inline_style( $handle, false ); if ( $inline_style ) { - $inline_style_tag = sprintf( - "\n", - esc_attr( $handle ), - $this->type_attr, - $inline_style - ); + $processor = new WP_HTML_Tag_Processor( "type_attr}>\n" ); + $processor->next_tag(); + $processor->set_attribute( 'id', "{$handle}-inline-css" ); + $processor->set_modifiable_text( "\n{$inline_style}\n" ); + $inline_style_tag = $processor->get_updated_html(); } else { $inline_style_tag = ''; } @@ -364,12 +363,11 @@ public function print_inline_style( $handle, $display = true ) { return $output; } - printf( - "\n", - esc_attr( $handle ), - $this->type_attr, - $output - ); + $processor = new WP_HTML_Tag_Processor( "type_attr}>\n" ); + $processor->next_tag(); + $processor->set_attribute( 'id', "{$handle}-inline-css" ); + $processor->set_modifiable_text( "\n{$output}\n" ); + echo $processor->get_updated_html(); return true; } From c938d4c8a7e0719a879d65d273e077dbcff6343f Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 17 Dec 2025 13:15:37 +0100 Subject: [PATCH 05/13] Use HTML Tag Processor for STYLE tags in theme.php --- src/wp-includes/theme.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index 452b2588ebe9f..b8d35a255d35c 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -1953,11 +1953,13 @@ function _custom_background_cb() { $style .= $image . $position . $size . $repeat . $attachment; } - ?> - id="custom-background-css"> -body.custom-background { } - - " ); + $processor->next_tag(); + + $style_tag_content = 'body.custom-background { ' . trim( $style ) . ' }'; + $processor->set_modifiable_text( "\n{$style_tag_content}\n" ); + echo $processor->get_updated_html(); } /** @@ -1967,7 +1969,7 @@ function _custom_background_cb() { */ function wp_custom_css_cb() { $styles = wp_get_custom_css(); - if ( ! $styles || ! is_customize_preview() ) { + if ( ! $styles && ! is_customize_preview() ) { return; } From dd919f13c7ce2322a90d6f70a587518a32147e00 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 23 Dec 2025 13:40:23 +0100 Subject: [PATCH 06/13] Build font style tags with HTML API --- src/wp-includes/fonts/class-wp-font-face.php | 36 ++++---------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/src/wp-includes/fonts/class-wp-font-face.php b/src/wp-includes/fonts/class-wp-font-face.php index 07cd3d6de9002..fd66825a0b4e5 100644 --- a/src/wp-includes/fonts/class-wp-font-face.php +++ b/src/wp-includes/fonts/class-wp-font-face.php @@ -118,7 +118,13 @@ public function generate_and_print( array $fonts ) { return; } - printf( $this->get_style_element(), $css ); + $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor->next_tag(); + foreach ( $this->style_tag_attrs as $name => $value ) { + $processor->set_attribute( $name, $value ); + } + $processor->set_modifiable_text( "\n{$css}\n" ); + echo $processor->get_updated_html(); } /** @@ -219,34 +225,6 @@ private function validate_font_face_declarations( array $font_face ) { return $font_face; } - /** - * Gets the style element for wrapping the `@font-face` CSS. - * - * @since 6.4.0 - * - * @return string The style element. - */ - private function get_style_element() { - $attributes = $this->generate_style_element_attributes(); - - return "\n"; - } - - /** - * Gets the defined \n"; $expected_output = sprintf( $style_element, $expected ); - $this->expectOutputString( $expected_output ); - $font_face->generate_and_print( $fonts ); + $output = get_echo( + function () use ( $font_face, $fonts ) { + $font_face->generate_and_print( $fonts ); + } + ); + $this->assertEqualHTML( $expected_output, $output ); } } diff --git a/tests/phpunit/tests/fonts/font-face/wpPrintFontFaces.php b/tests/phpunit/tests/fonts/font-face/wpPrintFontFaces.php index 2fa64559c2049..1d6ef663c5f22 100644 --- a/tests/phpunit/tests/fonts/font-face/wpPrintFontFaces.php +++ b/tests/phpunit/tests/fonts/font-face/wpPrintFontFaces.php @@ -37,8 +37,12 @@ public function test_should_not_print_when_no_fonts() { public function test_should_print_given_fonts( array $fonts, $expected ) { $expected_output = $this->get_expected_styles_output( $expected ); - $this->expectOutputString( $expected_output ); - wp_print_font_faces( $fonts ); + $output = get_echo( + function () use ( $fonts ) { + wp_print_font_faces( $fonts ); + } + ); + $this->assertEqualHTML( $expected_output, $output ); } public function test_should_escape_tags() { @@ -60,9 +64,13 @@ public function test_should_escape_tags() { CSS; - $this->expectOutputString( $expected_output ); - wp_print_font_faces( $fonts ); + $output = get_echo( + function () use ( $fonts ) { + wp_print_font_faces( $fonts ); + } + ); + $this->assertEqualHTML( $expected_output, $output ); } public function test_should_print_fonts_in_merged_data() { @@ -71,8 +79,8 @@ public function test_should_print_fonts_in_merged_data() { $expected = $this->get_expected_fonts_for_fonts_block_theme( 'font_face_styles' ); $expected_output = $this->get_expected_styles_output( $expected ); - $this->expectOutputString( $expected_output ); - wp_print_font_faces(); + $output = get_echo( 'wp_print_font_faces' ); + $this->assertEqualHTML( $expected_output, $output ); } private function get_expected_styles_output( $styles ) { diff --git a/tests/phpunit/tests/fonts/font-face/wpPrintFontFacesFromStyleVariations.php b/tests/phpunit/tests/fonts/font-face/wpPrintFontFacesFromStyleVariations.php index a59ba882a4e86..5dd6304fd2f7b 100644 --- a/tests/phpunit/tests/fonts/font-face/wpPrintFontFacesFromStyleVariations.php +++ b/tests/phpunit/tests/fonts/font-face/wpPrintFontFacesFromStyleVariations.php @@ -43,8 +43,8 @@ public function test_should_print_fonts_in_style_variations() { $expected = $this->get_custom_style_variations( 'expected_styles' ); $expected_output = $this->get_expected_styles_output( $expected ); - $this->expectOutputString( $expected_output ); - wp_print_font_faces_from_style_variations(); + $output = get_echo( 'wp_print_font_faces_from_style_variations' ); + $this->assertEqualHTML( $expected_output, $output ); } private function get_expected_styles_output( $styles ) { From 6c6a72b07dea9150d26ef9b7a767b22c67e83c5a Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 23 Dec 2025 14:19:49 +0100 Subject: [PATCH 08/13] Use HTML API for hide header text --- src/wp-includes/theme.php | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index b8d35a255d35c..18b4d98b5ed73 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -3010,16 +3010,24 @@ function _custom_logo_header_styles() { $classes = array_map( 'sanitize_html_class', $classes ); $classes = '.' . implode( ', .', $classes ); - $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"'; - ?> - - - \n" + ); + $processor->next_tag(); + if ( ! current_theme_supports( 'html5', 'style' ) ) { + $processor->set_attribute( 'type', 'text/css' ); + } + $processor->set_modifiable_text( $css ); + echo $processor->get_updated_html(); } } From aad4744b50a4af3f714cb94ec2ea0cde3e455a81 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 23 Dec 2025 14:19:52 +0100 Subject: [PATCH 09/13] Revert "Use HTML API for hide header text" This reverts commit 6c6a72b07dea9150d26ef9b7a767b22c67e83c5a. --- src/wp-includes/theme.php | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index 18b4d98b5ed73..b8d35a255d35c 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -3010,24 +3010,16 @@ function _custom_logo_header_styles() { $classes = array_map( 'sanitize_html_class', $classes ); $classes = '.' . implode( ', .', $classes ); - $css = <<<"CSS" - -{$classes} { - position: absolute; - clip-path: inset(50%); -} - -CSS; - - $processor = new WP_HTML_Tag_Processor( - "\n" - ); - $processor->next_tag(); - if ( ! current_theme_supports( 'html5', 'style' ) ) { - $processor->set_attribute( 'type', 'text/css' ); - } - $processor->set_modifiable_text( $css ); - echo $processor->get_updated_html(); + $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"'; + ?> + + + Date: Fri, 26 Dec 2025 22:45:33 +0100 Subject: [PATCH 10/13] Fix lint --- src/wp-includes/script-loader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index e3d1c446e33b1..e63012b31f594 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2415,7 +2415,7 @@ function _print_styles() { echo "\n"; if ( ! empty( $wp_styles->print_code ) ) { - $processor = new WP_HTML_Tag_Processor( "" ); + $processor = new WP_HTML_Tag_Processor( '' ); $processor->next_tag(); $style_tag_contents = "\n{$wp_styles->print_code}\n" . sprintf( "/*# sourceURL=%s */\n", rawurlencode( $concat_source_url ) ); From 0141653ab81876a8d7930db11aadaff15cf5bdf6 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Mon, 29 Dec 2025 18:08:54 +0100 Subject: [PATCH 11/13] Restore STYLE tag trailing newline Co-authored-by: Weston Ruter --- src/wp-includes/script-loader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index bd4f15359680c..c38d662666ee0 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2413,7 +2413,7 @@ function _print_styles() { echo "\n"; if ( ! empty( $wp_styles->print_code ) ) { - $processor = new WP_HTML_Tag_Processor( '' ); + $processor = new WP_HTML_Tag_Processor( "\n" ); $processor->next_tag(); $style_tag_contents = "\n{$wp_styles->print_code}\n" . sprintf( "/*# sourceURL=%s */\n", rawurlencode( $concat_source_url ) ); From 658509902d218a1bf3a721a162ddd6c5a34bbd4a Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Mon, 29 Dec 2025 19:47:30 +0100 Subject: [PATCH 12/13] Restore STYLE tag trailing newlines in theme.php Co-authored-by: Weston Ruter --- src/wp-includes/theme.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index adf3b50555118..44fd522aaeaae 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -1951,7 +1951,7 @@ function _custom_background_cb() { $style .= $image . $position . $size . $repeat . $attachment; } - $processor = new WP_HTML_Tag_Processor( "" ); + $processor = new WP_HTML_Tag_Processor( "\n" ); $processor->next_tag(); $style_tag_content = 'body.custom-background { ' . trim( $style ) . ' }'; @@ -1970,7 +1970,7 @@ function wp_custom_css_cb() { return; } - $processor = new WP_HTML_Tag_Processor( '' ); + $processor = new WP_HTML_Tag_Processor( "\n" ); $processor->next_tag(); if ( ! current_theme_supports( 'html5', 'style' ) ) { $processor->set_attribute( 'type', 'text/css' ); From 407d43f838826d709305b4da8e92d4d7d6210154 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 30 Dec 2025 10:42:53 +0100 Subject: [PATCH 13/13] Move trailing newline out of Tag Processor --- src/wp-includes/class-wp-styles.php | 8 ++++---- src/wp-includes/fonts/class-wp-font-face.php | 4 ++-- src/wp-includes/script-loader.php | 8 ++++---- src/wp-includes/theme.php | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/wp-includes/class-wp-styles.php b/src/wp-includes/class-wp-styles.php index e19a7645f93e8..72af6c29b0171 100644 --- a/src/wp-includes/class-wp-styles.php +++ b/src/wp-includes/class-wp-styles.php @@ -158,11 +158,11 @@ public function do_item( $handle, $group = false ) { $inline_style = $this->print_inline_style( $handle, false ); if ( $inline_style ) { - $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor = new WP_HTML_Tag_Processor( '' ); $processor->next_tag(); $processor->set_attribute( 'id', "{$handle}-inline-css" ); $processor->set_modifiable_text( "\n{$inline_style}\n" ); - $inline_style_tag = $processor->get_updated_html(); + $inline_style_tag = "{$processor->get_updated_html()}\n"; } else { $inline_style_tag = ''; } @@ -336,11 +336,11 @@ public function print_inline_style( $handle, $display = true ) { return $output; } - $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor = new WP_HTML_Tag_Processor( '' ); $processor->next_tag(); $processor->set_attribute( 'id', "{$handle}-inline-css" ); $processor->set_modifiable_text( "\n{$output}\n" ); - echo $processor->get_updated_html(); + echo "{$processor->get_updated_html()}\n"; return true; } diff --git a/src/wp-includes/fonts/class-wp-font-face.php b/src/wp-includes/fonts/class-wp-font-face.php index 4c3100e66992b..193a5d0951ddb 100644 --- a/src/wp-includes/fonts/class-wp-font-face.php +++ b/src/wp-includes/fonts/class-wp-font-face.php @@ -92,10 +92,10 @@ public function generate_and_print( array $fonts ) { return; } - $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor = new WP_HTML_Tag_Processor( '' ); $processor->next_tag(); $processor->set_modifiable_text( "\n{$css}\n" ); - echo $processor->get_updated_html(); + echo "{$processor->get_updated_html()}\n"; } /** diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index c38d662666ee0..fb9cebbf4b551 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2413,12 +2413,12 @@ function _print_styles() { echo "\n"; if ( ! empty( $wp_styles->print_code ) ) { - $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor = new WP_HTML_Tag_Processor( '' ); $processor->next_tag(); $style_tag_contents = "\n{$wp_styles->print_code}\n" . sprintf( "/*# sourceURL=%s */\n", rawurlencode( $concat_source_url ) ); $processor->set_modifiable_text( $style_tag_contents ); - echo $processor->get_updated_html(); + echo "{$processor->get_updated_html()}\n"; } } @@ -3148,10 +3148,10 @@ function wp_enqueue_block_support_styles( $style, $priority = 10 ) { add_action( $action_hook_name, static function () use ( $style ) { - $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor = new WP_HTML_Tag_Processor( '' ); $processor->next_tag(); $processor->set_modifiable_text( $style ); - echo $processor->get_updated_html(); + echo "{$processor->get_updated_html()}\n"; }, $priority ); diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index 44fd522aaeaae..0ff915cbe4263 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -1951,12 +1951,12 @@ function _custom_background_cb() { $style .= $image . $position . $size . $repeat . $attachment; } - $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor = new WP_HTML_Tag_Processor( "" ); $processor->next_tag(); $style_tag_content = 'body.custom-background { ' . trim( $style ) . ' }'; $processor->set_modifiable_text( "\n{$style_tag_content}\n" ); - echo $processor->get_updated_html(); + echo "{$processor->get_updated_html()}\n"; } /** @@ -1970,14 +1970,14 @@ function wp_custom_css_cb() { return; } - $processor = new WP_HTML_Tag_Processor( "\n" ); + $processor = new WP_HTML_Tag_Processor( '' ); $processor->next_tag(); if ( ! current_theme_supports( 'html5', 'style' ) ) { $processor->set_attribute( 'type', 'text/css' ); } $processor->set_attribute( 'id', 'wp-custom-css' ); $processor->set_modifiable_text( "\n{$styles}\n" ); - echo $processor->get_updated_html(); + echo "{$processor->get_updated_html()}\n"; } /**