Skip to content

Commit 08292be

Browse files
committed
Script Loader: Preserve original CSS cascade for classic themes when hoisting late-printed styles.
This refactors `wp_hoist_late_printed_styles()` to strictly preserve the classic theme CSS cascade when moving styles from `wp_footer` to the `HEAD`. Previously, hoisted styles were appended in an order closer to the CSS cascade for block themes, potentially causing specificity issues for CSS selectors written for the previous cascade. This is intended to eliminate the need for sites which upgraded to 6.9 to apply a hotfix involving `add_filter( 'should_load_separate_core_block_assets', '__return_false' )` to disable the optimization. Key changes: * Identifies styles enqueued during `enqueue_block_assets`. * Separates core block styles from third-party block styles. * Inserts core block styles immediately after `wp-block-library`. * Inserts third-party block styles after `classic-theme-styles`. * Inserts `global-styles` after all `enqueue_block_assets` styles. This ensures the following order is maintained: 1. Core block library. 2. Core block styles. 3. Classic theme styles. 4. Third-party block styles. 5. Global styles. Developed in WordPress#10601 Follow-up to [61174], [61122], [61076], [61008]. Reviewed by jorbin. Merges [61554] to the 6.9 branch. Props westonruter, wildworks, jorbin, peterwilsoncc, sabernhardt, audrasjb, pmbs, threadi, madhavishah01, raftaar1191, noruzzaman, ozgursar. See #64099, #64150, #43258. Fixes #64354. git-svn-id: https://develop.svn.wordpress.org/branches/6.9@61556 602fd350-edb4-49c9-b593-d223f7449a82
1 parent af07652 commit 08292be

File tree

2 files changed

+339
-124
lines changed

2 files changed

+339
-124
lines changed

src/wp-includes/script-loader.php

Lines changed: 151 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3643,8 +3643,25 @@ function wp_hoist_late_printed_styles() {
36433643
return;
36443644
}
36453645

