Skip to content

Commit 9d03e8e

Browse files
committed
Editor: Avoid enqueueing assets for blocks which do not render content.
This change prevents scripts, styles, and script modules from being enqueued for blocks that do not render any HTML content. This is common for hidden blocks or blocks like the Featured Image block when no image is present. This change reduces the amount of unused CSS and JavaScript on a page, improving performance. A new filter, `enqueue_empty_block_content_assets`, is introduced to allow developers to override this behavior and enqueue assets for empty blocks if needed. The implementation involves capturing the asset queues before and after a block is rendered. The newly enqueued assets are only merged if the block's rendered content is not empty. This is done recursively for nested blocks to ensure that assets for inner blocks are also not enqueued if a parent block is hidden. Developed in #9213. Props westonruter, aristath, peterwilsoncc, gziolo, krupajnanda, dd32, jorbin. See #50328. Fixes #63676. git-svn-id: https://develop.svn.wordpress.org/trunk@60930 602fd350-edb4-49c9-b593-d223f7449a82
1 parent b3c3c8e commit 9d03e8e

File tree

5 files changed

+408
-28
lines changed

5 files changed

+408
-28
lines changed

src/wp-includes/class-wp-block.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,14 @@ public function replace_rich_text( $rich_text ) {
492492
public function render( $options = array() ) {
493493
global $post;
494494

495+
// Capture the current assets queues and then clear out to capture the diff of what was introduced by rendering.
496+
$before_styles_queue = wp_styles()->queue;
497+
$before_scripts_queue = wp_scripts()->queue;
498+
$before_script_modules_queue = wp_script_modules()->queue;
499+
wp_styles()->queue = array();
500+
wp_scripts()->queue = array();
501+
wp_script_modules()->queue = array();
502+
495503
/*
496504
* There can be only one root interactive block at a time because the rendered HTML of that block contains
497505
* the rendered HTML of all its inner blocks, including any interactive block.
@@ -661,6 +669,44 @@ public function render( $options = array() ) {
661669
$root_interactive_block = null;
662670
}
663671

672+
// Capture the new assets enqueued during rendering, and restore the queues the state prior to rendering.
673+
$new_styles_queue = wp_styles()->queue;
674+
$new_scripts_queue = wp_scripts()->queue;
675+
$new_script_modules_queue = wp_script_modules()->queue;
676+
wp_styles()->queue = $before_styles_queue;
677+
wp_scripts()->queue = $before_scripts_queue;
678+
wp_script_modules()->queue = $before_script_modules_queue;
679+
$has_new_styles = count( $new_styles_queue ) > 0;
680+
$has_new_scripts = count( $new_scripts_queue ) > 0;
681+
$has_new_script_modules = count( $new_script_modules_queue ) > 0;
682+
683+
// Merge the newly enqueued assets with the existing assets if the rendered block is not empty.
684+
if (
685+
( $has_new_styles || $has_new_scripts || $has_new_script_modules ) &&
686+
(
687+
trim( $block_content ) !== '' ||
688+
/**
689+
* Filters whether to enqueue assets for a block which has no rendered content.
690+
*
691+
* @since 6.9.0
692+
*
693+
* @param bool $enqueue Whether to enqueue assets.
694+
* @param string $block_name Block name.
695+
*/
696+
(bool) apply_filters( 'enqueue_empty_block_content_assets', false, $this->name )
697+
)
698+
) {
699+
if ( $has_new_styles ) {
700+
wp_styles()->queue = array_unique( array_merge( wp_styles()->queue, $new_styles_queue ) );
701+
}
702+
if ( $has_new_scripts ) {
703+
wp_scripts()->queue = array_unique( array_merge( wp_scripts()->queue, $new_scripts_queue ) );
704+
}
705+
if ( $has_new_script_modules ) {
706+
wp_script_modules()->queue = array_unique( array_merge( wp_script_modules()->queue, $new_script_modules_queue ) );
707+
}
708+
}
709+
664710
return $block_content;
665711
}
666712
}

