Skip to content

Conversation

westonruter
Copy link
Member

@westonruter westonruter commented Oct 15, 2025

This is a follow-up to #9213 (r60930 & 9d03e8e) which broke asset enqueues on WPOrg, as reported by @dd32:

@westonruter This has caused breakage on WordPress.org - #meta8104, and the enqueue_empty_block_content_assets filter doesn't seem to be related at all (It didn't even fire).

I'm not 100% sure why this is happening, as it doesn't appear that it's directly related to this skipping logic, but rather that the queued data is being lost somehow - perhaps being overwritten with older data.[[BR]]
So I'm thinking this could be related to nested blocks, where a script/style is registered from within one of those subblocks.

For example, this plugin adds one of the styles that were missing:
https://github.com/WordPress/wordpress.org/blob/trunk/wordpress.org/public_html/wp-content/plugins/wporg-bbp-code-blocks-expand-contract/wporg-bbp-code-blocks-expand-contract.php#L27-L46

That's a fairly basic enqueue, but the only thing I can think of is it being fired from within a block wporg/global-header. https://github.com/WordPress/wporg-mu-plugins/tree/trunk/mu-plugins/blocks/global-header-footer

Here's a diff of two WordPress.org sites before/after that changeset.

Here's a diff of wordpress.org/support/forums/:
https://gist.github.com/dd32/a9441db9a3fac0ce2a962625f7ca2aef

Here's a diff of make.wordpress.org/updates/:
https://gist.github.com/dd32/6a495ca9617384a33ebd73997859fe69

I'm unable to figure out how to duplicate this on a stand alone site, https://github.com/wordpress/wporg-parent-2021 might reproduce it (but it's provisioning is broken for me right now)


One thing I've noticed (But I don't believe isn't entirely unrelated) is that I believe wp_script_is( 'admin-bar', 'enqueued' ) would now return false during the block render even if it was enqueued, but is not enqueued directly (or required by one of the currently enqueued scripts).

This PR takes an alternative approach to not clear out the queue before each block is rendered. Since blocks are rendered in depth-first order, simply capturing the enqueued assets before rendering and then comparing with the assets enqueued after a block (or nested block tree) is rendered should be sufficient. When no content is rendered in the block, then the logic has been updated to dequeue what had newly been enqueued (rather than to merge queues of the previous queue and the new queue).

As an added bonus, this ensures that wp_script_is( 'admin-bar', 'enqueued' ) works as expected in the block render callbacks/filters.

