Make WordPress Core

Opened 6 months ago

Closed 6 months ago

Last modified 5 weeks ago

#64150 closed defect (bug) (fixed)

Late-printed styles are not hoisted to HEAD if wp-block-library is not enqueued

Reported by: westonruter's profile westonruter Owned by: westonruter's profile westonruter
Milestone: 6.9 Priority: normal
Severity: normal Version: 6.9
Component: Script Loader Keywords: has-patch has-unit-tests
Focuses: performance Cc:

Description

This is a follow-up to #64099. In the PR, I raised a question for future investigation:

There's one gotcha here which I want to investigate in a follow-up. It could be that a site doesn't use blocks at all, and they have removed this hook:

add_action( 'wp_enqueue_scripts', 'wp_common_block_scripts_and_styles' );

In this case, the style won't be present to add a placeholder to. This is likely exceedingly rare and an edge case that I don't think blocks the initial merge of this. But I want to follow on testing on a sites using the Classic Editor exclusively.

Well, it wasn't so exceedingly rare, as @Soean reported this as a bug in 6.9-beta1:

we remove the wp-block-library styles from our site:

<?php
add_action(
        'enqueue_block_assets',
        function (): void {
                wp_deregister_style( 'wp-block-library' );
                wp_register_style( 'wp-block-library', '' );
        }
);

Like others:

With WP 6.9-Beta1 we don't get the global-styles-inline-css styles anymore, which breaks our styles.

To reproduce this issue, you can install the following plugin:

<?php
/**
 * Plugin Name: Enqueue Stylesheet at WP Footer
 */

add_action(
        'enqueue_block_assets',
        function (): void {
                wp_deregister_style( 'wp-block-library' );
        }
);

add_action(
        'wp_head',
        static function () {
                echo '<style>body { background-color: red; }</style>';
        }
);

add_action(
        'wp_footer',
        static function () {
                wp_enqueue_style( 'lime-background', plugin_dir_url( __FILE__ ) . 'lime-background.css' );
        }
);

The lime-background.css file contains simply:

body {
        background-color: lime !important;
}

When the plugin is active, a red background will appear because lime-background is printed at wp_footer with print_late_styles(), but since wp-block-library is not printed at wp_head, there is no placeholder comment in any the inline style for that stylesheet.

We can address this issue simply by falling back to appending the late-printed styles to the very end of the HEAD tag.

Change History (23)

This ticket was mentioned in PR #10417 on WordPress/wordpress-develop by @westonruter.


6 months ago
#1

  • Keywords has-patch has-unit-tests added

#3 @Soean
6 months ago

Hey,
now our page is rendered correct, but I see some new default block inline styles. We don't want to use these default styles.

This is because the should_load_separate_core_block_assets filter is set to true.

#4 @westonruter
6 months ago

@Soean Thanks for the feedback. Well, in that case I think you perhaps should just do:

<?php
add_filter( 'should_load_separate_core_block_assets', '__return_false' );

This will override what wp_load_classic_theme_block_styles_on_demand() does here:

<?php
add_filter( 'should_load_separate_core_block_assets', '__return_true', 0 );

#5 @Soean
6 months ago

I know this helps, but this means wp_load_classic_theme_block_styles_on_demand() will maybe break some other themes on the WP 6.9 update.

#6 @westonruter
6 months ago

@Soean What styles specifically are being included unwantedly? If they are specifically targeting blocks, and a site is not using blocks, then won't the styles just not apply to anything?

#7 @Soean
6 months ago

We use blocks and all our styles for the theme and content are in one file: style.css

When I look at the HTML source code now, I see that there are 862 new inline styles.

<style id='wp-block-heading-inline-css'>...</style>
<style id='wp-block-paragraph-inline-css'>...</style>
<style id='wp-block-button-inline-css'>...</style>
<style id='wp-block-button-inline-css'>...</style>
<style id='wp-block-buttons-inline-css'>...</style>
<style id='wp-block-cover-inline-css'>...</style>
<style id='wp-block-image-inline-css'>...</style>
<style id='wp-block-columns-inline-css'>...</style>
<style id='wp-block-group-inline-css'>...</style>

These styles increase the size of the document and are not cached like the style.css.

And some inline styles break our theme styles, like this one:

.wp-block-image.aligncenter, .wp-block-image.alignleft, .wp-block-image.alignright {
    display: table;
}

#8 @westonruter
6 months ago

@Soean Does your theme include add_theme_support( 'wp-block-styles' )?

#9 @Soean
6 months ago

No, the function wp_common_block_scripts_and_styles() enqueues wp-block-library on every theme. Regardless of the add_theme_support( 'wp-block-styles' )

https://developer.wordpress.org/reference/functions/wp_common_block_scripts_and_styles/

This is why so many themes use wp_deregister_style( 'wp-block-library' );

#10 @westonruter
6 months ago

@Soean Got it. OK, so what if we also modified wp_hoist_late_printed_styles() to only filter should_load_separate_core_block_assets and should_load_block_assets_on_demand to true if current_theme_supports( 'wp-block-styles' )? I just amended the PR with a commit to do that. If you could validate that it addresses your concerns and fixes the issue for you, that would be great.

#11 @Soean
6 months ago

@westonruter Thank you, this looks good to me. Now it works with our setup 🙂

#12 @westonruter
6 months ago

Excellent.

For reference, here is the plugin code I used to test this with a classic theme (e.g. Twenty Ten):

<?php
/**
 * Plugin Name: Disable Block Styles
 */

add_action(
        'enqueue_block_assets',
        function (): void {
                wp_deregister_style( 'wp-block-library' );
                wp_register_style( 'wp-block-library', '' );
        }
);

