Skip to content

Commit 49f1bbe

Browse files
Squash sirreal:scripts/allow-script-module-dependency (WordPress#8024) at 9acd7f0
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 9d5d79a commit 49f1bbe

5 files changed

Lines changed: 475 additions & 63 deletions

File tree

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

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,13 +533,77 @@ public function print_import_map() {
533533
* Returns the import map array.
534534
*
535535
* @since 6.5.0
536+
* @since 7.0.0 Script module dependencies ('module_dependencies') of classic scripts are now included.
537+
*
538+
* @global WP_Scripts $wp_scripts
536539
*
537540
* @return array<string, array<string, string>> Array with an `imports` key mapping to an array of script module
538541
* identifiers and their respective URLs, including the version query.
539542
*/
540543
private function get_import_map(): array {
544+
global $wp_scripts;
545+
541546
$imports = array();
542-
foreach ( array_keys( $this->get_dependencies( $this->queue ) ) as $id ) {
547+
548+
// Identify script modules that are dependencies of classic scripts.
549+
$classic_script_module_dependencies = array();
550+
if ( $wp_scripts instanceof WP_Scripts ) {
551+
$handles = array_merge(
552+
$wp_scripts->queue,
553+
$wp_scripts->to_do,
554+
$wp_scripts->done
555+
);
556+
557+
$processed = array();
558+
while ( ! empty( $handles ) ) {
559+
$handle = array_pop( $handles );
560+
if ( isset( $processed[ $handle ] ) || ! isset( $wp_scripts->registered[ $handle ] ) ) {
561+
continue;
562+
}
563+
$processed[ $handle ] = true;
564+
565+
$module_dependencies = $wp_scripts->get_data( $handle, 'module_dependencies' );
566+
if ( is_array( $module_dependencies ) ) {
567+
$missing_module_dependencies = array();
568+
foreach ( $module_dependencies as $id ) {
569+
if ( ! isset( $this->registered[ $id ] ) ) {
570+
$missing_module_dependencies[] = $id;
571+
} else {
572+
$classic_script_module_dependencies[] = $id;
573+
}
574+
}
575+
576+
if ( count( $missing_module_dependencies ) > 0 ) {
577+
_doing_it_wrong(
578+
'WP_Scripts::add_data',
579+
sprintf(
580+
/* translators: 1: Script handle, 2: 'module_dependencies', 3: List of missing dependency IDs. */
581+
__( 'The script with the handle "%1$s" was enqueued with script module dependencies ("%2$s") that are not registered: %3$s.' ),
582+
$handle,
583+
'module_dependencies',
584+
implode( wp_get_list_item_separator(), $missing_module_dependencies )
585+
),
586+
'7.0.0'
587+
);
588+
}
589+
}
590+
591+
foreach ( $wp_scripts->registered[ $handle ]->deps as $dep ) {
592+
if ( ! isset( $processed[ $dep ] ) ) {
593+
$handles[] = $dep;
594+
}
595+
}
596+
}
597+
}
598+
599+
// Note: the script modules in $this->queue are not included in the importmap because they get printed as scripts.
600+
$ids = array_unique(
601+
array_merge(
602+
$classic_script_module_dependencies,
603+
array_keys( $this->get_dependencies( array_merge( $this->queue, $classic_script_module_dependencies ) ) )
604+
)
605+
);
606+
foreach ( $ids as $id ) {
543607
$src = $this->get_src( $id );
544608
if ( '' !== $src ) {
545609
$imports[ $id ] = $src;

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,45 @@ public function add_data( $handle, $key, $value ) {
920920
);
921921
return false;
922922
}
923+
} elseif ( 'module_dependencies' === $key ) {
924+
if ( ! is_array( $value ) ) {
925+
_doing_it_wrong(
926+
__METHOD__,
927+
sprintf(
928+
/* translators: 1: 'module_dependencies', 2: Script handle. */
929+
__( 'The value for "%1$s" must be an array for the "%2$s" script.' ),
930+
'module_dependencies',
931+
$handle
932+
),
933+
'7.0.0'
934+
);
935+
return false;
936+
}
937+
938+
$sanitized_value = array();
939+
$has_invalid_ids = false;
940+
foreach ( $value as $id ) {
941+
if ( ! is_string( $id ) ) {
942+
$has_invalid_ids = true;
943+
} else {
944+
$sanitized_value[] = $id;
945+
}
946+
}
947+
948+
if ( $has_invalid_ids ) {
949+
_doing_it_wrong(
950+
__METHOD__,
951+
sprintf(
952+
/* translators: 1: Script handle, 2: 'module_dependencies' */
953+
__( 'The script handle "%1$s" has one or more of its script module dependencies ("%2$s") which are not strings.' ),
954+
$handle,
955+
'module_dependencies'
956+
),
957+
'7.0.0'
958+
);
959+
}
960+
961+
$value = $sanitized_value;
923962
}
924963
return parent::add_data( $handle, $key, $value );
925964
}

src/wp-includes/functions.wp-scripts.php

Lines changed: 77 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,47 @@ function _wp_scripts_maybe_doing_it_wrong( $function_name, $handle = '' ) {
6868
);
6969
}
7070

71+
/**
72+
* Adds the data for the recognized args and warns for unrecognized args.
73+
*
74+
* @ignore
75+
* @since 7.0.0
76+
*
77+
* @param string $function_name Function name.
78+
* @param WP_Scripts $wp_scripts WP_Scripts instance.
79+
* @param string $handle Script handle.
80+
* @param array $args Array of extra args for the script.
81+
*/
82+
function _wp_scripts_add_args_data( string $function_name, WP_Scripts $wp_scripts, string $handle, array $args ) {
83+
$allowed_keys = array( 'strategy', 'in_footer', 'fetchpriority', 'module_dependencies' );
84+
$unknown_keys = array_diff( array_keys( $args ), $allowed_keys );
85+
if ( ! empty( $unknown_keys ) ) {
86+
_doing_it_wrong(
87+
$function_name,
88+
sprintf(
89+
/* translators: 1: $args, 2: List of unrecognized keys. */
90+
__( 'Unrecognized keys in the %1$s array: %2$s.' ),
91+
'$args',
92+
implode( wp_get_list_item_separator(), $unknown_keys )
93+
),
94+
'7.0.0'
95+
);
96+
}
97+
98+
if ( ! empty( $args['in_footer'] ) ) {
99+
$wp_scripts->add_data( $handle, 'group', 1 );
100+
}
101+
if ( ! empty( $args['strategy'] ) ) {
102+
$wp_scripts->add_data( $handle, 'strategy', $args['strategy'] );
103+
}
104+
if ( ! empty( $args['fetchpriority'] ) ) {
105+
$wp_scripts->add_data( $handle, 'fetchpriority', $args['fetchpriority'] );
106+
}
107+
if ( ! empty( $args['module_dependencies'] ) ) {
108+
$wp_scripts->add_data( $handle, 'module_dependencies', $args['module_dependencies'] );
109+
}
110+
}
111+
71112
/**
72113
* Prints scripts in document head that are in the $handles queue.
73114
*
@@ -159,22 +200,24 @@ function wp_add_inline_script( $handle, $data, $position = 'after' ) {
159200
* @since 4.3.0 A return value was added.
160201
* @since 6.3.0 The $in_footer parameter of type boolean was overloaded to be an $args parameter of type array.
161202
* @since 6.9.0 The $fetchpriority parameter of type string was added to the $args parameter of type array.
162-
*
163-
* @param string $handle Name of the script. Should be unique.
164-
* @param string|false $src Full URL of the script, or path of the script relative to the WordPress root directory.
165-
* If source is set to false, script is an alias of other scripts it depends on.
166-
* @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array.
167-
* @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
168-
* as a query string for cache busting purposes. If version is set to false, a version
169-
* number is automatically added equal to current installed WordPress version.
170-
* If set to null, no version is added.
171-
* @param array<string, string|bool>|bool $args {
172-
* Optional. An array of additional script loading strategies. Default empty array.
203+
* @since 7.0.0 The $module_dependencies parameter of type string[] was added to the $args parameter of type array.
204+
*
205+
* @param string $handle Name of the script. Should be unique.
206+
* @param string|false $src Full URL of the script, or path of the script relative to the WordPress root directory.
207+
* If source is set to false, script is an alias of other scripts it depends on.
208+
* @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array.
209+
* @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
210+
* as a query string for cache busting purposes. If version is set to false, a version
211+
* number is automatically added equal to current installed WordPress version.
212+
* If set to null, no version is added.
213+
* @param array<string, string|bool|string[]>|bool $args {
214+
* Optional. An array of extra args for the script. Default empty array.
173215
* Otherwise, it may be a boolean in which case it determines whether the script is printed in the footer. Default false.
174216
*
175-
* @type string $strategy Optional. If provided, may be either 'defer' or 'async'.
176-
* @type bool $in_footer Optional. Whether to print the script in the footer. Default 'false'.
177-
* @type string $fetchpriority Optional. The fetch priority for the script. Default 'auto'.
217+
* @type string $strategy Optional. If provided, may be either 'defer' or 'async'.
218+
* @type bool $in_footer Optional. Whether to print the script in the footer. Default 'false'.
219+
* @type string $fetchpriority Optional. The fetch priority for the script. Default 'auto'.
220+
* @type string[] $module_dependencies Optional. IDs for module dependencies loaded via dynamic import. Default empty array.
178221
* }
179222
* @return bool Whether the script has been registered. True on success, false on failure.
180223
*/
@@ -189,15 +232,8 @@ function wp_register_script( $handle, $src, $deps = array(), $ver = false, $args
189232
$wp_scripts = wp_scripts();
190233

191234
$registered = $wp_scripts->add( $handle, $src, $deps, $ver );
192-
if ( ! empty( $args['in_footer'] ) ) {
193-
$wp_scripts->add_data( $handle, 'group', 1 );
194-
}
195-
if ( ! empty( $args['strategy'] ) ) {
196-
$wp_scripts->add_data( $handle, 'strategy', $args['strategy'] );
197-
}
198-
if ( ! empty( $args['fetchpriority'] ) ) {
199-
$wp_scripts->add_data( $handle, 'fetchpriority', $args['fetchpriority'] );
200-
}
235+
_wp_scripts_add_args_data( __FUNCTION__, $wp_scripts, $handle, $args );
236+
201237
return $registered;
202238
}
203239

@@ -345,22 +381,24 @@ function wp_deregister_script( $handle ) {
345381
* @since 2.1.0
346382
* @since 6.3.0 The $in_footer parameter of type boolean was overloaded to be an $args parameter of type array.
347383
* @since 6.9.0 The $fetchpriority parameter of type string was added to the $args parameter of type array.
348-
*
349-
* @param string $handle Name of the script. Should be unique.
350-
* @param string $src Full URL of the script, or path of the script relative to the WordPress root directory.
351-
* Default empty.
352-
* @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array.
353-
* @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
354-
* as a query string for cache busting purposes. If version is set to false, a version
355-
* number is automatically added equal to current installed WordPress version.
356-
* If set to null, no version is added.
357-
* @param array<string, string|bool>|bool $args {
358-
* Optional. An array of additional script loading strategies. Default empty array.
384+
* @since 7.0.0 The $module_dependencies parameter of type string[] was added to the $args parameter of type array.
385+
*
386+
* @param string $handle Name of the script. Should be unique.
387+
* @param string $src Full URL of the script, or path of the script relative to the WordPress root directory.
388+
* Default empty.
389+
* @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array.
390+
* @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
391+
* as a query string for cache busting purposes. If version is set to false, a version
392+
* number is automatically added equal to current installed WordPress version.
393+
* If set to null, no version is added.
394+
* @param array<string, string|bool|string[]>|bool $args {
395+
* Optional. An array of extra args for the script. Default empty array.
359396
* Otherwise, it may be a boolean in which case it determines whether the script is printed in the footer. Default false.
360397
*
361-
* @type string $strategy Optional. If provided, may be either 'defer' or 'async'.
362-
* @type bool $in_footer Optional. Whether to print the script in the footer. Default 'false'.
363-
* @type string $fetchpriority Optional. The fetch priority for the script. Default 'auto'.
398+
* @type string $strategy Optional. If provided, may be either 'defer' or 'async'.
399+
* @type bool $in_footer Optional. Whether to print the script in the footer. Default 'false'.
400+
* @type string $fetchpriority Optional. The fetch priority for the script. Default 'auto'.
401+
* @type string[] $module_dependencies Optional. IDs for module dependencies loaded via dynamic import. Default empty array.
364402
* }
365403
*/
366404
function wp_enqueue_script( $handle, $src = '', $deps = array(), $ver = false, $args = array() ) {
@@ -379,14 +417,8 @@ function wp_enqueue_script( $handle, $src = '', $deps = array(), $ver = false, $
379417
if ( $src ) {
380418
$wp_scripts->add( $_handle[0], $src, $deps, $ver );
381419
}
382-
if ( ! empty( $args['in_footer'] ) ) {
383-
$wp_scripts->add_data( $_handle[0], 'group', 1 );
384-
}
385-
if ( ! empty( $args['strategy'] ) ) {
386-
$wp_scripts->add_data( $_handle[0], 'strategy', $args['strategy'] );
387-
}
388-
if ( ! empty( $args['fetchpriority'] ) ) {
389-
$wp_scripts->add_data( $_handle[0], 'fetchpriority', $args['fetchpriority'] );
420+
if ( ! empty( $args ) ) {
421+
_wp_scripts_add_args_data( __FUNCTION__, $wp_scripts, $_handle[0], $args );
390422
}
391423
}
392424

0 commit comments

Comments
 (0)