WordPress lets you register your own script files with your theme or plugin instead of hardcoding a <script> tag into your header or footer. The traditional approach loads scripts unconditionally on every page, whether they’re needed or not, and gives WordPress no way to manage load order or avoid duplicate copies of the same library. Registering scripts with wp_register_script() (and loading them with wp_enqueue_script()) lets WordPress handle dependencies, versioning, and placement for you, which keeps your site faster and your script loading predictable.
So how do you register a script?
Use the following syntax to register a script. This is typically called inside a function hooked to wp_enqueue_scripts (more on that below).
wp_register_script( $handle, $src, $deps, $ver, $in_footer );
Parameters — this signature has not changed since this post was first written, so everything below is still accurate. The only thing that needed updating was the example dependency used to illustrate it (see below).
$handle
‘handle’ is simply the name of your script. You can give it any name you like, but it must be unique throughout your theme or plugin — no two registered scripts can share the same handle.
$src
‘src’ is the URL to your script file. This can point to a file inside your own theme or plugin, or to a script hosted elsewhere such as a CDN.
Here’s a practical example that registers a theme’s own main.js file, with jQuery (which WordPress ships with core) listed as a dependency:
function ankurm_register_scripts() {
wp_register_script(
'ankurm-main',
get_template_directory_uri() . '/js/main.js',
array( 'jquery' ),
'1.0.0',
true
);
}
add_action( 'wp_enqueue_scripts', 'ankurm_register_scripts' );
An earlier version of this post used AngularJS 1.1.5 from a CDN as the example ‘src’. That example is long out of date — AngularJS 1.x reached end of life in January 2022, and version 1.1.5 itself dates back to 2013. Pulling in an abandoned library is exactly the kind of thing wp_register_script() is meant to help you manage deliberately, not stumble into by copying an old snippet, so the example above now registers a theme’s own script instead. If you do need to pull a third-party library from a CDN, just make sure it’s a version that is still maintained and swap the URL in as the $src argument — everything else about the call stays the same.
$deps
If your script depends on other scripts, list their handles in an array here. This is one of the most useful parts of wp_register_script(), because WordPress will guarantee that every handle in $deps is loaded before the current script, regardless of the order in which you registered things.
For example, say you register a second script that depends on the ankurm-main handle registered above:
wp_register_script(
'ankurm-widgets',
get_template_directory_uri() . '/js/widgets.js',
array( 'jquery', 'ankurm-main' ),
'1.0.0',
true
);
Here, widgets.js declares both jquery and ankurm-main as dependencies. WordPress will load jquery, then ankurm-main, and only then ankurm-widgets — in that order, on every page where ankurm-widgets is enqueued. You never need to manually order your <script> tags yourself; you only need to declare the relationships correctly and WordPress resolves the load order for you. This also means you can register a script in one place and enqueue it conditionally somewhere else, and the dependency chain still resolves correctly.
$ver
‘ver’ specifies a version number, which WordPress appends to the script URL as a query string (e.g. ?ver=1.0.0). This is primarily used for cache busting: when you bump the version number, browsers and caching layers treat it as a new URL and fetch the latest file instead of serving a stale cached copy. If you leave this parameter unset or pass false, WordPress uses the current WordPress version number by default. Passing null omits the version query string entirely. For your own theme/plugin scripts, it’s best practice to bump $ver deliberately whenever you change the file, so browsers pick up the update.
$in_footer
If you set this parameter to true, the script is printed in the footer (right before </body>) instead of in <head>. This requires your theme to call wp_footer() in the appropriate place, which virtually every modern theme already does. Loading non-critical scripts in the footer is generally good practice, since it avoids blocking the initial render of the page. If you omit this parameter, WordPress defaults to loading the script in <head>.
How do you load a registered script in your theme?
Registering a script only tells WordPress that the script exists and how it relates to other scripts — it does not actually load it on the page. To do that, you call wp_enqueue_script() and pass it the handle:
wp_enqueue_script( 'ankurm-main' );
You can also skip the separate registration step entirely and call wp_enqueue_script() directly with the same arguments — it accepts the same $handle, $src, $deps, $ver, and $in_footer parameters as wp_register_script(). Registering first is mainly useful when other scripts (yours or a plugin’s) need to declare a dependency on your handle without necessarily loading it themselves.
Always hook into wp_enqueue_scripts
Both wp_register_script() and wp_enqueue_script() should be called from a function attached to the wp_enqueue_scripts action hook, as shown in the example above. This is the hook WordPress fires specifically for queuing up front-end scripts and styles, and it runs early enough in the page lifecycle that your script and style queues are fully resolved before WordPress prints them. Calling these functions directly in your theme’s template files (outside of any hook) or too late in the request will cause scripts to be missed entirely or loaded in the wrong order. For admin-side scripts, use the analogous admin_enqueue_scripts hook instead.
That’s all there is to it. You’ve now seen how to register a script with the correct dependencies, version, and placement, and how to load it safely from the right hook.
FAQs
Do I need to register a script before enqueuing it?
No. wp_enqueue_script() accepts the same parameters as wp_register_script(), so for a script you only use in one place, you can enqueue it directly. Registering first is only necessary if you want other code to be able to reference the handle as a dependency without loading it itself.
What happens if I list a handle in $deps that hasn’t been registered?
WordPress will silently skip the missing dependency rather than throwing a fatal error, but your script may break at runtime if it actually relies on that dependency being present. Always double check the handle is spelled correctly and registered somewhere before it’s needed.
Is it safe to load scripts from a third-party CDN instead of bundling them?
It works mechanically — you simply pass the CDN URL as $src — but you take on the risk of that CDN going down, changing, or serving an outdated/abandoned version of the library (the AngularJS 1.1.5 example earlier in this post’s history is a cautionary example). For production sites, it’s generally safer to bundle a specific, current version of any third-party script with your theme or plugin so you control when and how it updates.
Conclusion
wp_register_script() and wp_enqueue_script() give WordPress everything it needs to load your scripts efficiently: a unique handle, a source URL, an explicit dependency list, a version for cache busting, and a choice of header or footer placement. Hook your calls into wp_enqueue_scripts, declare your dependencies honestly in $deps, and WordPress will take care of getting everything loaded in the right order.
Reference
You can visit the following WordPress developer reference pages for more information.