Skip to content

Everything for WordPress, web development — and beyond

🔌 Loading jQuery in WordPress: the right way

🔌 Loading jQuery in WordPress: the right way

You install a plugin and it drags in its own copy of jQuery. Your theme already loaded jQuery via wp_enqueue_script. The plugin, once again, loads it directly from a CDN. On the page: two or even three versions of the same library. Conflicts, bloated size, unpredictable behavior.

The problem is as old as WordPress itself, yet it still happens: developers copy-paste <script src="jquery.js"> into header.php "because it's faster." Faster, until the first conflict with a plugin that expects the native WP version.

As of 2026, WordPress ships jQuery 3.6.0 out of the box and provides a simple, deterministic way to include it without duplication and without manually tracking versions. Below is the only correct approach, from the basic wp_enqueue_script to safely replacing it with a CDN version and using noConflict mode.

💡 Quick overview:

  • How WordPress already loads jQuery and why you shouldn't do it manually
  • wp_enqueue_script with the jquery dependency: one line in functions.php
  • When and how to safely replace the built-in jQuery with a CDN version (Google / cdnjs)
  • noConflict mode: protection against collisions with other libraries
  • Tips for themes and plugins: when you should NOT override the built-in jQuery

jQuery is already in core: what WordPress does for you

Starting with version 3.6, WordPress registers jQuery under the handle jquery. You don't need to download jquery.min.js, place it in your theme folder, and include it with a <script> tag. The core does this automatically as soon as you specify jquery in your script's dependencies.

The current jQuery version in WordPress core is 3.6.0. It comes bundled with jQuery Migrate (for backward compatibility with legacy code) and loads only when some script declares jquery as a dependency. No dependencies means jQuery doesn't appear on the page, and the site doesn't load unnecessary resources.

This is why a direct <script src="/wp-content/themes/mytime/jquery.js"> in header.php is a mistake, not a shortcut. You bypass the dependency system, remove WP's ability to manage load order, and get a duplicate when a plugin legitimately requests jquery via wp_enqueue_script.

The right way: wp_enqueue_script with a dependency

The basic mechanics fit in one line inside the wp_enqueue_scripts hook. You write your script, and WordPress figures out when and in what order to load everything.

Create (or open) your theme's functions.php and add:

1function mytheme_enqueue_scripts() {
2 wp_enqueue_script(
3 'mytheme-main',
4 get_template_directory_uri() . '/js/main.js',
5 array( 'jquery' ),
6 '1.0.0',
7 array(
8 'strategy' => 'defer',
9 'in_footer' => true,
10 )
11 );
12}
13add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_scripts' );

What's happening here:

  • mytheme-main is the unique handle for your script. Come up with your own, prefixed with the theme name.
  • get_template_directory_uri() . '/js/main.js' is the path to the file. You can also use an external CDN URL.
  • array( 'jquery' ) is the key point: you're telling WP "my script depends on jQuery." The core sees this and automatically queues jQuery before your script. No <script> tags in the template.
  • '1.0.0' is the version for cache busting. Change it with every script update.
  • array( 'strategy' => 'defer', 'in_footer' => true ): since WordPress 6.3, the $args parameter accepts an array. defer means "execute the script after the DOM is built but before DOMContentLoaded." in_footer places the script in the footer.

The old syntax with a boolean fifth parameter (true = in footer) still works, but for new projects use the array syntax. It's more readable and gives you control over async/defer.

Verify that your theme calls wp_head() before the closing </head> and wp_footer() before </body>. Without these calls, wp_enqueue_script simply won't work. This is a common trap when migrating from ancient themes.

How to replace the built-in jQuery with your own version

Sometimes the native version isn't enough. You want jQuery 4.0.0 from a CDN for the latest fixes, or you need a specific version for compatibility with a legacy plugin. You can replace it, but carefully.

The mistake: simply calling wp_enqueue_script('jquery', 'https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js'). WordPress does NOT overwrite an already registered handle. You'll get both the native version AND the CDN version on the same page.

The correct sequence: first deregister the native jquery, then register your own:

1function mytheme_use_cdn_jquery() {
2 // Deregister the built-in jQuery
3 wp_deregister_script( 'jquery' );
4
5 // Register your own — from CDN
6 wp_register_script(
7 'jquery',
8 'https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js',
9 array(),
10 '4.0.0',
11 true
12 );
13
14 // Enqueue it
15 wp_enqueue_script( 'jquery' );
16}
17add_action( 'wp_enqueue_scripts', 'mytheme_use_cdn_jquery' );

Three points often overlooked:

Google Hosted Libraries. Google's alternative CDN is still alive and hosts jQuery 3.7.1: https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js. The upside: millions of sites already warm browser caches for this URL. The downside: Google adds its own headers and doesn't update versions immediately after release.

cdnjs. If you need jQuery 4.0.0, get it from cdn.jsdelivr.net/npm/[email protected]/. cdnjs mirrors the npm package and serves it with proper CORS headers.

