Skip to content
Closed
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
137e732
Use well-formed HTML in tests
westonruter Oct 28, 2025
f5d49cd
Use HTTPS and fix late inline style contents
westonruter Oct 28, 2025
cccb1ef
Add separate test case specifically for filtering print_late_styles
westonruter Oct 28, 2025
137b9de
Add comment for PHPCompatibility issue
westonruter Oct 28, 2025
8975233
Use more specific return type for WP_Block_Type_Registry::get_all_reg…
westonruter Oct 29, 2025
6308437
Remove PHPCompatibility.FunctionDeclarations.NewClosure.ThisFoundOuts…
westonruter Oct 29, 2025
2d94ec6
Add a rendered block to the output
westonruter Oct 29, 2025
2d537f7
Add failing test cases for test_wp_hoist_late_printed_styles
westonruter Oct 29, 2025
92cd33c
Exclude PHPCompatibility.FunctionDeclarations.NewClosure.ThisFoundOut…
westonruter Oct 30, 2025
d5a964b
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Nov 2, 2025
53d21e6
Print block styles after wp-block-library and everything else at end …
westonruter Nov 2, 2025
9d8bd27
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Nov 5, 2025
156c6f5
Add example for get_array_snapshot_export
westonruter Nov 5, 2025
16d3f54
Prevent enabling should_load_block_assets_on_demand if should_load_se…
westonruter Nov 5, 2025
99b1b42
Improve tests
westonruter Nov 5, 2025
28faf6d
Remove obsolete print_late_styles override
westonruter Nov 5, 2025
d305804
Update tests
westonruter Nov 5, 2025
e8482a0
Add todo comments
westonruter Nov 5, 2025
54b2474
Refactor HTML Tag Processor logic
westonruter Nov 5, 2025
d93e767
Fix missing use of footer in assertion
westonruter Nov 5, 2025
ec25a5f
Use correct variable in assertion
westonruter Nov 5, 2025
53ef0c6
Remove unhelpful test cases since print_late_styles filter seems to h…
westonruter Nov 5, 2025
ead1aa2
Set styles_inline_size_limit to unlimited for test
westonruter Nov 5, 2025
d2afb80
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Nov 5, 2025
27f5e33
Opt to set styles_inline_size_limit to zero for test
westonruter Nov 5, 2025
3c77325
Test that non-empty wp-block-library inline style is not removed
westonruter Nov 5, 2025
12d4ae7
Consolidate assertions
westonruter Nov 5, 2025
1e5797c
Fix classic_theme_with_should_load_separate_core_block_assets_opt_out…
westonruter Nov 5, 2025
08f4809
Empty out added theme supports before running tests
westonruter Nov 5, 2025
a9a54ca
Add core-block-supports-duotone to the list of styles to print after …
westonruter Nov 5, 2025
c7a4c64
Improve formatting of empty array in export
westonruter Nov 5, 2025
a8fe022
Restore original block type registry after test
westonruter Nov 5, 2025
0ad3084
Fix tests when run as part of enture test suite
westonruter Nov 5, 2025
e3e5b3b
Revert unrelated WP_Block_Type_Registry change
westonruter Nov 5, 2025
9cc527e
Restore original_ini_config
westonruter Nov 5, 2025
dac85df
Remove admin-specific style printing logic
westonruter Nov 5, 2025
0d65fca
Carify comments
westonruter Nov 5, 2025
5d22771
Add test for when styles_inline_size_limit is unlimited
westonruter Nov 5, 2025
56c35c8
Remove obsolete wp_block_styles_not_supported test
westonruter Nov 5, 2025
73c5b07
Remove test for test which is not worthwhile
westonruter Nov 5, 2025
2fed203
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Nov 5, 2025
18691a4
Replace todo with explanation of why set_bookmark will never return f…
westonruter Nov 5, 2025
3f0ac52
Restore comment to _wp_footer_scripts()
westonruter Nov 5, 2025
34d7573
Restore and update comment for _wp_footer_scripts()
westonruter Nov 5, 2025
2524386
Add assertion to ensure wp-block-separator style is registered
westonruter Nov 6, 2025
fd0c402
Debug
westonruter Nov 6, 2025
c2fd29f
Undebug
westonruter Nov 6, 2025
4447f46
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Nov 7, 2025
9607f0e
Opt for ignore list rather than ack list
westonruter Nov 7, 2025
9b86cde
Only use placeholder comment for ensuring wp-block-library inline sty…
westonruter Nov 7, 2025
9f816a3
Improve ensure_style_asset_file_created helper
westonruter Nov 7, 2025
b8f8d37
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Nov 7, 2025
0a6564e
Remove see wrappers of auto-linked function names in dev docs.
peterwilsoncc Nov 7, 2025
885bddd
Add missing static to closure
westonruter Nov 7, 2025
2216f14
Unimprove ensure_style_asset_file_created helper
westonruter Nov 7, 2025
732b28e
Update phpcs exclusion after 885bdddd720f45ad13c920f83f1a7a19a3c7acca
westonruter Nov 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions phpcompat.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,12 @@
<exclude-pattern>/sodium_compat/src/PHP52/SplFixedArray\.php$</exclude-pattern>
</rule>

