Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
39a11a8
Add "expose" logic to script modules
sirreal Oct 8, 2024
65fd1df
Make get_src return nullable
sirreal Oct 8, 2024
843e1e0
Rework, rename, add tests
sirreal Dec 16, 2024
2e180cf
Remove uniqueness checks
sirreal Dec 17, 2024
7fc42d2
Replace excessively prescriptive comment
sirreal Dec 17, 2024
5144a90
Add test for correct merge with regular dependencies
sirreal Dec 17, 2024
d83ea4b
Fix overwriting array keys
sirreal Dec 17, 2024
9125683
Working proposal with caveats
sirreal Dec 19, 2024
5ddc2dd
Revert preveious approach at module dependencies
sirreal Dec 19, 2024
9e976bb
Inspect wp_scripts and extract module deps from scripts on the page
sirreal Dec 19, 2024
591e3b5
Fix regression printing enqueued modules in importmap
sirreal Dec 19, 2024
d1d8c43
Check for WP_Scripts instance
sirreal Dec 19, 2024
10c3a02
Fix possible unset module id in script modules
sirreal Dec 19, 2024
a444ffa
Fix lint
sirreal Dec 19, 2024
b0f579b
Update and improve tests with classic scripts
sirreal Dec 19, 2024
8366f45
Improve variable name and array push of many values
sirreal Dec 19, 2024
45cacbb
Remove a loop from importmap checking
sirreal Dec 19, 2024
14ae089
Merge branch 'trunk' into scripts/allow-script-module-dependency
sirreal Apr 3, 2025
6122621
Merge trunk into scripts/allow-script-module-dependency
westonruter Jan 29, 2026
b77dbc7
Remove merge conflict markers
westonruter Jan 29, 2026
1d12174
Fix test_included_module_appears_in_importmap
westonruter Jan 29, 2026
64e67b8
Fix test_included_modules_concat_with_enqueued_dependencies
westonruter Jan 29, 2026
fda5f17
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Jan 29, 2026
f2f72a6
Pass module dependencies via args insead of deps
westonruter Jan 29, 2026
d926e8f
Ensure module_dependencies is an array before iterating over
westonruter Jan 29, 2026
1a1df99
Optimize classic script module dependency resolution
westonruter Jan 30, 2026
6b56f5f
Improve variable naming, add comment, and add phpdoc
westonruter Jan 30, 2026
cf8f813
Restore WP_Script_Modules::get_src() only returning string
westonruter Jan 30, 2026
34867df
Warn when script is enqueued with missing script module dependency
westonruter Jan 30, 2026
babe954
Use array_pop() instead of array_shift() to avoid re-indexing
westonruter Jan 30, 2026
b450826
Validate module_dependencies in WP_Scripts::add_data()
westonruter Jan 30, 2026
269c4c7
Validate extra args in wp_register_script() and wp_enqueue_script()
westonruter Jan 30, 2026
3c2c84b
Refactor wp_register_script() and wp_enqueue_script() to avoid code d…
westonruter Jan 30, 2026
354f42d
Standardize wp_scripts global handling in script module tests
westonruter Jan 30, 2026
ae642f4
Use PHP 7.4 class member types
westonruter Jan 30, 2026
8a782ac
Fix variable alignment
westonruter Jan 30, 2026
6a3141a
Use globals consistently
westonruter Jan 30, 2026
07ab8d6
Add descriptions to script module dependency tests
westonruter Jan 30, 2026
907cb0d
Refactor and simplify script module dependency tests
westonruter Jan 30, 2026
23e2a33
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Jan 30, 2026
7f53642
Add comment explaining why a classic script with a missing dynamic sc…
westonruter Jan 30, 2026
7ddcdd7
Improve phrasing
westonruter Jan 31, 2026
0cb95e0
Improve param default value description
westonruter Jan 31, 2026
ce5124f
Avoid calling _wp_scripts_add_args_data() with empty args
westonruter Jan 31, 2026
083287a
Use WP_Scripts::add_data() instead of WP_Scripts::add() for _doing_it…
westonruter Jan 31, 2026
9acd7f0
Update test_wp_scripts_doing_it_wrong_for_missing_script_module_depen…
westonruter Jan 31, 2026
a97279c
Merge branch 'trunk' into scripts/allow-script-module-dependency
sirreal Feb 2, 2026
2f95af0
Merge branch 'trunk' into scripts/allow-script-module-dependency
sirreal Feb 2, 2026
681472c
Improve specificity of $deps param
westonruter Feb 2, 2026
c82565c
Allow passing script modules as arrays for module_dependencies
westonruter Feb 2, 2026
bf143fc
fixup! Allow passing script modules as arrays for module_dependencies
westonruter Feb 2, 2026
23fc17d
fixup! Allow passing script modules as arrays for module_dependencies
westonruter Feb 2, 2026
9924b07
Add tests for passing array module specifiers
westonruter Feb 2, 2026
6b29352
Improve variable name
westonruter Feb 2, 2026
e1ad3c7
Update tear_down logic order
westonruter Feb 2, 2026
12adf99
Merge branch 'trunk' into scripts/allow-script-module-dependency
westonruter Feb 2, 2026
2b3ddf8
Script Loader: Remove $function_name argument from _wp_scripts_add_ar…
westonruter Feb 3, 2026
8ff8e43
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Feb 4, 2026
3a67800
List the supported keys after the unrecognized keys in the notice
westonruter Feb 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 125 additions & 51 deletions src/wp-includes/class-wp-script-modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,31 +88,31 @@ class WP_Script_Modules {
* @since 6.5.0
* @since 6.9.0 Added the $args parameter.
*
* @param string $id The identifier of the script module. Should be unique. It will be used in the
* final import map.
* @param string $src Optional. Full URL of the script module, or path of the script module relative
* to the WordPress root directory. If it is provided and the script module has
* not been registered yet, it will be registered.
* @param array<string|array> $deps {
* Optional. List of dependencies.
*
* @type string|array ...$0 {
* An array of script module identifiers of the dependencies of this script
* module. The dependencies can be strings or arrays. If they are arrays,
* they need an `id` key with the script module identifier, and can contain
* an `import` key with either `static` or `dynamic`. By default,
* dependencies that don't contain an `import` key are considered static.
*
* @type string $id The script module identifier.
* @type string $import Optional. Import type. May be either `static` or
* `dynamic`. Defaults to `static`.
* }
* }
* @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
* It is added to the URL as a query string for cache busting purposes. If $version
* is set to false, the version number is the currently installed WordPress version.
* If $version is set to null, no version is added.
* @param array<string, string|bool> $args {
* @param string $id The identifier of the script module. Should be unique. It will be used in the
* final import map.
* @param string $src Optional. Full URL of the script module, or path of the script module relative
* to the WordPress root directory. If it is provided and the script module has
* not been registered yet, it will be registered.
* @param array<string|array<string, string>> $deps {
* Optional. List of dependencies.
*
* @type string|array<string, string> ...$0 {
* An array of script module identifiers of the dependencies of this script
* module. The dependencies can be strings or arrays. If they are arrays,
* they need an `id` key with the script module identifier, and can contain
* an `import` key with either `static` or `dynamic`. By default,
* dependencies that don't contain an `import` key are considered static.
*
* @type string $id The script module identifier.
* @type string $import Optional. Import type. May be either `static` or
* `dynamic`. Defaults to `static`.
* }
* }
* @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
* It is added to the URL as a query string for cache busting purposes. If $version
* is set to false, the version number is the currently installed WordPress version.
* If $version is set to null, no version is added.
* @param array<string, string|bool> $args {
* Optional. An array of additional args. Default empty array.
*
* @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional.
Expand Down Expand Up @@ -260,31 +260,31 @@ public function set_in_footer( string $id, bool $in_footer ): bool {
* @since 6.5.0
* @since 6.9.0 Added the $args parameter.
*
* @param string $id The identifier of the script module. Should be unique. It will be used in the
* final import map.
* @param string $src Optional. Full URL of the script module, or path of the script module relative
* to the WordPress root directory. If it is provided and the script module has
* not been registered yet, it will be registered.
* @param array<string|array> $deps {
* Optional. List of dependencies.
*
* @type string|array ...$0 {
* An array of script module identifiers of the dependencies of this script
* module. The dependencies can be strings or arrays. If they are arrays,
* they need an `id` key with the script module identifier, and can contain
* an `import` key with either `static` or `dynamic`. By default,
* dependencies that don't contain an `import` key are considered static.
*
* @type string $id The script module identifier.
* @type string $import Optional. Import type. May be either `static` or
* `dynamic`. Defaults to `static`.
* }
* }
* @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
* It is added to the URL as a query string for cache busting purposes. If $version
* is set to false, the version number is the currently installed WordPress version.
* If $version is set to null, no version is added.
* @param array<string, string|bool> $args {
* @param string $id The identifier of the script module. Should be unique. It will be used in the
* final import map.
* @param string $src Optional. Full URL of the script module, or path of the script module relative
* to the WordPress root directory. If it is provided and the script module has
* not been registered yet, it will be registered.
* @param array<string|array<string, string>> $deps {
* Optional. List of dependencies.
*
* @type string|array<string, string> ...$0 {
* An array of script module identifiers of the dependencies of this script
* module. The dependencies can be strings or arrays. If they are arrays,
* they need an `id` key with the script module identifier, and can contain
* an `import` key with either `static` or `dynamic`. By default,
* dependencies that don't contain an `import` key are considered static.
*
* @type string $id The script module identifier.
* @type string $import Optional. Import type. May be either `static` or
* `dynamic`. Defaults to `static`.
* }
* }
* @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
* It is added to the URL as a query string for cache busting purposes. If $version
* is set to false, the version number is the currently installed WordPress version.
* If $version is set to null, no version is added.
* @param array<string, string|bool> $args {
* Optional. An array of additional args. Default empty array.
*
* @type bool $in_footer Whether to print the script module in the footer. Only relevant to block themes. Default 'false'. Optional.
Expand Down Expand Up @@ -533,13 +533,87 @@ public function print_import_map() {
* Returns the import map array.
*
* @since 6.5.0
* @since 7.0.0 Script module dependencies ('module_dependencies') of classic scripts are now included.
*
* @global WP_Scripts $wp_scripts
*
* @return array<string, array<string, string>> Array with an `imports` key mapping to an array of script module
* identifiers and their respective URLs, including the version query.
*/
private function get_import_map(): array {
global $wp_scripts;

$imports = array();
foreach ( array_keys( $this->get_dependencies( $this->queue ) ) as $id ) {

// Identify script modules that are dependencies of classic scripts.
$classic_script_module_dependencies = array();
if ( $wp_scripts instanceof WP_Scripts ) {
$handles = array_merge(
$wp_scripts->queue,
$wp_scripts->to_do,
$wp_scripts->done
);

$processed = array();
while ( ! empty( $handles ) ) {
$handle = array_pop( $handles );
if ( isset( $processed[ $handle ] ) || ! isset( $wp_scripts->registered[ $handle ] ) ) {
continue;
}
$processed[ $handle ] = true;

$module_dependencies = $wp_scripts->get_data( $handle, 'module_dependencies' );
if ( is_array( $module_dependencies ) ) {
$missing_module_dependencies = array();
foreach ( $module_dependencies as $module ) {
if ( is_string( $module ) ) {
$id = $module;
} elseif ( is_array( $module ) && isset( $module['id'] ) && is_string( $module['id'] ) ) {
$id = $module['id'];
} else {
// Invalid module dependency was supplied by direct manipulation of the extra data.
// Normally, this error scenario would be caught when WP_Scripts::add_data() is called.
continue;
}

if ( ! isset( $this->registered[ $id ] ) ) {
$missing_module_dependencies[] = $id;
} else {
$classic_script_module_dependencies[] = $id;
}
}

if ( count( $missing_module_dependencies ) > 0 ) {
_doing_it_wrong(
'WP_Scripts::add_data',
sprintf(
/* translators: 1: Script handle, 2: 'module_dependencies', 3: List of missing dependency IDs. */
__( 'The script with the handle "%1$s" was enqueued with script module dependencies ("%2$s") that are not registered: %3$s.' ),
$handle,
'module_dependencies',
implode( wp_get_list_item_separator(), $missing_module_dependencies )
),
'7.0.0'
);
}
}

foreach ( $wp_scripts->registered[ $handle ]->deps as $dep ) {
if ( ! isset( $processed[ $dep ] ) ) {
$handles[] = $dep;
}
}
}
}

// Note: the script modules in $this->queue are not included in the importmap because they get printed as scripts.
$ids = array_unique(
array_merge(
$classic_script_module_dependencies,
array_keys( $this->get_dependencies( array_merge( $this->queue, $classic_script_module_dependencies ) ) )
)
);
foreach ( $ids as $id ) {
$src = $this->get_src( $id );
if ( '' !== $src ) {
$imports[ $id ] = $src;
Expand Down
42 changes: 42 additions & 0 deletions src/wp-includes/class-wp-scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,48 @@ public function add_data( $handle, $key, $value ) {
);
return false;
}
} elseif ( 'module_dependencies' === $key ) {
if ( ! is_array( $value ) ) {
_doing_it_wrong(
__METHOD__,
sprintf(
/* translators: 1: 'module_dependencies', 2: Script handle. */
__( 'The value for "%1$s" must be an array for the "%2$s" script.' ),
'module_dependencies',
$handle
),
'7.0.0'
);
return false;
}

$sanitized_value = array();
$has_invalid_ids = false;
foreach ( $value as $module ) {
if (
is_string( $module ) ||
( is_array( $module ) && isset( $module['id'] ) && is_string( $module['id'] ) )
) {
$sanitized_value[] = $module;
} else {
$has_invalid_ids = true;
}
}

if ( $has_invalid_ids ) {
_doing_it_wrong(
__METHOD__,
sprintf(
/* translators: 1: Script handle, 2: 'module_dependencies' */
__( 'The script handle "%1$s" has one or more of its script module dependencies ("%2$s") which are invalid.' ),
$handle,
'module_dependencies'
),
'7.0.0'
);
}

$value = $sanitized_value;
}
return parent::add_data( $handle, $key, $value );
}
Expand Down
Loading
Loading