src/wp-includes/class-wp-script-modules.php

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ class WP_Script_Modules {
2323
private $registered = array();
2424

2525
/**
26-
* Holds the script module identifiers that were enqueued before registered.
26+
* An array of IDs for queued script modules.
2727
*
28-
* @since 6.5.0
29-
* @var array<string, true>
28+
* @since 6.9.0
29+
* @var string[]
3030
*/
31-
private $enqueued_before_registered = array();
31+
public $queue = array();
3232

3333
/**
3434
* Tracks whether the @wordpress/a11y script module is available.
@@ -122,7 +122,6 @@ public function register( string $id, string $src, array $deps = array(), $versi
122122
$this->registered[ $id ] = array(
123123
'src' => $src,
124124
'version' => $version,
125-
'enqueue' => isset( $this->enqueued_before_registered[ $id ] ),
126125
'dependencies' => $dependencies,
127126
'fetchpriority' => $fetchpriority,
128127
);
@@ -213,13 +212,11 @@ public function set_fetchpriority( string $id, string $priority ): bool {
213212
* }
214213
*/
215214
public function enqueue( string $id, string $src = '', array $deps = array(), $version = false, array $args = array() ) {
216-
if ( isset( $this->registered[ $id ] ) ) {
217-
$this->registered[ $id ]['enqueue'] = true;
218-
} elseif ( $src ) {
215+
if ( ! in_array( $id, $this->queue, true ) ) {
216+
$this->queue[] = $id;
217+
}
218+
if ( ! isset( $this->registered[ $id ] ) && $src ) {
219219
$this->register( $id, $src, $deps, $version, $args );
220-
$this->registered[ $id ]['enqueue'] = true;
221-
} else {
222-
$this->enqueued_before_registered[ $id ] = true;
223220
}
224221
}
225222

@@ -231,10 +228,7 @@ public function enqueue( string $id, string $src = '', array $deps = array(), $v
231228
* @param string $id The identifier of the script module.
232229
*/
233230
public function dequeue( string $id ) {
234-
if ( isset( $this->registered[ $id ] ) ) {
235-
$this->registered[ $id ]['enqueue'] = false;
236-
}
237-
unset( $this->enqueued_before_registered[ $id ] );
231+
$this->queue = array_diff( $this->queue, array( $id ) );
238232
}
239233

240234
/**
@@ -245,8 +239,8 @@ public function dequeue( string $id ) {
245239
* @param string $id The identifier of the script module.
246240
*/
247241
public function deregister( string $id ) {
242+
$this->dequeue( $id );
248243
unset( $this->registered[ $id ] );
249-
unset( $this->enqueued_before_registered[ $id ] );
250244
}
251245

252246
/**
@@ -304,9 +298,9 @@ public function print_enqueued_script_modules() {
304298
* @since 6.5.0
305299
*/
306300
public function print_script_module_preloads() {
307-
foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $id => $script_module ) {
301+
foreach ( $this->get_dependencies( array_unique( $this->queue ), array( 'static' ) ) as $id => $script_module ) {
308302
// Don't preload if it's marked for enqueue.
309-
if ( true !== $script_module['enqueue'] ) {
303+
if ( ! in_array( $id, $this->queue, true ) ) {
310304
echo sprintf(
311305
'<link rel="modulepreload" href="%s" id="%s"%s>',
312306
esc_url( $this->get_src( $id ) ),
@@ -345,7 +339,7 @@ public function print_import_map() {
345339
*/
346340
private function get_import_map(): array {
347341
$imports = array();
348-
foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $id => $script_module ) {
342+
foreach ( $this->get_dependencies( array_unique( $this->queue ) ) as $id => $script_module ) {
349343
$imports[ $id ] = $this->get_src( $id );
350344
}
351345
return array( 'imports' => $imports );
@@ -359,13 +353,10 @@ private function get_import_map(): array {
359353
* @return array<string, array> Script modules marked for enqueue, keyed by script module identifier.
360354
*/
361355
private function get_marked_for_enqueue(): array {
362-
$enqueued = array();
363-
foreach ( $this->registered as $id => $script_module ) {
364-
if ( true === $script_module['enqueue'] ) {
365-
$enqueued[ $id ] = $script_module;
366-
}
367-
}
368-
return $enqueued;
356+
return wp_array_slice_assoc(
357+
$this->registered,
358+
$this->queue
359+
);
369360
}
370361

371362
/**
@@ -457,7 +448,7 @@ private function get_src( string $id ): string {
457448
*/
458449
public function print_script_module_data(): void {
459450
$modules = array();
460-
foreach ( array_keys( $this->get_marked_for_enqueue() ) as $id ) {
451+
foreach ( array_unique( $this->queue ) as $id ) {
461452
if ( '@wordpress/a11y' === $id ) {
462453
$this->a11y_available = true;
463454
}

tests/phpunit/tests/blocks/editor.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,21 @@ public function set_up() {
3131

3232
global $post_ID;
3333
$post_ID = 1;
34+
35+
global $wp_scripts, $wp_styles;
36+
$this->original_wp_scripts = $wp_scripts;
37+
$this->original_wp_styles = $wp_styles;
38+
$wp_scripts = null;
39+
$wp_styles = null;
40+
wp_scripts();
41+
wp_styles();
3442
}
3543

3644
public function tear_down() {
45+
global $wp_scripts, $wp_styles;
46+
$wp_scripts = $this->original_wp_scripts;
47+
$wp_styles = $this->original_wp_styles;
48+
3749
/** @var WP_REST_Server $wp_rest_server */
3850
global $wp_rest_server;
3951
$wp_rest_server = null;
@@ -42,6 +54,16 @@ public function tear_down() {
4254
parent::tear_down();
4355
}
4456

57+
/**
58+
* @var WP_Scripts|null
59+
*/
60+
protected $original_wp_scripts;
61+
62+
/**
63+
* @var WP_Styles|null
64+
*/
65+
protected $original_wp_styles;
66+
4567
public function filter_set_block_categories_post( $block_categories, $post ) {
4668
if ( empty( $post ) ) {
4769
return $block_categories;

0 commit comments

Comments
 (0)