{"id":5818,"date":"2026-02-12T20:45:29","date_gmt":"2026-02-13T01:45:29","guid":{"rendered":"https:\/\/chubes.net\/?documentation=script-modules-api"},"modified":"2026-03-13T03:29:23","modified_gmt":"2026-03-13T07:29:23","slug":"script-modules-api","status":"publish","type":"documentation","link":"https:\/\/chubes.net\/docs\/wordpress-core\/script-modules\/script-modules-api\/","title":{"rendered":"Script Modules API"},"content":{"rendered":"<p>Native support for ES Modules and Import Maps in WordPress.<\/p><p><strong>Since:<\/strong> 6.5.0<br \/>\n<strong>Source:<\/strong> <code>wp-includes\/script-modules.php<\/code>, <code>wp-includes\/class-wp-script-modules.php<\/code><\/p><h2 class=\"wp-block-heading\">Components<\/h2><figure class=\"wp-block-table\"><table><thead><tr><th>Component<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><a href=\"https:\/\/chubes.net\/docs\/wordpress-core\/script-modules\/script-modules-functions\/\">functions.md<\/a><\/td><td>Core registration and enqueue functions<\/td><\/tr><tr><td><a href=\"https:\/\/chubes.net\/docs\/wordpress-core\/script-modules\/wp_script_modules-class\/\">class-wp-script-modules.md<\/a><\/td><td>Script modules registry class<\/td><\/tr><tr><td><a href=\"https:\/\/chubes.net\/docs\/wordpress-core\/script-modules\/script-modules-hooks\/\">hooks.md<\/a><\/td><td>Actions and filters<\/td><\/tr><\/tbody><\/table><\/figure><h2 class=\"wp-block-heading\">What Are Script Modules?<\/h2><p>Script Modules are WordPress&#8217;s implementation of native ES Modules (ESM). Unlike traditional scripts loaded with <code>wp_enqueue_script()<\/code>, script modules:<\/p><ul class=\"wp-block-list\"><li>Use <code>&lt;script type=&quot;module&quot;&gt;<\/code> tags<\/li><li>Support native <code>import<\/code>\/<code>export<\/code> syntax<\/li><li>Leverage browser import maps for dependency resolution<\/li><li>Are deferred by default (no blocking)<\/li><li>Have module scope (not global)<\/li><\/ul><h2 class=\"wp-block-heading\">Import Maps<\/h2><p>Import maps allow bare module specifiers (like <code>@wordpress\/interactivity<\/code>) to resolve to actual URLs. WordPress automatically generates an import map containing all registered script modules and their dependencies.<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">html<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-html\"><code class=\"language-html\">&lt;script type=&quot;importmap&quot; id=&quot;wp-importmap&quot;&gt;\n{\n  &quot;imports&quot;: {\n    &quot;@wordpress\/interactivity&quot;: &quot;\/wp-includes\/js\/dist\/script-modules\/interactivity\/index.min.js?ver=6.7&quot;\n  }\n}\n&lt;\/script&gt;<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Registration Flow<\/h2><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\"><\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code\"><code>wp_register_script_module( $id, $src, $deps, $version, $args )\n    \u2514\u2500\u2500 WP_Script_Modules::register()\n            \u2514\u2500\u2500 Store in $registered array<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Enqueue Flow<\/h2><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\"><\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code\"><code>wp_enqueue_script_module( $id )\n    \u2514\u2500\u2500 WP_Script_Modules::enqueue()\n            \u2514\u2500\u2500 Add to $queue array<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Output Flow<\/h2><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\"><\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code\"><code>add_hooks()\n    \u251c\u2500\u2500 wp_head (block themes) or wp_footer (classic themes)\n    \u2502       \u251c\u2500\u2500 print_import_map()\n    \u2502       \u2514\u2500\u2500 print_script_module_preloads()\n    \u2502\n    \u251c\u2500\u2500 wp_head (block themes only)\n    \u2502       \u2514\u2500\u2500 print_head_enqueued_script_modules()\n    \u2502\n    \u2514\u2500\u2500 wp_footer\n            \u251c\u2500\u2500 print_enqueued_script_modules()\n            \u251c\u2500\u2500 print_script_module_data()\n            \u2514\u2500\u2500 print_a11y_script_module_html()<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Block Themes vs Classic Themes<\/h2><figure class=\"wp-block-table\"><table><thead><tr><th>Behavior<\/th><th>Block Themes<\/th><th>Classic Themes<\/th><\/tr><\/thead><tbody><tr><td>Import map location<\/td><td><code>wp_head<\/code><\/td><td><code>wp_footer<\/code><\/td><\/tr><tr><td>Head script modules<\/td><td>Supported (<code>in_footer: false<\/code>)<\/td><td>Not supported<\/td><\/tr><tr><td>Module preloads<\/td><td><code>wp_head<\/code><\/td><td><code>wp_footer<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p>In classic themes, script modules used by blocks aren&#8217;t known at <code>wp_head<\/code>, so everything prints in the footer.<\/p><h2 class=\"wp-block-heading\">Dependencies<\/h2><p>Dependencies can be static or dynamic:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">\/\/ Static dependency (preloaded, in import map)\nwp_register_script_module( &#039;my-module&#039;, $src, array( &#039;other-module&#039; ) );\n\n\/\/ Dynamic dependency (in import map only, not preloaded)\nwp_register_script_module( &#039;my-module&#039;, $src, array(\n    array( &#039;id&#039; =&gt; &#039;lazy-module&#039;, &#039;import&#039; =&gt; &#039;dynamic&#039; )\n) );<\/code><\/pre><\/div><ul class=\"wp-block-list\"><li><strong>Static<\/strong>: Loaded immediately via <code>&lt;link rel=&quot;modulepreload&quot;&gt;<\/code> and included in import map<\/li><li><strong>Dynamic<\/strong>: Only included in import map for runtime <code>import()<\/code> calls<\/li><\/ul><h2 class=\"wp-block-heading\">Fetch Priority<\/h2><p>Script modules support the <code>fetchpriority<\/code> attribute (since 6.9.0):<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">wp_register_script_module( &#039;critical-module&#039;, $src, array(), false, array(\n    &#039;fetchpriority&#039; =&gt; &#039;high&#039;\n) );<\/code><\/pre><\/div><figure class=\"wp-block-table\"><table><thead><tr><th>Value<\/th><th>Behavior<\/th><\/tr><\/thead><tbody><tr><td><code>'auto'<\/code><\/td><td>Browser default (default)<\/td><\/tr><tr><td><code>'low'<\/code><\/td><td>Lower priority, non-critical path<\/td><\/tr><tr><td><code>'high'<\/code><\/td><td>Higher priority, critical path<\/td><\/tr><\/tbody><\/table><\/figure><p>WordPress core modules (<code>@wordpress\/interactivity<\/code>, <code>@wordpress\/block-library\/*<\/code>, <code>@wordpress\/a11y<\/code>) use <code>fetchpriority: low<\/code> and <code>in_footer: true<\/code> since they&#8217;re not needed for critical rendering.<\/p><h2 class=\"wp-block-heading\">Default Script Modules<\/h2><p>WordPress registers these modules via <code>wp_default_script_modules()<\/code>:<\/p><figure class=\"wp-block-table\"><table><thead><tr><th>Module ID<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><code>@wordpress\/interactivity<\/code><\/td><td>Interactivity API runtime<\/td><\/tr><tr><td><code>@wordpress\/interactivity-router<\/code><\/td><td>Client-side navigation<\/td><\/tr><tr><td><code>@wordpress\/block-library\/*<\/code><\/td><td>Block-specific view scripts<\/td><\/tr><tr><td><code>@wordpress\/a11y<\/code><\/td><td>Accessibility announcements<\/td><\/tr><\/tbody><\/table><\/figure><h2 class=\"wp-block-heading\">Example Usage<\/h2><h3 class=\"wp-block-heading\">Register and Enqueue<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">\/\/ Register a script module\nwp_register_script_module(\n    &#039;my-plugin\/gallery&#039;,\n    plugin_dir_url( __FILE__ ) . &#039;js\/gallery.js&#039;,\n    array( &#039;@wordpress\/interactivity&#039; ),\n    &#039;1.0.0&#039;\n);\n\n\/\/ Enqueue it\nwp_enqueue_script_module( &#039;my-plugin\/gallery&#039; );<\/code><\/pre><\/div><h3 class=\"wp-block-heading\">Register and Enqueue in One Call<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">wp_enqueue_script_module(\n    &#039;my-plugin\/gallery&#039;,\n    plugin_dir_url( __FILE__ ) . &#039;js\/gallery.js&#039;,\n    array( &#039;@wordpress\/interactivity&#039; ),\n    &#039;1.0.0&#039;\n);<\/code><\/pre><\/div><h3 class=\"wp-block-heading\">Passing Data to Modules<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">add_filter( &#039;script_module_data_my-plugin\/gallery&#039;, function( $data ) {\n    $data[&#039;apiEndpoint&#039;] = rest_url( &#039;my-plugin\/v1\/images&#039; );\n    $data[&#039;nonce&#039;] = wp_create_nonce( &#039;wp_rest&#039; );\n    return $data;\n} );<\/code><\/pre><\/div><p>In JavaScript:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">javascript<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-javascript\"><code class=\"language-javascript\">const dataEl = document.getElementById( &#039;wp-script-module-data-my-plugin\/gallery&#039; );\nconst data = dataEl ? JSON.parse( dataEl.textContent ) : {};\nconsole.log( data.apiEndpoint );<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Best Practices<\/h2><ol class=\"wp-block-list\"><li><strong>Use namespaced IDs<\/strong>: <code>my-plugin\/module-name<\/code> prevents collisions<\/li><li><strong>Prefer static dependencies<\/strong>: Only use dynamic for lazy-loaded code<\/li><li><strong>Set appropriate fetchpriority<\/strong>: Use <code>low<\/code> for non-critical modules<\/li><li><strong>Use <code>in_footer<\/code> for non-critical modules<\/strong>: Especially in block themes<\/li><li><strong>Don&#8217;t mix with <code>wp_enqueue_script()<\/code><\/strong>: Keep ES modules separate from classic scripts<\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>Native support for ES Modules and Import Maps in WordPress. Since: 6.5.0 Source: wp-includes\/script-modules.php, wp-includes\/class-wp-script-modules.php Components Component Description functions.md Core registration and enqueue functions class-wp-script-modules.md Script modules registry class hooks.md&#8230;<\/p>\n","protected":false},"featured_media":0,"template":"","meta":{"footnotes":""},"tags":[],"project":[658],"project_type":[749],"class_list":["post-5818","documentation","type-documentation","status-publish","hentry","project-script-modules","project_type-wordpress-reference"],"project_info":{"id":589,"name":"WordPress Core","slug":"wordpress-core"},"project_type_info":{"id":749,"name":"WordPress Reference","slug":"wordpress-reference"},"_links":{"self":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation\/5818","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation"}],"about":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/types\/documentation"}],"version-history":[{"count":3,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation\/5818\/revisions"}],"predecessor-version":[{"id":10994,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation\/5818\/revisions\/10994"}],"wp:attachment":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/media?parent=5818"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/tags?post=5818"},{"taxonomy":"project","embeddable":true,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/project?post=5818"},{"taxonomy":"project_type","embeddable":true,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/project_type?post=5818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}