<!--
Excluded while waiting for PHPCompatibility v10.
See <https://github.com/PHPCompatibility/PHPCompatibility/issues/1481>.
-->
<rule ref="PHPCompatibility.FunctionDeclarations.NewClosure.ThisFoundOutsideClass">
<exclude-pattern>/src/wp-includes/script-loader\.php$</exclude-pattern>
</rule>

</ruleset>
2 changes: 1 addition & 1 deletion src/wp-includes/class-wp-block-type-registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public function get_registered( $name ) {
*
* @since 5.0.0
*
* @return WP_Block_Type[] Associative array of `$block_type_name => $block_type` pairs.
* @return array<string, WP_Block_Type> Associative array of `$block_type_name => $block_type` pairs.
*/
public function get_all_registered() {
return $this->registered_block_types;
Expand Down
144 changes: 91 additions & 53 deletions src/wp-includes/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -3607,20 +3607,23 @@ function wp_load_classic_theme_block_styles_on_demand() {
// The following two filters are added by default for block themes in _add_default_theme_supports().

/*
* Load separate block styles so that the large block-library stylesheet is not enqueued unconditionally,
* and so that block-specific styles will only be enqueued when they are used on the page.
* A priority of zero allows for this to be easily overridden by themes which wish to opt out.
* Load separate block styles so that the large block-library stylesheet is not enqueued unconditionally, and so
* that block-specific styles will only be enqueued when they are used on the page. A priority of zero allows for
* this to be easily overridden by themes which wish to opt out. If a site has explicitly opted out of loading
* separate block styles, then abort.
*/
add_filter( 'should_load_separate_core_block_assets', '__return_true', 0 );
if ( ! wp_should_load_separate_core_block_assets() ) {
return;
}

/*
* Also ensure that block assets are loaded on demand (although the default value is from should_load_separate_core_block_assets).
* As above, a priority of zero allows for this to be easily overridden by themes which wish to opt out.
* As above, a priority of zero allows for this to be easily overridden by themes which wish to opt out. If a site
* has explicitly opted out of loading block styles on demand, then abort.
*/
add_filter( 'should_load_block_assets_on_demand', '__return_true', 0 );

// If a site has explicitly opted out of loading block styles on demand via filters with priorities higher than above, then abort.
if ( ! wp_should_load_separate_core_block_assets() || ! wp_should_load_block_assets_on_demand() ) {
if ( ! wp_should_load_block_assets_on_demand() ) {
return;
}

Expand All @@ -3642,15 +3645,6 @@ function wp_hoist_late_printed_styles() {
return;
}

/*
* While normally late styles are printed, there is a filter to disable prevent this, so this makes sure they are
* printed. Note that this filter was intended to control whether to print the styles queued too late for the HTML
* head. This filter was introduced in <https://core.trac.wordpress.org/ticket/9346>. However, with the template
* enhancement output buffer, essentially no style can be enqueued too late, because an output buffer filter can
* always hoist it to the HEAD.
*/
add_filter( 'print_late_styles', '__return_true', PHP_INT_MAX );

/*
* Print a placeholder comment where the late styles can be hoisted from the footer to be printed in the header
* by means of a filter below on the template enhancement output buffer.
Expand All @@ -3660,11 +3654,44 @@ function wp_hoist_late_printed_styles() {
wp_add_inline_style( 'wp-block-library', $placeholder );

// Wrap print_late_styles() with a closure that captures the late-printed styles.
$printed_late_styles = '';
$capture_late_styles = static function () use ( &$printed_late_styles ) {
$printed_block_styles = '';
$printed_late_styles = '';
$capture_late_styles = static function () use ( &$printed_block_styles, &$printed_late_styles ) {
global $concatenate_scripts;
script_concat_settings();

// Print the styles related to on-demand block enqueues.
$all_block_style_handles = array();
foreach ( WP_Block_Type_Registry::get_instance()->get_all_registered() as $block_type ) {
foreach ( $block_type->style_handles as $style_handle ) {
$all_block_style_handles[] = $style_handle;
}
}
$all_block_style_handles = array_merge(
$all_block_style_handles,
array( 'global-styles', 'core-block-supports', 'block-style-variation-styles' ) // TODO: What else?
);

$enqueued_block_styles = array_values( array_intersect( $all_block_style_handles, wp_styles()->queue ) );
if ( count( $enqueued_block_styles ) > 0 ) {
wp_styles()->do_concat = $concatenate_scripts;
ob_start();
wp_styles()->do_items( $enqueued_block_styles );
_print_styles(); // TODO: Is this needed?
$printed_block_styles = ob_get_clean();
wp_styles()->reset();
}

/*
* Print remaining styles not related to blocks. This is the same logic as in print_late_styles(), but without
* the filter to control whether late styles are printed (since they are being hoisted anyway).
*/
wp_styles()->do_concat = $concatenate_scripts;
ob_start();
print_late_styles();
wp_styles()->do_footer_items();
_print_styles(); // TODO: Is this needed?
$printed_late_styles = ob_get_clean();
wp_styles()->reset();
};

/*
Expand Down Expand Up @@ -3695,65 +3722,76 @@ static function () use ( $capture_late_styles ) {
// Replace placeholder with the captured late styles.
add_filter(
'wp_template_enhancement_output_buffer',
function ( $buffer ) use ( $placeholder, &$printed_late_styles ) {
function ( $buffer ) use ( $placeholder, &$printed_block_styles, &$printed_late_styles ) {

// Anonymous subclass of WP_HTML_Tag_Processor which exposes underlying bookmark spans.
$processor = new class( $buffer ) extends WP_HTML_Tag_Processor {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmsnell How does this updated WP_HTML_Tag_Processor extension look here? Note the insert_before and insert_after methods.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And now a review method as well.

public function get_span(): WP_HTML_Span {
$instance = $this; // phpcs:ignore PHPCompatibility.FunctionDeclarations.NewClosure.ThisFoundOutsideClass -- It is inside an anonymous class.
$instance->set_bookmark( 'here' );
return $instance->bookmarks['here'];
/**
* Gets the span for the current token.
*
* @return WP_HTML_Span Current token span.
*/
private function get_span(): WP_HTML_Span {
$this->set_bookmark( 'here' ); // TODO: What if this fails?
return $this->bookmarks['here'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so much better with the removal of the additional surprising complexity!

}

/**
* Inserts text before the current token.
*
* @param string $text Text to insert.
*/
public function insert_before( string $text ) {
$this->lexical_updates[] = new WP_HTML_Text_Replacement( $this->get_span()->start, 0, $text );
}

/**
* Inserts text after the current token.
*
* @param string $text Text to insert.
*/
public function insert_after( string $text ) {
$span = $this->get_span();

$this->lexical_updates[] = new WP_HTML_Text_Replacement( $span->start + $span->length, 0, $text );
}
};

// Loop over STYLE tags.
// TODO: If there are no block styles to print, it would be nice to not have to replace the placeholder comment.
// Insert block styles right after wp-block-library (if it is present), and then insert any remaining styles at </head>.
while ( $processor->next_tag( array( 'tag_closers' => 'visit' ) ) ) {

// We've encountered the inline style for the 'wp-block-library' stylesheet which probably has the placeholder comment.
if (
! $processor->is_tag_closer() &&
'STYLE' === $processor->get_tag() &&
'wp-block-library-inline-css' === $processor->get_attribute( 'id' )
) {
// If the inline style lacks the placeholder comment, then we have to continue until we get to </HEAD> to append the styles there.
// If the inline style lacks the placeholder comment, then all the styles will be inserted below at </head>.
$css_text = $processor->get_modifiable_text();
if ( ! str_contains( $css_text, $placeholder ) ) {
continue;
}

// Remove the placeholder now that we've located the inline style.
$processor->set_modifiable_text( str_replace( $placeholder, '', $css_text ) );
$buffer = $processor->get_updated_html();

// Insert the $printed_late_styles immediately after the closing inline STYLE tag. This preserves the CSS cascade.
$span = $processor->get_span();
$buffer = implode(
'',
array(
substr( $buffer, 0, $span->start + $span->length ),
$printed_late_styles,
substr( $buffer, $span->start + $span->length ),
)
);
break;
}
if ( '' !== $printed_block_styles ) {
$processor->insert_after( $printed_block_styles );

// As a fallback, append the hoisted late styles to the end of the HEAD.
if ( $processor->is_tag_closer() && 'HEAD' === $processor->get_tag() ) {
$span = $processor->get_span();
$buffer = implode(
'',
array(
substr( $buffer, 0, $span->start ),
$printed_late_styles,
substr( $buffer, $span->start ),
)
);
// Prevent printing them again at </head>.
$printed_block_styles = '';
}

// If there aren't any late styles, there's no need to continue to finding </head>.
if ( '' === $printed_late_styles ) {
break;
}
} elseif ( 'HEAD' === $processor->get_tag() && $processor->is_tag_closer() ) {
$processor->insert_before( $printed_block_styles . $printed_late_styles );
break;
}
}

return $buffer;
return $processor->get_updated_html();
}
);
}
Expand Down
Loading
Loading