jQuery in WordPress

This page is primarily intended for those who code for WordPress… 🤓

Work in Progress

Actual jQuery tutorials are not provided here, those are plentiful elsewhere and to be frank, I have to use them whenever I create with jQuery which means I am not the one who should be writing them. However, setting up WordPress for proper jQuery use I believe I have nailed.

WordPress and jQuery

There are three libraries frequently used on WordPress sites:

  1. jQuery Core (version 1.12.4)
  2. jQuery Migrate (version 1.4.1)
  3. jQuery UI (version ???)

Additionally, there are jQuery UI Themes that are not packaged with WordPress but at least a few of them should be.

Using jQuery Core in WordPress

Most jQuery scripts are written for jQuery Core. When you read various articles around the web on WordPress, you will find people telling you that if your plugin or theme has a jQuery script works with jQuery 1.9 that the proper way to enqueue it is to specify jquery-core as the dependency, for example:

wp_enqueue_script('my-cool-script',
                  '/path/to/myscript.js',
                  array('jquery-core'),
                  1.1.4);

These websites will that you that is wrong to just use jquery as the dependency, explaining geeky detail about how when you specify jquery as a dependency it causes jquery-migrate to be loaded as well, and (oh my the sky is falling) how that means an extra connection that slows down page loads!

The advice sounds wise but they are wrong. The advice might be sound if it was still 2015 but it is definitely the wrong advice now.

Young Western Pond Turtle
Turtles may be slow, but jQuery Migrate is not. This image is just over 200kB. It is over 8 times larger than the jQuery Migrate plugin in current WordPress.

First about the speed thing. The current Migrate Plugin is (minified) under 15kB. The version of the Migrate plugin in current WordPress is larger but is (minified) under 25kB. Typical (icons excluded) images on a web page are generally anywhere from 50kB to 200kB with some websites regularly using images up to 400kB. The file size of jQuery Migrate is not the problem on web sites that are slow to load.

The biggest reason why many web pages are slow is actually because of the gobs of eye candy third party resource, often related to advertisements that really do not care about the speed of your web page loading. Advertisements are bloated and very often the code use to bring in the advertisement to the page is extremely inefficient. That slows down a website far more than loading the jQuery Migrate plugin will.

The only reasonable time it is appropriate to specify jquery-core as the dependency for your jQuery script is when you know it will run with the current version of jQuery without any deprecation warnings. Otherwise specifying jquery as the script dependency is the right thing to do.

Some webmasters will update the version of jQuery that WordPress comes with. Some webmasters are required to do so because even though WordPress patches their archaic version of jQuery, it is no longer maintained by the vendor and therefore is not suitable in certain industries with higher site security requirements. Some webmasters are required to because they need to run jQuery scripts that need newer capabilities than what the jQuery in WordPress provides.

There is also a good possibility that WordPress Core itself will update the jQuery it ships with soon. If your script does not work in current jQuery or has deprecation warnings that indicate it will not work with a near future version of jQuery, then your plugin or theme could break for many users simply because you specified jquery-core rather than jquery as its dependency.

Having your plugin pull in the usually un-needed jQuery Migrate plugin on WordPress sites running the older version of jQuery when it is not needed is a small price to pay for your plugin or theme continuing to work with newer versions of jQuery specifically because your script does need the Migrate plugin with more recent versions of jQuery.

So, only specify jquery-core as the dependency if you are sure it works without even deprecation warnings in the current jQuery.

jQuery Migrate

The primary purpose of this plugin is to do what the name says, assist in migration of jQuery scripts to a newer version of jQuery that breaks the scripts.

When jQuery 1.9 was released, it removed some features that some scripts depended upon. The original Migrate plugin provided those features so that the scripts would still (most of the time) work when the jQuery library was updated. The ‘developer’ version (non-minified) specifically logs warnings when it is used so the developer has an easier time finding out what parts of their code needs to be ported. The ‘production’ version (minified) does not, it is intended for websites that need to still run the old code while a developer works on porting the old code and testing the fixes.

A bug fix updated version of this original Migrate plugin, originally released in 2013, is what is in WordPress. It provides backwards compatibility for code that does not work in jQuery 1.9.

The jQuery Migrate in WordPress I actually prefer to refer to as the jQuery Obsolete plugin because if your code needs it, your code is obsolete.

If you have code that still needs the version of jQuery Migrate in WordPress, that is code that has not been properly updated in seven years. Junk it, seriously. Or pay someone to fix it.

