Make WordPress Core


Ignore:
Timestamp:
01/29/2026 09:25:28 PM (7 months ago)
Author:
jorbin
Message:

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 https://github.com/WordPress/wordpress-develop/pull/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.

Location:
branches/6.9
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/6.9

  • branches/6.9/src/wp-includes/script-loader.php

    r61174 r61556  
    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
     
    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
     
    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.
     
    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 (
     
    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 );
    3812 
    3813                                                 // Prevent printing them again at </head>.
    3814                                                 $printed_block_styles = '';
     3834                                        if ( 'classic-theme-styles' === $handle ) {
     3835                                                $processor->set_bookmark( 'classic_theme_styles' );
    38153836                                        }
    38163837
    3817                                         // If there aren't any late styles, there's no need to continue to finding </head>.
    3818                                         if ( '' === $printed_late_styles ) {
    3819                                                 break;
     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' );
    38203843                                        }
    3821                                 } elseif ( 'HEAD' === $processor->get_tag() && $processor->is_tag_closer() ) {
    3822                                         $processor->insert_before( $printed_block_styles . $printed_late_styles );
    3823                                         break;
    38243844                                }
    38253845                        }
    38263846
     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 = '';
     3875
     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;
     3880                                        }
     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 = '';
     3907                                }
     3908                        }
     3909
     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                }
Note: See TracChangeset for help on using the changeset viewer.