Skip to content

Commit 53d21e6

Browse files
committed
Print block styles after wp-block-library and everything else at end of HEAD
1 parent d5a964b commit 53d21e6

File tree

2 files changed

+84
-31
lines changed

2 files changed

+84
-31
lines changed

src/wp-includes/script-loader.php

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3634,7 +3634,7 @@ function wp_hoist_late_printed_styles() {
36343634
* enhancement output buffer, essentially no style can be enqueued too late, because an output buffer filter can
36353635
* always hoist it to the HEAD.
36363636
*/
3637-
add_filter( 'print_late_styles', '__return_true', PHP_INT_MAX );
3637+
add_filter( 'print_late_styles', '__return_true', PHP_INT_MAX ); // TODO: Remove.
36383638

36393639
/*
36403640
* Print a placeholder comment where the late styles can be hoisted from the footer to be printed in the header
@@ -3645,11 +3645,44 @@ function wp_hoist_late_printed_styles() {
36453645
wp_add_inline_style( 'wp-block-library', $placeholder );
36463646

36473647
// Wrap print_late_styles() with a closure that captures the late-printed styles.
3648-
$printed_late_styles = '';
3649-
$capture_late_styles = static function () use ( &$printed_late_styles ) {
3648+
$printed_block_styles = '';
3649+
$printed_late_styles = '';
3650+
$capture_late_styles = static function () use ( &$printed_block_styles, &$printed_late_styles ) {
3651+
global $concatenate_scripts;
3652+
script_concat_settings();
3653+
3654+
// Print the styles related to on-demand block enqueues.
3655+
$all_block_style_handles = array();
3656+
foreach ( WP_Block_Type_Registry::get_instance()->get_all_registered() as $block_type ) {
3657+
foreach ( $block_type->style_handles as $style_handle ) {
3658+
$all_block_style_handles[] = $style_handle;
3659+
}
3660+
}
3661+
$all_block_style_handles = array_merge(
3662+
$all_block_style_handles,
3663+
array( 'global-styles', 'core-block-supports', 'block-style-variation-styles' ) // TODO: What else?
3664+
);
3665+
3666+
$enqueued_block_styles = array_values( array_intersect( $all_block_style_handles, wp_styles()->queue ) );
3667+
if ( count( $enqueued_block_styles ) > 0 ) {
3668+
wp_styles()->do_concat = $concatenate_scripts;
3669+
ob_start();
3670+
wp_styles()->do_items( $enqueued_block_styles );
3671+
_print_styles();
3672+
$printed_block_styles = ob_get_clean();
3673+
wp_styles()->reset();
3674+
}
3675+
3676+
/*
3677+
* Print remaining styles not related to blocks. This is the same logic as in print_late_styles(), but without
3678+
* the filter to control whether late styles are printed (since they are being hoisted anyway).
3679+
*/
3680+
wp_styles()->do_concat = $concatenate_scripts;
36503681
ob_start();
3651-
print_late_styles();
3682+
wp_styles()->do_footer_items();
3683+
_print_styles();
36523684
$printed_late_styles = ob_get_clean();
3685+
wp_styles()->reset();
36533686
};
36543687

