Script Modules Hooks
Actions and filters for customizing script module behavior.
Source: wp-includes/class-wp-script-modules.php
Filters
script_module_loader_src
Filters the script module source URL.
apply_filters( 'script_module_loader_src', string $src, string $id )
Since: 6.5.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$src |
string |
Module source URL (with version query param). |
$id |
string |
Module identifier. |
Return
string — Filtered source URL. Non-string returns become empty string.
Example
// Use a CDN for certain modules
add_filter( 'script_module_loader_src', function( $src, $id ) {
if ( str_starts_with( $id, '@wordpress/' ) ) {
return str_replace(
site_url( '/wp-includes/' ),
'https://cdn.example.com/wp/',
$src
);
}
return $src;
}, 10, 2 );
// Add integrity hash
add_filter( 'script_module_loader_src', function( $src, $id ) {
if ( 'my-plugin/main' === $id ) {
// Note: This modifies URL, not the tag attributes
// For SRI, you'd need to filter the tag output
}
return $src;
}, 10, 2 );
script_module_data_{$module_id}
Filters data associated with a specific script module.
apply_filters( "script_module_data_{$module_id}", array $data )
Since: 6.7.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$data |
array |
Data to embed for this module. Default empty array. |
Return
array — Filtered data. If empty array, nothing is embedded.
Description
Data passed through this filter is JSON-serialized and embedded in the page as a <script type="application/json"> tag with ID wp-script-module-data-{$module_id}.
This is useful for passing configuration, nonces, or other data that the module needs immediately on load, without requiring an additional API request.
Example: Passing Configuration
add_filter( 'script_module_data_my-plugin/gallery', function( $data ) {
$data['config'] = array(
'apiEndpoint' => rest_url( 'my-plugin/v1/images' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'maxItems' => 50,
);
return $data;
} );
Example: Passing User Data
add_filter( 'script_module_data_my-plugin/dashboard', function( $data ) {
if ( is_user_logged_in() ) {
$user = wp_get_current_user();
$data['user'] = array(
'id' => $user->ID,
'name' => $user->display_name,
'canEdit' => current_user_can( 'edit_posts' ),
);
}
return $data;
} );
Reading Data in JavaScript
// In your ES module
function getModuleData( moduleId ) {
const el = document.getElementById( `wp-script-module-data-${ moduleId }` );
if ( el ) {
try {
return JSON.parse( el.textContent );
} catch ( e ) {
console.error( 'Failed to parse module data:', e );
}
}
return {};
}
// Usage
const data = getModuleData( 'my-plugin/gallery' );
console.log( data.config.apiEndpoint );
Output
<script type="application/json" id="wp-script-module-data-my-plugin/gallery">
{"config":{"apiEndpoint":"https://example.com/wp-json/my-plugin/v1/images","nonce":"abc123","maxItems":50}}
</script>
Internal Hooks
These hooks are used by WordPress internally but can be leveraged:
wp_head / wp_footer / admin_print_footer_scripts
WP_Script_Modules::add_hooks() attaches output methods to these standard WordPress hooks:
| Hook | Block Themes | Classic Themes | Admin |
|---|---|---|---|
wp_head |
import map, preloads, head modules | — | — |
wp_footer |
footer modules, data, a11y HTML | all output | — |
admin_print_footer_scripts |
— | — | all output |
You can use these hooks to add your own module-related output:
// Add custom importmap entries (advanced)
add_action( 'wp_head', function() {
// Note: This is a workaround. Prefer wp_register_script_module().
echo '<script type="importmap-shim">{"imports":{"custom":"..."}}</script>';
}, 1 ); // Before WordPress prints its import map
No Hook: Registration Timing
Unlike wp_enqueue_scripts, there’s no dedicated hook for script module registration. Register modules when your code loads:
// In a plugin
add_action( 'init', function() {
wp_register_script_module(
'my-plugin/main',
plugins_url( 'js/main.js', __FILE__ ),
array( '@wordpress/interactivity' ),
'1.0.0'
);
} );
// Enqueue when needed (e.g., in a block's render callback)
add_action( 'render_block_my-plugin/gallery', function( $content ) {
wp_enqueue_script_module( 'my-plugin/main' );
return $content;
} );
Or use wp_enqueue_scripts for frontend modules:
add_action( 'wp_enqueue_scripts', function() {
if ( is_singular( 'gallery' ) ) {
wp_enqueue_script_module( 'my-plugin/gallery' );
}
} );
Hook Priorities
When working with script modules, be aware of default priorities:
| Method | Hook | Priority |
|---|---|---|
print_import_map |
wp_head/wp_footer |
10 |
print_script_module_preloads |
wp_head/wp_footer |
10 |
print_head_enqueued_script_modules |
wp_head |
10 |
print_enqueued_script_modules |
wp_footer |
10 |
print_script_module_data |
wp_footer |
10 |
print_a11y_script_module_html |
wp_footer |
20 |
The a11y HTML prints at priority 20 to ensure it comes after the data.