Then there is a very special case added for the sake of themes which may include a block which specifically renders wp_head(): in the case of enqueueing a script there which is only printed in the footer, the result of wp_head() may be no output at all (since the script will be printed at wp_footer() instead. To account for this, now the logic for checking whether to dequeue assets is skipped if the wp_head action happened during the block's rendering.

This PR also undoes the exposing of WP_Script_Modules::$queue member variable in favor of a WP_Script_Modules::get_queue() method, since the queue no longer needs to be easily written to directly; now wp_dequeue_script_module() is used to remove enqueued script modules when necessary.

Trac ticket: https://core.trac.wordpress.org/ticket/63676


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.

@westonruter westonruter changed the title Avoid resetting asset queues and add wp_head special case Block Visibility: Avoid resetting asset queues and add wp_head special case Oct 15, 2025
@westonruter westonruter changed the title Block Visibility: Avoid resetting asset queues and add wp_head special case Block Visibility: Avoid resetting asset queues prior to block rendering and add wp_head special case Oct 15, 2025
@westonruter westonruter marked this pull request as ready for review October 15, 2025 00:29
Copy link

github-actions bot commented Oct 15, 2025

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 props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props westonruter, peterwilsoncc, dd32.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@dd32
Copy link
Member

dd32 commented Oct 15, 2025

I've tested this on WordPress.org, and done a diff of the output before changes, verses with trunk with this PR, and the only diff is a \n meaning this PR does seem to resolve the issue encountered.

The approach of dequeuing instead of conditionally enqueueing assets does seem a bit weird at first, but It does seem like the best approach for back-compat.

The only alternative that I can think of would require a far more indepth change to how WP_Dependency operates, effectively adding a $deps->start_transaction(); render_block(); $deps->commit() OR $deps->discard_queue_changes(); within deps, which would introduce other edge-cases, but would keep the manipulation of deps within the script/style handlers rather than in the block renderer.

Having to check for wp_head running feels like a dirty hack here, but I understand the intention of it, and is probably best to remain included. (for reference, this check isn't needed on WordPress.org, but I can imagine an edge-case where it would be - such as where no actual HTML output occured on the hook which seems rare enough to be frustrating to debug)

Copy link
Contributor

@peterwilsoncc peterwilsoncc left a comment

Choose a reason for hiding this comment

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

A note and a question inline.

global $post;

// Capture the current assets queues and then clear out to capture the diff of what was introduced by rendering.
$before_wp_head_count = did_action( 'wp_head' );
Copy link
Contributor

Choose a reason for hiding this comment

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

In @dd32's code, it appears that the specific problem is not wp_head but rather wp_enqueue|register_style|scripts. It just happens that wp_head fires them.

It could be best to test for the specific rather than the general. 🤷‍♂️

Copy link
Member Author

Choose a reason for hiding this comment

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

The issue (as I found) is with wp_print_scripts() and wp_print_styles(), that either of these (especially the former) may not print anything during wp_head, since what is enqueued may get printed in wp_footer. We could change this to look if the wp_print_scripts or wp_print_styles actions fired, but they don't always fire.

Or actually, maybe it would be better to check if the wp_enqueue_scripts action fired. As I think about it, the issue is that plugins and themes are being invited to enqueued scripts and styles, but if nothing is printed then we undo the enqueueing. So this needs to be prevented.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've made that change in 7f8f721. That feels better and makes much more sense.

…into trac-63676-fixing-blocks-containing-wp-head
Copy link
Contributor

@peterwilsoncc peterwilsoncc left a comment

Choose a reason for hiding this comment

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

I won't have the chance to test fully until this weekend but these changes look good to me and I'm happy with the core/wp-head test included in the test suite.

Thanks for modifying the action test to wp_enqueue_scripts, much appreciated.

@westonruter westonruter changed the title Block Visibility: Avoid resetting asset queues prior to block rendering and add wp_head special case Block Visibility: Avoid resetting asset queues prior to block rendering and add wp_enqueue_scripts special case Oct 16, 2025
pento pushed a commit that referenced this pull request Oct 16, 2025
…to enqueue assets for non-hidden blocks.

This eliminates constant emptying out of the queues for styles, scripts, and script modules before rendering each block. This ensures that `wp_script_is()`/`wp_style_is()` will return true for assets that are actually enqueued. The `WP_Script_Modules::$queue` member which was made public in [60930] is now made private in favor of a `WP_Script_Modules::get_queue()` method, since there is no need to clear out the queue before rendering each block and restore after the rendering is complete. 

Finally, as a very special case for unusual blocks which contain `wp_head()`, a check is done to see if the `wp_enqueue_scripts` action occurred during the rendering of a block; if so, then no assets will be dequeued even if no markup is rendered in the block, since it may be that a script was enqueued for the footer and not the head. 

Developed in #10252

Follow-up to [60930].

Props westonruter, dd32, peterwilsoncc, nikunj8866, krupajnanda.
Fixes #63676.


git-svn-id: https://develop.svn.wordpress.org/trunk@60951 602fd350-edb4-49c9-b593-d223f7449a82
@westonruter
Copy link
Member Author

Committed in c6a9f26 (r60951).

markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Oct 16, 2025
…to enqueue assets for non-hidden blocks.

This eliminates constant emptying out of the queues for styles, scripts, and script modules before rendering each block. This ensures that `wp_script_is()`/`wp_style_is()` will return true for assets that are actually enqueued. The `WP_Script_Modules::$queue` member which was made public in [60930] is now made private in favor of a `WP_Script_Modules::get_queue()` method, since there is no need to clear out the queue before rendering each block and restore after the rendering is complete. 

Finally, as a very special case for unusual blocks which contain `wp_head()`, a check is done to see if the `wp_enqueue_scripts` action occurred during the rendering of a block; if so, then no assets will be dequeued even if no markup is rendered in the block, since it may be that a script was enqueued for the footer and not the head. 

Developed in WordPress/wordpress-develop#10252

Follow-up to [60930].

Props westonruter, dd32, peterwilsoncc, nikunj8866, krupajnanda.
Fixes #63676.

Built from https://develop.svn.wordpress.org/trunk@60951


git-svn-id: http://core.svn.wordpress.org/trunk@60287 1a063a9b-81f0-0310-95a4-ce76da25c4cd
github-actions bot pushed a commit to platformsh/wordpress-performance that referenced this pull request Oct 16, 2025
…to enqueue assets for non-hidden blocks.

This eliminates constant emptying out of the queues for styles, scripts, and script modules before rendering each block. This ensures that `wp_script_is()`/`wp_style_is()` will return true for assets that are actually enqueued. The `WP_Script_Modules::$queue` member which was made public in [60930] is now made private in favor of a `WP_Script_Modules::get_queue()` method, since there is no need to clear out the queue before rendering each block and restore after the rendering is complete. 

Finally, as a very special case for unusual blocks which contain `wp_head()`, a check is done to see if the `wp_enqueue_scripts` action occurred during the rendering of a block; if so, then no assets will be dequeued even if no markup is rendered in the block, since it may be that a script was enqueued for the footer and not the head. 

Developed in WordPress/wordpress-develop#10252

Follow-up to [60930].

Props westonruter, dd32, peterwilsoncc, nikunj8866, krupajnanda.
Fixes #63676.

Built from https://develop.svn.wordpress.org/trunk@60951


git-svn-id: https://core.svn.wordpress.org/trunk@60287 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants