The supported way to add jQuery to a WordPress theme is to enqueue your script from functions.php on the wp_enqueue_scripts hook, declare WordPress’s registered jquery handle as a dependency, and write your JavaScript for noConflict() mode. This gives WordPress control over load order, avoids duplicate libraries, and prevents the common “$ is not defined” error.
Antihost offers managed WordPress hosting with free migration, one-click staging and a 14-day free trial.
What you are adding—and why the method matters
A theme usually needs two separate pieces: the jQuery library and your theme’s own JavaScript file. WordPress already registers a jQuery library, so your theme normally should not download or register another copy. Instead, your file declares that it depends on the registered handle named jquery.
As an Amazon Associate I earn from qualifying purchases.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →WordPress then builds the correct dependency order: jQuery is printed before your dependent file, and your file is printed only once even if another component also requests it. The API function for this is wp_enqueue_script(), called from the front-end wp_enqueue_scripts action. Hardcoding a <script> element in header.php bypasses that dependency system and can produce duplicate libraries, incorrect ordering, or conflicts with plugins.
The examples below assume a classic PHP theme. A child theme must use a URL helper that points to the directory where the JavaScript file actually exists.
#1 Best Overall
Recommended implementation in functions.php
1. Create the JavaScript file
For the example, create assets/js/main.js inside the theme that is active on the site. If the file belongs to a child theme, place it in the child-theme directory; if it belongs to the parent, place it in the parent directory and use the corresponding URI helper.
2. Enqueue it on the front end
Add this code to the active theme’s functions.php:
Free tools Windows power users keep installed
One-click scans. No signup required.
<?php
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_scripts' );
function mytheme_enqueue_scripts() {
wp_enqueue_script(
'mytheme-main',
get_parent_theme_file_uri( 'assets/js/main.js' ),
array( 'jquery' ),
wp_get_theme()->get( 'Version' ),
array(
'in_footer' => true,
)
);
}
Each argument has a job:
mytheme-main: a unique handle for your script. Use a theme-specific prefix so it does not collide with a plugin or another theme.get_parent_theme_file_uri( 'assets/js/main.js' ): builds the URL to a file in the parent theme. For a file in a child theme, useget_theme_file_uri( 'assets/js/main.js' )when that matches the location in your theme setup.array( 'jquery' ): declares the registered WordPress jQuery handle as a dependency. WordPress resolves this handle beforemytheme-main.wp_get_theme()->get( 'Version' ): uses the active theme version as the script version, helping browsers recognize a changed asset after a theme update.array( 'in_footer' => true ): asks WordPress to print the script in the footer rather than in the document head.
Use a different handle and function prefix for each theme. The handle is an internal identifier, not the filename, and changing the filename alone does not make a handle unique.
3. Confirm that the theme has the required template hooks
The active theme must call wp_head() in its head template and wp_footer() immediately before the closing body tag. WordPress uses those locations to print enqueued assets. Very old or heavily customized themes that omit either call may appear to accept the enqueue code while outputting no script tag.
Make the $ alias work in WordPress
WordPress loads its bundled jQuery in noConflict() mode. That means the global $ alias is not available in the way it is on a standalone jQuery page. Calling $( '.menu-toggle' ) at global scope can therefore produce “$ is not defined” or “$ is not a function.”
Use the theme handbook’s wrapper pattern
Wrap the file in an immediately invoked function expression (IIFE), accept jQuery as the argument, and use $ only inside that function:
Recommended Free Tools
Rank #2
( function( $ ) {
$( function() {
$( '.menu-toggle' ).on( 'click', function() {
$( '.site-navigation' ).toggleClass( 'is-open' );
} );
} );
} )( jQuery );
The outer function creates a local $ variable. The final )( jQuery ) passes WordPress’s global jQuery object into that local parameter. The inner callback waits until the document is ready before looking for the button and navigation elements.
Use the ready callback’s local parameter instead
This equivalent form keeps the alias local to the ready callback:
jQuery( document ).ready( function( $ ) {
$( '.menu-toggle' ).on( 'click', function() {
$( '.site-navigation' ).toggleClass( 'is-open' );
} );
} );
Both patterns are safe. The important rule is not to assume that $ is globally available in a WordPress theme.
How WordPress decides script order
When you pass array( 'jquery' ) as the dependency list, you are declaring a relationship rather than manually arranging tags. WordPress knows that your handle requires the registered jquery handle and resolves that dependency before printing your script. If another enqueued script also depends on jQuery, WordPress can share the same registered library instead of adding another copy.
| Approach | What happens | Typical result |
|---|---|---|
Enqueue with array( 'jquery' ) |
WordPress resolves the registered dependency and prints the files in dependency order. | Preferred for theme code; compatible with other enqueued assets. |
Hardcoded tag in header.php |
The browser sees a tag, but WordPress does not know the relationship or handle. | Possible ordering errors, duplicate libraries, and harder maintenance. |
| Manual second jQuery copy | A theme loads a separate library in addition to the registered one. | Potential plugin conflicts, different versions, and two competing jQuery objects. |
Global $ usage |
Code assumes the standalone jQuery alias exists. | “$ is not defined” or “$ is not a function” in WordPress. |
| IIFE or ready-callback wrapper | $ is mapped to the global jQuery object only inside a local scope. |
Works with WordPress’s noConflict() behavior. |
Choosing the correct theme URL helper
The URL must match the theme directory that contains the file. A wrong helper can produce a valid-looking URL that returns a 404.
- Parent-theme file:
get_parent_theme_file_uri( 'assets/js/main.js' ). - Active-theme file:
get_theme_file_uri( 'assets/js/main.js' )when the file should resolve from the active theme, including a child theme where appropriate. - Child-theme-specific file: use a child-theme URI helper available in your theme’s setup, or construct the URL from the child stylesheet directory when that is how the theme organizes assets.
Do not mix a parent URL helper with a file that exists only in the child directory. In browser developer tools, open the generated script URL directly; a 404 confirms a path or directory mismatch rather than a jQuery problem.
Rank #3
Footer, defer, and async options
The fifth argument to wp_enqueue_script() can be an arguments array. WordPress 6.3 and later document options including in_footer and a loading strategy.
Conservative footer loading
The example’s in_footer => true is the safest general starting point for a theme script. It keeps the script out of the head while preserving the dependency relationship.
Adding defer
If the script and its dependencies do not require immediate execution during parsing, you can request deferred loading:
wp_enqueue_script(
'mytheme-main',
get_parent_theme_file_uri( 'assets/js/main.js' ),
array( 'jquery' ),
wp_get_theme()->get( 'Version' ),
array(
'in_footer' => true,
'strategy' => 'defer',
)
);
Test this change with every feature that depends on the script. A loading strategy can expose assumptions about execution timing, inline scripts, or code that expects a library to be ready during parsing.
Why async needs more caution
async allows a script to execute as soon as it finishes downloading, so execution order is not guaranteed. That is a poor fit for a file that depends on jQuery or for code whose behavior depends on another script. Use it only when the script is genuinely independent and you have verified that no ordering relationship is required.
Bundled jQuery versus loading a custom copy
The WordPress Theme Handbook advises themes not to replace a library that WordPress already bundles. The registered jquery handle is the integration point expected by themes and plugins. Reusing it means other components can share the same dependency and reduces the chance that two versions will attach different behavior to the page.
Rank #4
| Decision | Use the bundled handle when… | Consider another architecture only when… |
|---|---|---|
| Library source | Your code needs ordinary jQuery APIs and no special build requirement. | A documented compatibility constraint requires a separate, isolated implementation. |
| Version management | You want WordPress and its ecosystem to manage the registered library. | You control every dependent script and have a tested reason to pin a different library. |
| Conflict risk | You want to avoid duplicate jQuery objects and plugin incompatibilities. | You have an explicit isolation strategy and have tested it with the active plugins. |
Do not add a second CDN or theme-local jQuery file merely because it is familiar from a non-WordPress project. If you need behavior that the bundled version does not provide, document the compatibility requirement and test the complete site rather than silently replacing the registered handle.
Conditional loading for a smaller front end
You do not have to load every theme script on every URL. Keep the dependency declaration, but enqueue the file only where its feature exists. For example, a script used by a template-specific gallery can be wrapped in a conditional such as is_page_template(), an existing page check, or a post-type check that matches your site.
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_gallery' );
function mytheme_enqueue_gallery() {
if ( ! is_page_template( 'templates/gallery.php' ) ) {
return;
}
wp_enqueue_script(
'mytheme-gallery',
get_theme_file_uri( 'assets/js/gallery.js' ),
array( 'jquery' ),
wp_get_theme()->get( 'Version' ),
array( 'in_footer' => true )
);
}
The condition must run on the front-end enqueue hook, where WordPress’s query context is available. Keep the handle unique even when several conditional scripts are defined in the same function file.
Complete setup checklist
- The file exists under the active parent or child theme directory.
- The enqueue callback is attached to
wp_enqueue_scripts, not an admin-only hook. - The handle is unique and appears only once in your theme code.
- The URL helper points to the directory that actually contains the file.
array( 'jquery' )is present when the file calls jQuery.- Your JavaScript uses
jQuerydirectly or maps it to a local$with an IIFE or ready callback. - The active theme calls both
wp_head()andwp_footer(). - The browser can load the generated file without a 404.
- Any optimization, caching, concatenation, delay, or minification layer has been tested with the new dependency.
Troubleshooting common failures
“$ is not defined”
This means the code is trying to use the shorthand outside a safe local scope, or jQuery did not load at all. First inspect the page source or Network panel to see whether the WordPress jQuery file is present. If it is present, change the file to the IIFE or ready-callback pattern and ensure the enqueue dependency is array( 'jquery' ).
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minute“jQuery is not defined”
The library itself is unavailable when your file executes. Check that the enqueue callback runs, that the handle is spelled exactly jquery, and that no optimization tool has reordered or removed the dependency. A theme or plugin that deregisters jQuery can also cause this symptom; identify that change before adding a duplicate library.
“$ is not a function”
In WordPress this often means $ refers to something other than jQuery, or the alias is being used outside the wrapper. Use jQuery at the boundary and a local $ inside the callback. Also check for a JavaScript syntax error earlier in the page that prevented initialization.
Best Value
The script URL returns 404
Compare the generated URL with the real directory and filename, including capitalization. Parent and child theme paths are different. Correct the URI helper or move the file to the directory represented by the helper; do not try to solve a path error by changing jQuery code.
The file never appears in the HTML
Verify that the function is in the active theme’s functions.php, that the action name is exactly wp_enqueue_scripts, and that the template prints wp_head() and wp_footer(). If a conditional surrounds the enqueue call, temporarily remove the condition to determine whether the condition is excluding the current URL.
It worked until a cache or optimization change
Optimization layers can concatenate, delay, defer, or reorder scripts. Inspect the final generated markup and console errors rather than only the original PHP. Exclude the dependent pair from an optimization rule temporarily, then re-enable settings one at a time while preserving the declared dependency.
Practical debugging workflow
- Open the page in a private browser window with caches cleared.
- In developer tools, check the Console for
jQuery is not defined,$ is not a function, syntax errors, and the first failing line. - In the Network panel, filter for JavaScript and confirm that the jQuery request and your theme file both load successfully.
- Open your theme file’s response and verify that it is the expected JavaScript rather than an HTML error page.
- Inspect the final document or page source to confirm that the dependency is printed before the dependent script.
- Disable script optimization or delay features briefly. If the error disappears, restore the feature and add a dependency-aware exclusion or configuration.
- Test logged-out and logged-in views, because admin-bar markup, permissions, and conditional templates can change the page context.
When jQuery is the wrong tool
Adding jQuery is appropriate when the theme feature or an existing WordPress-compatible component requires it. For a small interaction, modern browser APIs can avoid a library dependency altogether, but that is a design decision rather than a reason to load a second jQuery copy. If you do use jQuery, follow WordPress’s registered-handle and noConflict() conventions so your code coexists with the rest of the site.
Final implementation reference
Use this compact pair as a known-good baseline, then adapt the selector and URL to your theme.
<?php
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_scripts' );
function mytheme_enqueue_scripts() {
wp_enqueue_script(
'mytheme-main',
get_parent_theme_file_uri( 'assets/js/main.js' ),
array( 'jquery' ),
wp_get_theme()->get( 'Version' ),
array( 'in_footer' => true )
);
}
( function( $ ) {
$( function() {
$( '.menu-toggle' ).on( 'click', function() {
$( '.site-navigation' ).toggleClass( 'is-open' );
} );
} );
} )( jQuery );
This arrangement expresses the dependency, respects WordPress’s jQuery mode, and leaves WordPress in charge of printing and ordering the scripts.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesQuick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