3646+
// Capture the styles enqueued at the enqueue_block_assets action, so that non-core block styles and global styles can be inserted afterwards during hoisting.
3647+
$style_handles_at_enqueue_block_assets = array();
3648+
add_action(
3649+
'enqueue_block_assets',
3650+
static function () use ( &$style_handles_at_enqueue_block_assets ) {
3651+
$style_handles_at_enqueue_block_assets = wp_styles()->queue;
3652+
},
3653+
PHP_INT_MIN
3654+
);
3655+
add_action(
3656+
'enqueue_block_assets',
3657+
static function () use ( &$style_handles_at_enqueue_block_assets ) {
3658+
$style_handles_at_enqueue_block_assets = array_values( array_diff( wp_styles()->queue, $style_handles_at_enqueue_block_assets ) );
3659+
},
3660+
PHP_INT_MAX
3661+
);
3662+
36463663
/*
3647-
* Add a placeholder comment into the inline styles for wp-block-library, after which where the late block styles
3664+
* Add a placeholder comment into the inline styles for wp-block-library, after which the late block styles
36483665
* can be hoisted from the footer to be printed in the header by means of a filter below on the template enhancement
36493666
* output buffer. The `wp_print_styles` action is used to ensure that if the inline style gets replaced at
36503667
* `enqueue_block_assets` or `wp_enqueue_scripts` that the placeholder will be sure to be present.
@@ -3663,35 +3680,51 @@ static function () use ( $placeholder ) {
36633680
* later hoisted to the HEAD in the template enhancement output buffer. This will run at `wp_print_footer_scripts`
36643681
* before `print_footer_scripts()` is called.
36653682
*/
3666-
$printed_block_styles = '';
3667-
$printed_late_styles = '';
3668-
$capture_late_styles = static function () use ( &$printed_block_styles, &$printed_late_styles ) {
3683+
$printed_core_block_styles = '';
3684+
$printed_other_block_styles = '';
3685+
$printed_global_styles = '';
3686+
$printed_late_styles = '';
3687+
3688+
$capture_late_styles = static function () use ( &$printed_core_block_styles, &$printed_other_block_styles, &$printed_global_styles, &$printed_late_styles ) {
36693689
// Gather the styles related to on-demand block enqueues.
3670-
$all_block_style_handles = array();
3690+
$all_core_block_style_handles = array();
3691+
$all_other_block_style_handles = array();
36713692
foreach ( WP_Block_Type_Registry::get_instance()->get_all_registered() as $block_type ) {
3672-
foreach ( $block_type->style_handles as $style_handle ) {
3673-
$all_block_style_handles[] = $style_handle;
3693+
if ( str_starts_with( $block_type->name, 'core/' ) ) {
3694+
foreach ( $block_type->style_handles as $style_handle ) {
3695+
$all_core_block_style_handles[] = $style_handle;
3696+
}
3697+
} else {
3698+
foreach ( $block_type->style_handles as $style_handle ) {
3699+
$all_other_block_style_handles[] = $style_handle;
3700+
}
36743701
}
36753702
}
3676-
$all_block_style_handles = array_merge(
3677-
$all_block_style_handles,
3678-
array(
3679-
'global-styles',
3680-
'block-style-variation-styles',
3681-
'core-block-supports',
3682-
'core-block-supports-duotone',
3683-
)
3684-
);
36853703

36863704
/*
3687-
* First print all styles related to blocks which should inserted right after the wp-block-library stylesheet
3705+
* First print all styles related to blocks which should be inserted right after the wp-block-library stylesheet
36883706
* to preserve the CSS cascade. The logic in this `if` statement is derived from `wp_print_styles()`.
36893707
*/
3690-
$enqueued_block_styles = array_values( array_intersect( $all_block_style_handles, wp_styles()->queue ) );
3691-
if ( count( $enqueued_block_styles ) > 0 ) {
3708+
$enqueued_core_block_styles = array_values( array_intersect( $all_core_block_style_handles, wp_styles()->queue ) );
3709+
if ( count( $enqueued_core_block_styles ) > 0 ) {
36923710
ob_start();
3693-
wp_styles()->do_items( $enqueued_block_styles );
3694-
$printed_block_styles = ob_get_clean();
3711+
wp_styles()->do_items( $enqueued_core_block_styles );
3712+
$printed_core_block_styles = ob_get_clean();
3713+
}
3714+
3715+
// Non-core block styles get printed after the classic-theme-styles stylesheet.
3716+
$enqueued_other_block_styles = array_values( array_intersect( $all_other_block_style_handles, wp_styles()->queue ) );
3717+
if ( count( $enqueued_other_block_styles ) > 0 ) {
3718+
ob_start();
3719+
wp_styles()->do_items( $enqueued_other_block_styles );
3720+
$printed_other_block_styles = ob_get_clean();
3721+
}
3722+
3723+
// Capture the global-styles so that it can be printed separately after classic-theme-styles and other styles enqueued at enqueue_block_assets.
3724+
if ( wp_style_is( 'global-styles' ) ) {
3725+
ob_start();
3726+
wp_styles()->do_items( array( 'global-styles' ) );
3727+
$printed_global_styles = ob_get_clean();
36953728
}
36963729

36973730
/*
@@ -3732,7 +3765,7 @@ static function () use ( $capture_late_styles ) {
37323765
// Replace placeholder with the captured late styles.
37333766
add_filter(
37343767
'wp_template_enhancement_output_buffer',
3735-
static function ( $buffer ) use ( $placeholder, &$printed_block_styles, &$printed_late_styles ) {
3768+
static function ( $buffer ) use ( $placeholder, &$style_handles_at_enqueue_block_assets, &$printed_core_block_styles, &$printed_other_block_styles, &$printed_global_styles, &$printed_late_styles ) {
37363769

37373770
// Anonymous subclass of WP_HTML_Tag_Processor which exposes underlying bookmark spans.
37383771
$processor = new class( $buffer ) extends WP_HTML_Tag_Processor {
@@ -3777,53 +3810,116 @@ public function remove() {
37773810
}
37783811
};
37793812

3780-
/*
3781-
* Insert block styles right after wp-block-library (if it is present), and then insert any remaining styles
3782-
* at </head> (or else print everything there). The placeholder CSS comment will always be added to the
3783-
* wp-block-library inline style since it gets printed at `wp_head` before the blocks are rendered.
3784-
* This means that there may not actually be any block styles to hoist from the footer to insert after this
3785-
* inline style. The placeholder CSS comment needs to be added so that the inline style gets printed, but
3786-
* if the resulting inline style is empty after the placeholder is removed, then the inline style is
3787-
* removed.
3788-
*/
3813+
// Locate the insertion points in the HEAD.
37893814
while ( $processor->next_tag( array( 'tag_closers' => 'visit' ) ) ) {
37903815
if (
37913816
'STYLE' === $processor->get_tag() &&
37923817
'wp-block-library-inline-css' === $processor->get_attribute( 'id' )
37933818
) {
3794-
$css_text = $processor->get_modifiable_text();
3795-
3796-
/*
3797-
* A placeholder CSS comment is added to the inline style in order to force an inline STYLE tag to
3798-
* be printed. Now that we've located the inline style, the placeholder comment can be removed. If
3799-
* there is no CSS left in the STYLE tag after removing the placeholder (aside from the sourceURL
3800-
* comment, then remove the STYLE entirely.)
3801-
*/
3802-
$css_text = str_replace( $placeholder, '', $css_text );
3803-
if ( preg_match( ':^/\*# sourceURL=\S+? \*/$:', trim( $css_text ) ) ) {
3804-
$processor->remove();
3805-
} else {
3806-
$processor->set_modifiable_text( $css_text );
3819+
$processor->set_bookmark( 'wp_block_library' );
3820+
} elseif ( 'HEAD' === $processor->get_tag() && $processor->is_tag_closer() ) {
3821+
$processor->set_bookmark( 'head_end' );
3822+
break;
3823+
} elseif ( ( 'STYLE' === $processor->get_tag() || 'LINK' === $processor->get_tag() ) && $processor->get_attribute( 'id' ) ) {
3824+
$id = $processor->get_attribute( 'id' );
3825+
$handle = null;
3826+
if ( 'STYLE' === $processor->get_tag() ) {
3827+
if ( preg_match( '/^(.+)-inline-css$/', $id, $matches ) ) {
3828+
$handle = $matches[1];
3829+
}
3830+
} elseif ( preg_match( '/^(.+)-css$/', $id, $matches ) ) {
3831+
$handle = $matches[1];
38073832
}
38083833

3809-
// Insert the $printed_late_styles immediately after the closing inline STYLE tag. This preserves the CSS cascade.
3810-
if ( '' !== $printed_block_styles ) {
3811-
$processor->insert_after( $printed_block_styles );
3834+
if ( 'classic-theme-styles' === $handle ) {
3835+
$processor->set_bookmark( 'classic_theme_styles' );
3836+
}
38123837

3813-
// Prevent printing them again at </head>.
3814-
$printed_block_styles = '';
3838+
if ( $handle && in_array( $handle, $style_handles_at_enqueue_block_assets, true ) ) {
3839+
if ( ! $processor->has_bookmark( 'first_style_at_enqueue_block_assets' ) ) {
3840+
$processor->set_bookmark( 'first_style_at_enqueue_block_assets' );
3841+
}
3842+
$processor->set_bookmark( 'last_style_at_enqueue_block_assets' );
38153843
}
3844+
}
3845+
}
3846+
3847+
/*
3848+
* Insert block styles right after wp-block-library (if it is present). The placeholder CSS comment will
3849+
* always be added to the wp-block-library inline style since it gets printed at `wp_head` before the blocks
3850+
* are rendered. This means that there may not actually be any block styles to hoist from the footer to
3851+
* insert after this inline style. The placeholder CSS comment needs to be added so that the inline style
3852+
* gets printed, but if the resulting inline style is empty after the placeholder is removed, then the
3853+
* inline style is removed.
3854+
*/
3855+
if ( $processor->has_bookmark( 'wp_block_library' ) ) {
3856+
$processor->seek( 'wp_block_library' );
3857+
3858+
$css_text = $processor->get_modifiable_text();
3859+
3860+
/*
3861+
* A placeholder CSS comment is added to the inline style in order to force an inline STYLE tag to
3862+
* be printed. Now that we've located the inline style, the placeholder comment can be removed. If
3863+
* there is no CSS left in the STYLE tag after removing the placeholder (aside from the sourceURL
3864+
* comment), then remove the STYLE entirely.
3865+
*/
3866+
$css_text = str_replace( $placeholder, '', $css_text );
3867+
if ( preg_match( ':^/\*# sourceURL=\S+? \*/$:', trim( $css_text ) ) ) {
3868+
$processor->remove();
3869+
} else {
3870+
$processor->set_modifiable_text( $css_text );
3871+
}
3872+
3873+
$inserted_after = $printed_core_block_styles;
3874+
$printed_core_block_styles = '';
38163875

3817-
// If there aren't any late styles, there's no need to continue to finding </head>.
3818-
if ( '' === $printed_late_styles ) {
3819-
break;
3876+
// If the classic-theme-styles is absent, then the third-party block styles cannot be inserted after it, so they get inserted here.
3877+
if ( ! $processor->has_bookmark( 'classic_theme_styles' ) ) {
3878+
if ( '' !== $printed_other_block_styles ) {
3879+
$inserted_after .= $printed_other_block_styles;
38203880
}
3821-
} elseif ( 'HEAD' === $processor->get_tag() && $processor->is_tag_closer() ) {
3822-
$processor->insert_before( $printed_block_styles . $printed_late_styles );
3823-
break;
3881+
$printed_other_block_styles = '';
3882+
3883+
// If there aren't any other styles printed at enqueue_block_assets either, then the global styles need to also be printed here.
3884+
if ( ! $processor->has_bookmark( 'last_style_at_enqueue_block_assets' ) ) {
3885+
if ( '' !== $printed_global_styles ) {
3886+
$inserted_after .= $printed_global_styles;
3887+
}
3888+
$printed_global_styles = '';
3889+
}
3890+
}
3891+
3892+
if ( '' !== $inserted_after ) {
3893+
$processor->insert_after( "\n" . $inserted_after );
3894+
}
3895+
}
3896+
3897+
// Insert global-styles after the styles enqueued at enqueue_block_assets.
3898+
if ( '' !== $printed_global_styles && $processor->has_bookmark( 'last_style_at_enqueue_block_assets' ) ) {
3899+
$processor->seek( 'last_style_at_enqueue_block_assets' );
3900+
3901+
$processor->insert_after( "\n" . $printed_global_styles );
3902+
$printed_global_styles = '';
3903+
3904+
if ( ! $processor->has_bookmark( 'classic_theme_styles' ) && '' !== $printed_other_block_styles ) {
3905+
$processor->insert_after( "\n" . $printed_other_block_styles );
3906+
$printed_other_block_styles = '';
38243907
}
38253908
}
38263909

3910+
// Insert third-party block styles right after the classic-theme-styles.
3911+
if ( '' !== $printed_other_block_styles && $processor->has_bookmark( 'classic_theme_styles' ) ) {
3912+
$processor->seek( 'classic_theme_styles' );
3913+
$processor->insert_after( "\n" . $printed_other_block_styles );
3914+
$printed_other_block_styles = '';
3915+
}
3916+
3917+
// Print all remaining styles.
3918+
$remaining_styles = $printed_core_block_styles . $printed_other_block_styles . $printed_global_styles . $printed_late_styles;
3919+
if ( $remaining_styles && $processor->has_bookmark( 'head_end' ) ) {
3920+
$processor->seek( 'head_end' );
3921+
$processor->insert_before( $remaining_styles . "\n" );
3922+
}
38273923
return $processor->get_updated_html();
38283924
}
38293925
);

0 commit comments

Comments
 (0)