add_action(
        'after_setup_theme',
        static function (): void {
                remove_theme_support( 'wp-block-styles' );
        },
        PHP_INT_MAX
);

Without that commit, I see a lot of block-specific styles being enqueued. With the commit, they are excluded.

@peterwilsoncc commented on PR #10417:


6 months ago
#13

On this branch, I'm seeing the inline block styles loading when running the testing plugin included on the ticket.

Reproduction steps:

  1. Activate 2014
  2. Deactivate the test plugin
  3. Create a post with the gallery block or any other block that contains styles
  4. Activate the test plugin
  5. Check out the 6.8 branch (no need to npm install or rebuild assets)
  6. Load the post created earlier
  7. The gallery block will not be styled as there are are no block styles or inline CSS.
  8. Check out this branch
  9. Reload the post created earlier
  10. The gallery block will be styled as the inline block styles are included in the output

I'm figuring out a test for this, will follow up once I have one.

@westonruter commented on PR #10417:


6 months ago
#14

@peterwilsoncc as we've chatted about over Slack, the issue is there are two test plugins:

  1. Enqueue Stylesheet at WP Footer (as listed in the ticket description)
  2. Disable Block Styles (listed in comment)

To test the issue with a theme not wanting to have any block styles at all, the second plugin needs to be used to test. The first plugin is just to test that late-enqueued styles successfully get printed even when the wp-block-library is absent (and thus the normal placeholder in the inline style is not present, meaning a fallback to inserting the late-printed styles before </head> is needed.

@peterwilsoncc commented on PR #10417:


6 months ago
#15

As discussed in Slack, I think I was using the wrong plugin when testing earlier.

At the time of my earlier tests I was running the following, which produces different results on each branch.

add_action(
        'enqueue_block_assets',
        function (): void {
                wp_deregister_style( 'wp-block-library' );
        }
);

add_action(
        'wp_head',
        static function () {
                echo '<style>body { background-color: red; }</style>';
        }
);

add_action(
        'wp_footer',
        static function () {
                wp_register_style( 'lime-background', null );
                wp_add_inline_style( 'lime-background', 'body { background-color: lime !important; }' );
                wp_enqueue_style( 'lime-background' );
        }
);

Using the second plugin on the ticket I am seeing the same thing on both branches, IE running

add_action(
        'enqueue_block_assets',
        function (): void {
                wp_deregister_style( 'wp-block-library' );
                wp_register_style( 'wp-block-library', '' );
        }
);

add_action(
        'after_setup_theme',
        static function (): void {
                remove_theme_support( 'wp-block-styles' );
        },
        PHP_INT_MAX
);

So I think this is good to go.

#16 @westonruter
6 months ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 61076:

Script Loader: Fall back to hoisting late-printed styles to end of HEAD if wp-block-library is not enqueued.

When the wp-block-library stylesheet is not enqueued, there will be no associated inline style present. This inline style normally contains the placeholder CSS comment for the HTML Tag Processor to identify the token after which the late-printed styles should be inserted. However, when the wp-block-library stylesheet is not enqueued (such as in themes which do not use blocks), or else the inline style is not printed for whatever reason, this adds a fallback to insert the late-printed styles immediately before </head>. This ensures that late-printed styles will always get hoisted.

Developed in https://github.com/WordPress/wordpress-develop/pull/10417

Follow-up to [61008].

Props westonruter, peterwilsoncc, Soean.
See #64099, #43258.
Fixes #64150.

@westonruter commented on PR #10417:


6 months ago
#17

Committed in r61076.

#18 @westonruter
6 months ago

There's a complication to using current_theme_supports( 'wp-block-styles' ) as the signal for whether opt-in to loading separate block styles on demand. It doesn't work with Twenty Twenty, which is the only bundled theme which doesn't add this theme support.

We need to decouple wp-block-styles theme support from whether should_load_separate_core_block_assets and should_load_block_assets_on_demand are enabled. Enabling the latter should not cause any styles to be printed.

More: https://core.trac.wordpress.org/ticket/64166#comment:2

cc @Soean

#19 @westonruter
5 months ago

In 61122:

Script Loader: Load block styles on demand in classic themes even when wp-block-styles support is absent.

This reverts part of [61076] which made wp-block-styles theme support a precondition for opting in to should_load_separate_core_block_assets and should_load_block_assets_on_demand. This meant that the Twenty Twenty theme (and other themes without this support declared) would not benefit from on-demand block style loading. Nevertheless, even though such themes were not getting block styles loaded on demand, the wp_load_classic_theme_block_styles_on_demand() function was proceeding to opt in to the output buffer for hoisting late-printed styles, even though it was unlikely there would then be any. This meant the template enhancement output buffer was being opened for no reason.

Enabling on-demand block style loading is measured to improve FCP and LCP in Twenty Twenty, for example a ~13% improvement over a Fast 4G connection when loading the Sample Page.

Developed in https://github.com/WordPress/wordpress-develop/pull/10457

Follow-up to [61008], [61076], [60936].

Props westonruter.
See #64099, #64150, #64166, #43258.

#20 @westonruter
5 months ago

  • Focuses performance added

#21 @westonruter
3 months ago

In 61554:

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].

Props westonruter, wildworks, jorbin, peterwilsoncc, sabernhardt, audrasjb, pmbs, threadi, madhavishah01, raftaar1191, noruzzaman, ozgursar.
See #64099, #64150, #43258.
Fixes #64354.

#22 @jorbin
3 months ago

In 61556:

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.

#23 @westonruter
5 weeks ago

In 61945:

Script Loader: Refine hoisted stylesheet ordering to preserve original 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 https://github.com/WordPress/wordpress-develop/pull/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.

Note: See TracTickets for help on using tickets.