When jQuery 3 was released, again there were features that were dropped. A second Migrate plugin was created to allow code that properly worked in jQuery 1.9+ but no longer worked in jQuery 3.0+ to still work so it could be migrated to jQuery 3.0+ native.

Code that required features no longer present in jQuery 1.9, what the first Migrate plugin accommodated, simply will not work with the newer Migrate plugin.

The newer Migrate plugin does however allow code that works in jQuery 1.12.4 (version in current WordPress) to still work in the latest jQuery—provided that it did not require the older Migrate plugin.

This is migrate plugin you WANT pulled in by WordPress installs that have upgraded their version of jQuery.

As long as your plugin or theme code is not so obsolete that it requires the Migrate plugin with the version of jQuery in stock WordPress, it will probably work in WordPress installs that have upgraded jQuery—provided the Migrate plugin is pulled in.

In my Pipfrosch jQuery plugin, under the default plugin settings the Migrate plugin will still be pulled in even if your code specifies jquery-core as the dependency, but webmasters can disable that behavior and many of the jQuery upgrade plugins and solutions out there are not as kind as I am to plugin developers.

This is important. So I will repeat it. Unless you know for sure that your code works in current jQuery (3.5.1) and works without deprecation warnings, just specify jquery as the dependency so the Migrate plugin gets pulled in. The is the right thing to do.

Do not specify jquery-migrate as a dependency. If your code is so obsolete that it needs the older Migrate plugin it is broken. Note that some of the WordPress jQuery Upgrade plugins and advice out there do the absolute WRONG thing and unregister that script handle. Specifying that as a dependency will cause your plugin to fail even on installs using older jQuery where it would have worked, so only ever specify jquery as the dependency for your scripts.

Using jQuery UI in WordPress

This is a curated collection of jQuery plugins that make it much easier to code user interface elements. It is big. It is also, in my opinion, done incorrectly in WordPress Core.

The current version of jQuery UI (1.12.1) is about 250k in size. That is larger than most images but smaller than some. However when loading jQuery UI it is almost always loaded in the <head/> node and that makes it render blocking content, a web page will not start to render until it has fully downloaded.

There are two solutions to reduce the time it takes for the ‘First Meaningful Paint (FPM)’ when using jQuery UI.

  1. You can use a customized jQuery UI library that only has the features you specifically need.
  2. You can split up jQuery UI into a set of several smaller files and only include the specific features you need. This is what WordPress does.
  3. You can use a Public CDN increasing the odds that a user to your site already has the file in their browser cache.

The first solution is unfortunately the solution that the jQuery UI website seems to promote. It does result in a much smaller download but it means the custom library has to be recreated every time you add new code that uses a feature not covered by your current custom version. If you never change the website that may not be a problem, but for most websites it is a pain in the mikta (Aris Bock referenece). It also often means replacing the associated CSS file. This solution is not compatible with Public CDNs.

The second solution is what WordPress does. Each feature that can be separated out is separated out into its own separate file. This unfortunately results in any script that makes use of more than a few features having an extremely bloated requirements array. For example:

$my_script_deps = array('jquery-ui-accordion',
                        'jquery-ui-autocomplete',
                        'jquery-ui-datepicker',
                        'jquery-ui-progressbar',
                        'jquery-ui-sortable',
                        'jquery');
wp_enqueue_script('my-cool-script',
                  '/path/to/myscript.js',
                  $my_script_deps,
                  1.1.4);

That will result in each of those scripts, plus their dependency on jquery-ui-core, being added to your <head/> node.

Splitting the files up is also not compatible with Public CDN use.

The third solution is really in my opinion the best. Use the complete jQuery UI library, all 250k of it, regardless of how many features you actually use but have the file served from a Public CDN. Even if you pay for a private CDN service, use a public CDN for jQuery UI. A new user to your website is far more likely to already have the file cached if you use a Public CDN than if you use a private CDN.

To further increase the odds that a user to your site already has the file loaded in their case when needed, every page on a website that does not use jQuery UI should preload it. For example:

<!-- Pipfrosch jQuery Prefetch -->
<link rel="prefetch"
      href="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
      crossorigin="anonymous" />
<!-- End Pipfrosch jQuery Prefetch -->

What the above code does when in the <head/> node is it makes the browser aware that file very likely will be needed in the near future, download it when it is not busy downloading files for the current page. With a Public CDN like code.jquery.com there is already a good chance your users already have the file. The few that do not, it gets downloaded before it is needed so that when they come to a page on your website that does need it, the browser already has it.

