Trac 64389: Refine hoisted stylesheet ordering in classic themes#10875
Trac 64389: Refine hoisted stylesheet ordering in classic themes#10875westonruter wants to merge 33 commits intoWordPress:trunkfrom
Conversation
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
…ut comments and then empty STYLE tags
This comment was marked as duplicate.
This comment was marked as duplicate.
There was a problem hiding this comment.
Pull request overview
Refines how global-styles is hoisted into the document <head> for classic themes when block assets are loaded on-demand, addressing cases where no block styles (and no classic-theme-styles) provide a reliable insertion point.
Changes:
- Enqueue a
wp-global-styles-placeholderinline style duringwp_enqueue_scriptsfor classic themes with on-demand loading, sowp_hoist_late_printed_styles()can reliably replace it with the footer-printedglobal-stylesin the<head>. - Update
wp_hoist_late_printed_styles()to detect and replace the new global-styles placeholder bookmark. - Expand PHPUnit coverage to include “Elementor-like” scenarios (theme.json present + no block content + dequeued block library), and adjust expected ordering accordingly.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/wp-includes/script-loader.php |
Adds/enables a global-styles placeholder in classic+on-demand mode and replaces it during hoisting to stabilize <head> ordering. |
tests/phpunit/tests/template.php |
Updates hoisting tests to include content parameterization and new scenarios/expectations around placeholder-driven ordering. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
|
This new placeholder approach may be relevant the hoisted placement of other styles. But I'd really love to get more reproduction steps for any issues people are experiencing. |
…action()/has_filter()
…lder where block styles are enqueued
|
Given that this has had been tested and code reviewed, I'm intending to proceed with commit later today so we can be sure it is tested in the next pre-release. |
| // 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. | ||
| $style_handles_at_enqueue_block_assets = array(); | ||
| add_action( | ||
| 'enqueue_block_assets', | ||
| static function () use ( &$style_handles_at_enqueue_block_assets ) { | ||
| $style_handles_at_enqueue_block_assets = wp_styles()->queue; | ||
| }, | ||
| PHP_INT_MIN | ||
| ); | ||
| add_action( | ||
| 'enqueue_block_assets', | ||
| static function () use ( &$style_handles_at_enqueue_block_assets ) { | ||
| $style_handles_at_enqueue_block_assets = array_values( array_diff( wp_styles()->queue, $style_handles_at_enqueue_block_assets ) ); | ||
| }, | ||
| PHP_INT_MAX | ||
| ); | ||
|
|
There was a problem hiding this comment.
This code is obsolete as it was just used to set the first_style_at_enqueue_block_assets and last_style_at_enqueue_block_assets bookmarks, which are also now no longer used.
| } elseif ( ( 'STYLE' === $processor->get_tag() || 'LINK' === $processor->get_tag() ) && $processor->get_attribute( 'id' ) ) { | ||
| $id = $processor->get_attribute( 'id' ); | ||
| $handle = null; | ||
| if ( 'STYLE' === $processor->get_tag() ) { | ||
| if ( preg_match( '/^(.+)-inline-css$/', $id, $matches ) ) { | ||
| $handle = $matches[1]; | ||
| } | ||
| } elseif ( preg_match( '/^(.+)-css$/', $id, $matches ) ) { | ||
| $handle = $matches[1]; | ||
| } | ||
|
|
||
| if ( 'classic-theme-styles' === $handle ) { | ||
| $processor->set_bookmark( 'classic_theme_styles' ); | ||
| } | ||
|
|
||
| if ( $handle && in_array( $handle, $style_handles_at_enqueue_block_assets, true ) ) { | ||
| if ( ! $processor->has_bookmark( 'first_style_at_enqueue_block_assets' ) ) { | ||
| $processor->set_bookmark( 'first_style_at_enqueue_block_assets' ); | ||
| } | ||
| $processor->set_bookmark( 'last_style_at_enqueue_block_assets' ); | ||
| } |
There was a problem hiding this comment.
This condition is obsolete because the first_style_at_enqueue_block_assets and last_style_at_enqueue_block_assets bookmarks are no longer used.
|
When prepping this for commit, I sent it through Gemini again for a review and it pointed out that the |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Just want to confirm that this PR fixes a case in a client project with a classic theme where theme's critical CSS was printed before the |
| if ( $is_classic_theme && doing_action( 'wp_enqueue_scripts' ) && $assets_on_demand ) { | ||
| if ( has_action( 'wp_template_enhancement_output_buffer_started', 'wp_hoist_late_printed_styles' ) ) { | ||
| wp_register_style( 'wp-global-styles-placeholder', false ); | ||
| wp_add_inline_style( 'wp-global-styles-placeholder', ':root { --wp-internal-comment: "Placeholder for wp_hoist_late_printed_styles() to replace with the global-styles printed at wp_footer." }' ); |
There was a problem hiding this comment.
Thats cure, I've never seen style comments added like this.
There was a problem hiding this comment.
Just a CSS custom property (variable) leveraged as a comment 😄
adamsilverstein
left a comment
There was a problem hiding this comment.
Tremendous! Left some nit pick feedback about comments.
Co-authored-by: Adam Silverstein <[email protected]>
Co-authored-by: Adam Silverstein <[email protected]>
…l CSS cascade in classic themes. This introduces placeholder inline `STYLE` tags in the `HEAD` which are used to accurately locate hoisted styles which were printed in the footer. This improves the robustness of the hoisting logic. A style placeholder had been used previously in the inline style for `wp-block-library` for placing core block styles, and new placeholders are added for global styles and non-core block styles. Furthermore, this fixes the cascade for inline styles added to `wp-block-library`. When separate block styles are not used, these styles would have appeared after the single combined `wp-block-library`. However, in 6.9 the order changed so that separate block styles would appear after. To preserve the original cascade, this splits the `wp-block-library` inline style: the first half (likely just the inlined `block-library/common.css`) appears before the block styles, and the remainder appears in a new `STYLE#wp-block-library-inline-css-extra` element. Developed in #10875 Follow-up to r61554, r61174, r61122, r61076, r61008. Props westonruter, joefusco, adamsilverstein, ocean90, mmorris8, ozgursar, vanonsopensource, xwolf, immeet94, george9, joezappie, jorbin, sajib1223, sabernhardt. See #64099, #64354, #64150, #43258. Fixes #64389. git-svn-id: https://develop.svn.wordpress.org/trunk@61945 602fd350-edb4-49c9-b593-d223f7449a82
…l CSS cascade in classic themes. This introduces placeholder inline `STYLE` tags in the `HEAD` which are used to accurately locate hoisted styles which were printed in the footer. This improves the robustness of the hoisting logic. A style placeholder had been used previously in the inline style for `wp-block-library` for placing core block styles, and new placeholders are added for global styles and non-core block styles. Furthermore, this fixes the cascade for inline styles added to `wp-block-library`. When separate block styles are not used, these styles would have appeared after the single combined `wp-block-library`. However, in 6.9 the order changed so that separate block styles would appear after. To preserve the original cascade, this splits the `wp-block-library` inline style: the first half (likely just the inlined `block-library/common.css`) appears before the block styles, and the remainder appears in a new `STYLE#wp-block-library-inline-css-extra` element. Developed in WordPress/wordpress-develop#10875 Follow-up to r61554, r61174, r61122, r61076, r61008. Props westonruter, joefusco, adamsilverstein, ocean90, mmorris8, ozgursar, vanonsopensource, xwolf, immeet94, george9, joezappie, jorbin, sajib1223, sabernhardt. See #64099, #64354, #64150, #43258. Fixes #64389. Built from https://develop.svn.wordpress.org/trunk@61945 git-svn-id: http://core.svn.wordpress.org/trunk@61227 1a063a9b-81f0-0310-95a4-ce76da25c4cd
…76127) * Sync changes from wp_enqueue_global_styles() to gutenberg override * Sync latest changes from WordPress/wordpress-develop#10875 Co-authored-by: westonruter <[email protected]> Co-authored-by: adamsilverstein <[email protected]>
…76127) * Sync changes from wp_enqueue_global_styles() to gutenberg override * Sync latest changes from WordPress/wordpress-develop#10875 Co-authored-by: westonruter <[email protected]> Co-authored-by: adamsilverstein <[email protected]>
…(#76127) * Sync changes from wp_enqueue_global_styles() to gutenberg override * Sync latest changes from WordPress/wordpress-develop#10875 Co-authored-by: westonruter <[email protected]> Co-authored-by: adamsilverstein <[email protected]> Source: WordPress/gutenberg@01ebc90
…(#76127) * Sync changes from wp_enqueue_global_styles() to gutenberg override * Sync latest changes from WordPress/wordpress-develop#10875 Co-authored-by: westonruter <[email protected]> Co-authored-by: adamsilverstein <[email protected]> Source: WordPress/gutenberg@9cc64f5
Trac ticket: https://core.trac.wordpress.org/ticket/64389
When a theme has a
theme.json, then it will not emit theclassic-theme-stylesstylesheet. When no other block styles printed either, as in the case of Elementor with the Hello Elementor theme, then the existing logic inwp_hoist_late_printed_styles()does not have a reference point (from printed block styles) to know where it should inject theglobal-styles. So, this PR makes the hoistingglobal-stylesmuch more robust by enqueueing a placeholder inline style which then gets replaced during processing of the template enhancement output buffer. This also allows for removing some convolutedifstatements to conditionally inject global styles around other styles.The same goes for where non-core block styles get printed. Previously the logic here would attempt to locate the
classic-theme-stylesand then insert the block styles after that style. But if the style was not enqueued, then it would have fall back to trying to insert them after elsewhere. This, again, is simplified by printing a placeholder inline style at the point where block styles normally get inserted. This placeholder style in theHEADis replaced with the styles rendered in the footer.The placeholder inline styles are simply removed if there are no appropriate styles to hoist there.
How I tested:
gutenberg_enqueue_global_styles()to correspond with the modifiedwp_enqueue_global_styles()in this PR. Or else, have Sync changes fromwp_enqueue_global_styles()to Gutenberg override gutenberg#76127 checked out.add_filter( 'wp_should_output_buffer_template_for_enhancement', '__return_true' );trunkeliminated the underline from links (probably Remove link underline style from default theme.json gutenberg#74901), so add this plugin code to restore the previous underline to reproduce the bug with the cascade:STYLE#global-styles-inline-cssis printed at the end ofHEAD, far afterLINK#hello-elementor-cssSTYLE#global-styles-inline-csselement is printed afterSTYLE#wp-emoji-styles-inline-cssand beforeLINK#hello-elementor-css.Fixing Cascade for
wp-block-libraryadded inline stylesThis PR also fixes (via 48eb4f6) the cascade for when inline styles are added to
wp-block-library. When the combined block library is enqueued, theme authors would expect any inline style to appear in the cascade after any core block styles. However, in 6.9 this was no longer the case as the separate block styles would get inserted after any suchwp-block-libraryinline styles. This is fixed now so that the inline styles forwp-block-libraryget after any separate core block styles.For example, consider this plugin code:
Before 6.9, in a classic theme where combined block library is loaded, this would result in the following styles printed (e.g. in Twenty Twenty-One):
In 6.9, however, when separate block styles are loaded on demand, the lime color style appears before the block style for the Separator block:
With the changes in this PR, the correct order placement in the cascade is better preserved:
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.
Commit Message
Script Loader: Refine hoisted stylesheet ordering in classic themes.
This introduces placeholder inline
STYLEtags in theHEADwhich are used to accurately locate hoisted styles which were printed in the footer. This improves the robustness of the hoisting logic. A style placeholder had been used previously in the inline style forwp-block-libraryfor placing core block styles, and new placeholders are added for global styles and non-core block styles.Furthermore, this fixes the cascade for inline styles added to
wp-block-library. When separate block styles are not used, these styles would have appeared after the single combinedwp-block-library. However, in 6.9 the order changed so that separate block styles would appear after. To preserve the original cascade, this splits thewp-block-libraryinline style: the first half (likely just the inlinedblock-library/common.css) appears before the block styles, and the remainder appears in a newSTYLE#wp-block-library-inline-css-extraelement.Developed in #10875
Follow-up to r61554, r61174, r61122, r61076, r61008.
Props westonruter, mmorris8, ozgursar, vanonsopensource, xwolf, immeet94, sabernhardt, george9, joezappie, jorbin, sajib1223, joefusco.
See #64099, #64354, #64150, #43258.
Fixes #64389.