I’m having trouble getting ES6 modules to work properly in WordPress. This is my first time working with modules and I’m trying to better organize my JavaScript code.
The Problem
I keep getting this error in Chrome: Uncaught SyntaxError: import declarations may only appear at top level of a module
What I’m Trying to Do
I want to import functions from my utilities.js file into other scripts like shop.js. I’m using WordPress’s built-in script enqueuing system.
My Current Setup
WordPress Functions File
In my functions.php, I’m enqueuing the scripts and trying to add the module type:
if (is_shop()) {
// Load utility functions as module
wp_enqueue_script('utils-js', get_template_directory_uri() . '/js/utilities.js', array('shop-js'), $version, true);
// Add module type to script tag
add_filter('script_loader_tag', 'make_script_module', 10, 3);
function make_script_module($tag, $handle, $src) {
if ('utils-js' === $handle) {
$tag = '<script src="' . $src . '" type="module"></script>';
}
return $tag;
}
// Main shop script
wp_enqueue_script('shop-js', get_template_directory_uri() . '/js/shop.js', array(), $version, true);
}
Module File (utilities.js)
const hideSelectedOption = (dropdown, valueToHide) => {
for (let j = 0; j < dropdown.length; j++) {
if (dropdown.options[j].value === valueToHide) {
dropdown.classList.remove("active");
dropdown[j].remove();
}
}
};
export { hideSelectedOption };
Main Script (shop.js)
import { hideSelectedOption } from "./utilities.js";
The scripts are loading in the right order but I still get the syntax error. What am I missing here? How do I properly set up ES6 modules in WordPress?
Had this exact problem six months ago migrating a WordPress project to ES6 modules. Your script loader filter only targets utils-js but you’re missing shop-js. Since shop.js has the import statement, the browser needs to treat it as a module too.
Update your filter to check both handles:
function make_script_module($tag, $handle, $src) {
if (in_array($handle, ['utils-js', 'shop-js'])) {
$tag = '<script src="' . $src . '" type="module"></script>';
}
return $tag;
}
Also ditch the dependency array from your shop-js enqueue call. ES6 imports handle loading order automatically - the browser fetches utilities.js when it hits the import in shop.js.
One heads up: module scripts defer by default. They won’t block HTML parsing but might change when your code runs compared to DOM events.
Had this exact same problem when I started using ES6 modules with WordPress. Your main script shop.js needs to be loaded as a module too, not just the utility file. When you import from a module, the browser has to treat the importing script as a module as well. Fix your filter function to handle both scripts - add a condition for ‘shop-js’ in your make_script_module function. Watch out for the dependencies array though. If shop.js imports from utilities.js, you might want to drop that dependency since ES6 imports handle the relationship directly. One thing that bit me - module scripts are deferred by default, so they load after DOM parsing. Can cause timing issues if you expect scripts to run right away. Just heads up in case you see weird behavior once the imports start working.
your dependency order’s wrong - you’re loading shop.js with utils-js as a dependency, but modules don’t work like that. drop the dependency array from shop.js since the import statement already handles loading. also, both scripts need type=“module”, not just utilities.js.