The Pipfrosch jQuery UI plugin that I wrote does this for you. On pages that do not actually use jQuery UI it will add the tag that triggers browsers to perform the prefetch. At least browsers that support it, as of this feature is still not implemented in Safari even though it is not a new feature. All other major browsers have been onboard for some time now.

Some people are hesitant to use a CDN because websites can break if the CDN is down or if the user browsing the site is running a browser plugin like Privacy Badger that has been configured to block the CDN being used.

Both the Pipfrosch jQuery and Pipfrosch jQuery UI plugins have been coded to detect when a JavaScript library or CSS file from a CDN failed to load and will load the file locally in those cases, avoiding breakage. The fallback is very robust with JavaScript but the fallback for CSS may not work in older browsers that do not implement the onerror attribute in the context of a <link /> tag. I know both FireFox and Chromium do and I suspect Chrome and Edge Safari do as well but I have not personally tested with those browsers.

Theme developers that use jQuery UI in my not-so-humble opinion should require my jQuery UI plugin with their theme (see TGM Activation Plugin for how to do this). Plugin developers that use jQuery UI probably should not, but plugin developers who use jQuery UI can do something like the following:

if ( defined( 'PIPJQUI_PLUGIN_VERSION' ) ) {
  $my_script_deps = array('pipfrosch-jquery-ui-core', 'jquery');
} else {
  $my_script_deps = array('jquery-ui-accordion',
                          'jquery-ui-autocomplete',
                          'jquery-ui-datepicker',
                          'jquery-ui-progressbar',
                          'jquery-ui-sortable',
                          'jquery');
}

You can just do the latter as well and not the former, as with my plugin those dependency handles are turned into aliases of the pipfrosch-jquery-ui-core handle, but there may be reasons related to CSS for detecting if the WordPress install has my plugin active.

Notice that in those examples, I specified jquery as a dependency. That may seem redundant but it is not, it ensures the jQuery Migrate plugin is pulled in.

Even though it is many years old, jQuery UI 1.12.1 works with jQuery 3.5.1 with some deprecation warnings and based upon pull request activity on github, jQuery UI 1.13.x is imminent and is fixing those deprecation issues. As such, jQuery UI only depends upon jquery-core and will not pull in the Migrate plugin. If you know that your code works in jQuery 3.5.1 without deprecation warnings, then feel free not to specify jquery as a dependency when registering or enqueuing your scripts, but otherwise, you should have it.

jQuery UI and Themes

This is something WordPress Core really gets wrong.

The JavaScript library for jQuery UI modified the DOM. That is only part of what jQuery UI needs to properly function, it also needs CSS rules to be applied to the classes the library assigns to the elements.

WordPress does not even load a default theme when jQuery UI is used within WordPress. If you search through support forums, you will find a lot of people who have tried to get jQuery UI working in WordPress and their failure was lack of the needed CSS being implemented.

A design flaw in WordPress is that it does not allow registering a JavaScript with a CSS file dependency. Plugins that use jQuery UI then have to include a CSS file of their own and enqueue it.

That however can create visual clashes with WordPress themes and may be one of the reasons why jQuery UI is not used in WordPress plugins and WordPress themes as often as it could be, or dare I even say should be. It is a really nice collection of libraries.

The way that I solve this, all of so-called ‘standard’ that are distributed by jQuery are included and register. The Pipfrosch jQuery UI plugin has a style handle called jquery-ui-theme-active that is registered in WordPress as an alias to one of those standard themes. Which theme it is an alias for is a preference of the WordPress admin (I like “Trontastic”) but it defaults to the Base theme if none is selected.

When WordPress is creating a frontend page, it checks to see if jQuery UI is an enqueued script. If it is, it then makes sure the jquery-ui-theme-active alias is enqueued so that the jQuery UI theme the WordPress administrator has set to use as the default is in fact loaded.

If plugin developers code their plugin to detect when Pipfrosch jQuery UI is active, they can know that a theme that provides CSS for what is in jQuery UI will be loaded. Any additional CSS the plugin wants to override what is in a default theme should be enqueued in a CSS that registers jquery-ui-theme-active as a dependency so that the plugin specific CSS loads after the jQuery UI theme CSS