36553688
/*
@@ -3680,7 +3713,7 @@ static function () use ( $capture_late_styles ) {
36803713
// Replace placeholder with the captured late styles.
36813714
add_filter(
36823715
'wp_template_enhancement_output_buffer',
3683-
function ( $buffer ) use ( $placeholder, &$printed_late_styles ) {
3716+
function ( $buffer ) use ( $placeholder, &$printed_block_styles, &$printed_late_styles ) {
36843717

36853718
// Anonymous subclass of WP_HTML_Tag_Processor which exposes underlying bookmark spans.
36863719
$processor = new class( $buffer ) extends WP_HTML_Tag_Processor {
@@ -3690,19 +3723,18 @@ public function get_span(): WP_HTML_Span {
36903723
}
36913724
};
36923725

3693-
// Loop over STYLE tags.
3694-
while ( $processor->next_tag( array( 'tag_closers' => 'visit' ) ) ) {
3695-
3696-
// We've encountered the inline style for the 'wp-block-library' stylesheet which probably has the placeholder comment.
3726+
// TODO: If there are no block styles to print, it would be nice to not have to replace the placehoolder comment.
3727+
// Locate the inline style for the 'wp-block-library' stylesheet which probably has the placeholder comment.
3728+
while ( $processor->next_tag( array( 'tag_name' => 'STYLE' ) ) ) {
36973729
if (
36983730
! $processor->is_tag_closer() &&
36993731
'STYLE' === $processor->get_tag() &&
37003732
'wp-block-library-inline-css' === $processor->get_attribute( 'id' )
37013733
) {
3702-
// If the inline style lacks the placeholder comment, then we have to continue until we get to </HEAD> to append the styles there.
3734+
// If the inline style lacks the placeholder comment, then all the styles will be inserted below before </HEAD>.
37033735
$css_text = $processor->get_modifiable_text();
37043736
if ( ! str_contains( $css_text, $placeholder ) ) {
3705-
continue;
3737+
break;
37063738
}
37073739

37083740
// Remove the placeholder now that we've located the inline style.
@@ -3715,25 +3747,47 @@ public function get_span(): WP_HTML_Span {
37153747
'',
37163748
array(
37173749
substr( $buffer, 0, $span->start + $span->length ),
3718-
$printed_late_styles,
3750+
$printed_block_styles,
37193751
substr( $buffer, $span->start + $span->length ),
37203752
)
37213753
);
3754+
3755+
// Prevent printing them again.
3756+
$printed_block_styles = '';
37223757
break;
37233758
}
3759+
}
3760+
3761+
// If there are remaining styles to hoist, either because
3762+
if ( $printed_block_styles || $printed_late_styles ) {
3763+
3764+
// Anonymous subclass of WP_HTML_Tag_Processor which exposes underlying bookmark spans.
3765+
$processor = new class( $buffer ) extends WP_HTML_Tag_Processor {
3766+
public function get_span(): WP_HTML_Span {
3767+
$this->set_bookmark( 'here' );
3768+
return $this->bookmarks['here'];
3769+
}
3770+
};
37243771

37253772
// As a fallback, append the hoisted late styles to the end of the HEAD.
3726-
if ( $processor->is_tag_closer() && 'HEAD' === $processor->get_tag() ) {
3727-
$span = $processor->get_span();
3728-
$buffer = implode(
3729-
'',
3730-
array(
3731-
substr( $buffer, 0, $span->start ),
3732-
$printed_late_styles,
3733-
substr( $buffer, $span->start ),
3734-
)
3735-
);
3736-
break;
3773+
while ( $processor->next_tag(
3774+
array(
3775+
'tag_name' => 'HEAD',
3776+
'tag_closers' => 'visit',
3777+
)
3778+
) ) {
3779+
if ( $processor->is_tag_closer() ) {
3780+
$span = $processor->get_span();
3781+
$buffer = implode(
3782+
'',
3783+
array(
3784+
substr( $buffer, 0, $span->start ),
3785+
$printed_block_styles . $printed_late_styles,
3786+
substr( $buffer, $span->start ),
3787+
)
3788+
);
3789+
break;
3790+
}
37373791
}
37383792
}
37393793

tests/phpunit/tests/template.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,9 +1075,7 @@ public function data_wp_hoist_late_printed_styles(): array {
10751075
'early-css',
10761076
'early-inline-css',
10771077
'wp-emoji-styles-inline-css',
1078-
'wp-block-library-css',
10791078
'wp-block-library-inline-css',
1080-
10811079
'wp-block-separator-inline-css',
10821080
'global-styles-inline-css',
10831081
'core-block-supports-inline-css',
@@ -1109,16 +1107,14 @@ public function data_wp_hoist_late_printed_styles(): array {
11091107
'wp-emoji-styles-inline-css',
11101108
'wp-block-library-css',
11111109
'wp-block-library-inline-css',
1112-
'late-css',
1113-
'late-inline-css',
1114-
1115-
// TODO: The following three are enqueued in a different order compared to $expected_head_styles above. Why?
11161110
'core-block-supports-inline-css',
11171111
'classic-theme-styles-inline-css',
11181112
'global-styles-inline-css',
1119-
11201113
'normal-css',
11211114
'normal-inline-css',
1115+
'wp-custom-css',
1116+
'late-css',
1117+
'late-inline-css',
11221118
),
11231119
),
11241120
'disabled_printing_late_styles' => array(
@@ -1183,6 +1179,8 @@ public function data_wp_hoist_late_printed_styles(): array {
11831179
*/
11841180
public function test_wp_hoist_late_printed_styles( ?Closure $set_up, array $theme_supports, array $expected ): void {
11851181
switch_theme( 'default' );
1182+
global $wp_styles;
1183+
$wp_styles = null;
11861184

11871185
foreach ( $theme_supports as $theme_support ) {
11881186
add_theme_support( $theme_support );
@@ -1205,6 +1203,7 @@ static function () {
12051203
foreach ( array_keys( $block_registry->get_all_registered() ) as $block_name ) {
12061204
$block_registry->unregister( $block_name );
12071205
}
1206+
register_core_block_style_handles();
12081207
register_core_block_types_from_metadata();
12091208

12101209
$this->assertFalse( wp_is_block_theme(), 'Test is only relevant to block themes.' );
@@ -1252,7 +1251,7 @@ static function () {
12521251

12531252
$this->assertStringContainsString( '</head>', $buffer, 'Expected the closing HEAD tag to be in the response.' );
12541253

1255-
$this->assertDoesNotMatchRegularExpression( '#/\*wp_late_styles_placeholder:[a-f0-9-]+\*/#', $filtered_buffer, 'Expected the placeholder to be removed.' );
1254+
$this->assertDoesNotMatchRegularExpression( '#/\*wp_late_styles_placeholder:[a-f0-9]+\*/#', $filtered_buffer, 'Expected the placeholder to be removed.' );
12561255
$found_styles = array(
12571256
'HEAD' => array(),
12581257
'BODY' => array(),

0 commit comments

Comments
 (0)