Don't deregister jQuery in public themes. If your theme is going to the WordPress.org repository, use the native jQuery from core. The reason is simple: when a site has both a theme (with CDN jQuery 4.0.0) and a plugin (expecting jQuery 3.6.0 from core), the user resolves the conflict, not the developer. In commercial themes and custom projects, feel free to replace it.

noConflict mode: when there's more than one library on the page

By default, jQuery occupies the global variable $. The problem is that $ is a popular name: Prototype, MooTools, and some legacy frameworks use it too. If a plugin or another script also claims $, the one that loaded last wins, and the others break.

Protection in one line at the beginning of your script:

1var $j = jQuery.noConflict();

After this, $ is released for other libraries, and your code works through $j. Full example: a sidebar with hover animation:

1jQuery(document).ready( function( $ ) {
2 // Here $ is jQuery, but only inside this function
3 $( '#sidebar li a' ).hover(
4 function() {
5 $( this ).stop().animate( { paddingLeft: '20px' }, 400 );
6 },
7 function() {
8 $( this ).stop().animate( { paddingLeft: '0' }, 400 );
9 }
10 );
11} );

Here $ works as jQuery inside the jQuery(document).ready() closure, and outside it's free for others. This is cleaner than spawning $j, $jq, and $myJQ variables throughout your code.

When noConflict is not needed: if your site runs entirely on WordPress without third-party JS frameworks and all plugins are written for wp_enqueue_script, $ is safe. But including noConflict in your theme's standard boilerplate is a good habit that costs only one line.

What plugin developers should do

If you're writing a plugin for public distribution, use only wp_enqueue_script with a dependency on jquery. No wp_deregister_script('jquery') inside plugins: you don't know what jQuery version other plugins on the same site expect.

The correct pattern for a plugin looks like this:

1function myplugin_frontend_scripts() {
2 wp_enqueue_script(
3 'myplugin-frontend',
4 plugins_url( '/js/frontend.js', __FILE__ ),
5 array( 'jquery' ),
6 MYPLUGIN_VERSION,
7 true
8 );
9}
10add_action( 'wp_enqueue_scripts', 'myplugin_frontend_scripts' );

MYPLUGIN_VERSION is the plugin version constant. With every plugin update, the user's browser gets a fresh script instead of a cached old one.

For admin scripts (admin panel only), use the admin_enqueue_scripts hook. jQuery in the admin is also registered under the same handle jquery.

⁉️🤔 Frequently asked questions

Why doesn't my jQuery code work even though wp_enqueue_script is called correctly?

The most common cause: the theme doesn't call wp_head() and wp_footer(). Without these functions, WordPress physically cannot insert <script> tags into the HTML. Open header.php. There should be <?php wp_head(); ?> before </head>. In footer.php, there should be <?php wp_footer(); ?> before </body>. If the theme is ancient and these calls are missing, add them. This is safe. All modern themes and plugins rely on wp_head/wp_footer. Without them, not only script loading is broken but also SEO plugins, fonts, and structured data.

Can I use jQuery 4.0.0 in WordPress if core ships with 3.6.0?

Yes, via wp_deregister_script + wp_register_script (see the section above). But note: jQuery 4.0.0 dropped IE 11 support and several deprecated methods. If your site or plugin relies on jQuery Migrate, stick with the core version or include Migrate explicitly. WordPress is gradually moving toward native JavaScript and React for the block editor, but jQuery will remain in core for a long time: too many themes and plugins depend on it.

A plugin loads its own jQuery even though I already included it via functions.php. What should I do?

The plugin probably hardcoded <script src="jquery..."> bypassing wp_enqueue_script. This is the plugin's mistake. Two solutions: find the direct call in the plugin code and replace it with wp_enqueue_script with a dependency (if you're willing to patch the plugin), or contact the plugin author asking them to fix it. As a temporary workaround, you can call wp_dequeue_script or remove the plugin's hook, but this treats symptoms rather than the cause.

What's faster: jQuery from WordPress core or from a CDN?

If the user's browser already cached jQuery from a CDN (Google or cdnjs), the CDN version loads instantly with a 304 Not Modified code. If not, the loading speed difference between core and CDN is negligible for jQuery (about 85 KB gzipped). For high-traffic projects, a CDN saves your server's bandwidth; for a typical WordPress site, there's no difference.

Should you abandon jQuery in favor of native JS

Short answer: it depends on the project. Compressed jQuery 4.0.0 weighs about 85 KB. That's not zero, but it's not cause for panic either. Modern native JS (querySelectorAll, fetch, and classList) covers 90% of what people needed jQuery for in 2015. If you're building a new theme from scratch and don't depend on jQuery plugins, consider vanilla JS. It's cleaner and faster.

But if the project already has jQuery dependencies (sliders, galleries, plugin UI components), don't overcomplicate things. WordPress will load jQuery anyway when a plugin requests it. Write clean wp_enqueue_script calls with dependencies, don't interfere with core's load order management, and jQuery will work fast and predictably.

🔗 wp_enqueue_script documentation | 🔗 wp_deregister_script documentation