For compatibility with WordPress installs that do not have Pipfrosch jQuery UI active, plugins that use jQuery UI probably should include at least a basic CSS file that covers all the jQuery UI features the plugin uses.

WordPress Theme developers that use jQuery UI, I really do recommend you require Pipfrosch jQuery UI but of course that is your choice.

Some WordPress Theme developers very well may want to make their own jQuery Theme rather than use a standard jQuery Theme.

For WordPress Theme developers who want to override what the Pipfrosch jQuery UI plugin has set as the default theme with another standard theme that is included in Pipfrosch jQuery UI, the following code in your functions.php will do it:

function your_theme_stub_load_jqui_theme()
{
  if ( function_exists( 'pipjqui_load_alternate_theme' ) ) {
    $my_preferred_theme="Black Tie";
    pipjqui_load_alternate_theme( $my_preferred_theme );
  }
}
add_action( 'wp_enqueue_scripts', 'your_theme_stub_load_jqui_theme' );

The function pipjqui_load_alternate_theme() will recreate the jquery-ui-theme-active alias handle to point to whatever standard theme you specified. Obviously you can replace “Black Tie” with any standard jQuery UI theme name.

On the other hand if you want to load a custom jQuery UI Theme, the following code in your functions.php will do it:

function your_theme_stub_load_jqui_theme() {
  if ( function_exists( 'pipjqui_load_custom_theme' ) ) {
    $my_handle = 'my-theme-custom-jquery-ui-theme';
    $my_source = trailingslashit( get_template_directory_uri() ) . 'css/my_custom-jquery-ui.min.css';
    $my_dep = 'Le-Frog'; // for the jQuery UI Le-Frog theme
    pipjqui_load_custom_theme( $my_handle, $my_source, $my_dep );
  }
}
add_action( 'wp_enqueue_scripts', 'your_theme_stub_load_jqui_theme' );

The function pipjqui_load_custom_theme() is for loading custom jQuery UI themes in place of whatever is chosen as the default.

The first argument is the handle to use for your custom jQuery UI theme. The second is the path to the CSS file. The third, if your CSS just is overriding something in a standard jQuery UI theme, you can specify which jQuery UI theme should be loaded before your custom CSS. If your CSS simply requires any standard theme, then leave it null and the default will be used instead of a specified theme. If your CSS is a complete jQuery UI Theme, then pass an empty string as the third argument.

The Pipfrosch jQuery UI plugin will register your CSS with the specified dependency (or no dependencies if empty string is third argument) and will recreate the jquery-ui-theme-active alias handle to point to your custom theme.

This way, any pages that use jQuery UI will result in the custom jQuery UI Theme being enqueued.

In the above example, the standard jQuery UI theme “Le-Frog” is defined as a dependency of the custom CSS and would be loaded before the custom CSS.

WordPress Administrative Pages

To avoid possibly breaking WordPress, neither the Pipfrosch jQuery nor the Pipfrosch jQuery UI plugins will alter the version of jQuery, jQuery Migrate, or jQuery UI used on administrative pages.

Summary

WordPress administrators should be encouraged to install both Pipfrosch jQuery and Pipfrosch jQuery UI as plugins that patch their WordPress install to use modern jQuery and jQuery UI when needed.

WordPress administrators should be encouraged to enable the use of a Public CDN for the jQuery libraries and jQuery UI themes after installing the Pipfrosch jQuery and Pipfrosch jQuery UI plugins.

WordPress Plugin and Theme developers who have code that does not with the jQuery standard in WordPress unless the Migrate plugin standard in WordPress is loaded have broken code that will already fail on many WordPress sites and will fail on many more when WordPress Core finally gets around to updating their ancient jQuery. Those scripts are in desperate need of fixing.

Unless a script is known to work with current jQuery without deprecation warnings, it should not be registered with jquery-core as a dependency. Instead register it with jquery as a dependency.

Plugins that use jQuery UI should recommend Pipfrosch jQuery UI but in most cases probably should not require it, instead making sure a theme file is loaded if Pipfrosch jQuery UI is not installed and active.

Themes that use jQuery UI really should require Pipfrosch jQuery UI as a dependency, and themes that do not use jQuery UI may want to consider requiring Pipfrosch jQuery UI as a dependency for the sake of users that install plugins that use jQuery UI.

Plugin and Theme developers, whenever possible, should use the Settings API for Plugin and Theme administration. When they do need to create custom admin pages and those custom admin pages use jQuery UI, they must be written to use the jQuery UI that is part of WordPress.