WordPress
Article

Including JavaScript in Plugins or Themes, the Right Way

By Jérémy Heleine

At the time of writing, more than 33,000 plugins and 2,600 themes are available on WordPress.org, and we can probably add more which are not present on this platform. They can do a lot of different things and, often, they use JavaScript to provide some features.

JavaScript and WordPress

Basically, including JavaScript code into a theme or a plugin is not difficult: what WordPress produces is nothing else than HTML so using the script tag with code directly into it or into a file linked thanks to the src attribute might be enough – if you were alone, developing in isolation.

The fact is you are not alone. People using WordPress can install plugins or themes next to yours, and the developers of these tools can also use JavaScript. Moreover, WordPress itself is using JavaScript. The problem is, if everyone includes their scripts without attention, the resulting page will be unnecessarily heavy.

The Problem

An example will be clearer, and I will take one that I know well: mine.

I developed the WP Photo Sphere plugin which allows users to add panoramas into their posts. To do that, I needed different JavaScript files: the library used to display this panoramas and the file that retrieves specific tags where panoramas are displayed. Moreover, in this last script, I use jQuery, so I need to include it.

If I did not care about users, I could insert these three scripts into all the pages of the websites which means visitors will have to download these files, even if the page does not need it.

At this time, the problem is already significant, but it becomes even bigger when we think about jQuery. What if two plugins using this library have this behavior? Not only will users download a useless file, but they will also download it twice!

The heavier a page is, the longer it will take to load. Websites that are too long to load are visited less than faster websites. If your plugin or theme makes the time of loading too long, they won’t be used. That is surely is a great motivation to optimize your tools, right?

The Inevitable Function to Insert Scripts

To avoid the problem of inserting the same file twice or more, WordPress provides us a great function: wp_enqueue_script(). When you want to insert a script, this function must become your best friend.

As its name suggests it, this function will add your scripts to a queue and include them at the right moment, into the header or into the footer, so no script tag will be added at the middle of the page.

Used alone, the wp_enqueue_script() function requires at least two parameters: the name of the script and the URL to it. For example, if I want to include a script needed by my plugin, I add this line into its main file (we will see proper ways to do that below).

wp_enqueue_script('test', plugin_dir_url(__FILE__) . 'test.js');

However, three additional parameters let you have more control on the way your script will be included, especially the last parameter which is a boolean: by default, this boolean is set to false and your script will be included in the head tag, but if you set it to true, then your script will be included in the footer.

The fourth parameter is useful if you make various versions of your script: it is a string containing the version number which will be concatenated to the end of the URL. Adding a version number ensures that visitors will get the right version of your script, regardless of caching.

The third parameter is one of the most interesting because it lets you indicate dependencies for your script. For example, if your script needs the library jQuery, you can use this parameter.

wp_enqueue_script('test', plugin_dir_url(__FILE__) . 'test.js', array('jquery'));

As you can see, dependencies must be indicated into an array, even if there is only one dependency. The name you indicate into this array is the name of a script registered thanks to a second function: wp_register_script().

The use of this second function is exactly the same as the use of the first: you indicate the name of the script, its URL, its dependencies, its version number and whether it must be included into the footer or not. The last three parameters are optional but the others are required.

wp_register_script('test', plugin_dir_url(__FILE__) . 'test.js', array('jquery'), '1.0', true);

Register a script will not include it. You still have to use the wp_enqueue_script() function to include your scripts, but its use is then simplified: you only have to indicate the name of the script.

wp_enqueue_script('test');

Maybe you are asking yourself about the usefulness of the wp_register_script() as the wp_enqueue_script() can do all the job. This function is here to indicate the way a script should be included but does not include it if it is not necessary.

An example will be clearer, so imagine that you have two JavaScript files to include. The first file is a library, and the second file uses this library to do some things. The library needs jQuery to work properly, so we register it as follows:

wp_register_script('mylib', plugin_dir_url(__FILE__) . 'lib/mylib.js', array('jquery'));

At this time, the library is not included, but if we want to include the main file, then we need to include this library: we indicate it as a dependency.

wp_enqueue_script('myfile', plugin_dir_url(__FILE__) . 'myfile.js', array('mylib'));

And all the magic appears. The myfile.js file is included, but it needs the mylib.js file to work: that’s the job of the dependency which will include this file. But! The mylib.js file needs jQuery, so jQuery is included too. Three files included in one line.

But that’s not the only advantage of the wp_register_script() function: if you register your scripts, other plugins will be able to use it. So if you want to make various plugins, with one which defines some libraries, the others will be able to include them.

The biggest advantage of the wp_enqueue_script() function is that it won’t include the same script twice. For example, imagine that two files need jQuery: this files indicate it as a dependency and WordPress will include the library when the first file is included. Then the time to include the second script is here. WordPress sees jQuery as a dependency, but the library is already included, so including it again is not needed: WordPress won’t do that.

The same behavior appears when you try to enqueue two scripts with different names but with the same URL. In the below example, WordPress will include the file once.

wp_enqueue_script('myfile', plugin_dir_url(__FILE__) . 'myfile.js', array('mylib'));
wp_enqueue_script('myotherfile', plugin_dir_url(__FILE__) . 'myfile.js');

However, be careful: this behavior is limited: if you indicate a version number in at least one wp_enqueue_script() call, the script will be included twice, even if this version number is the same. The below example seems to be the same as the previous one, but it will include the file twice.

wp_enqueue_script('myfile', plugin_dir_url(__FILE__) . 'myfile.js', array('mylib'), '1.0');
wp_enqueue_script('myotherfile', plugin_dir_url(__FILE__) . 'myfile.js', array(), '1.0');

That said, in general, you haven’t any reason to enqueue one script with different names. But it was necessary to clarify this case.

As you can see, this two functions are the best way to manage dependencies: you register them and WordPress will care of the rest, automatically.

Note that we used the name “jquery” to indicate that we want to include jQuery with our own files, but we did not register it. This name is already registered by WordPress: when you download the CMS, it contains jQuery.

This library is not the only one: you can find all the scripts registered by WordPress in this page. You can enqueue them directly or via a dependency, and the cool thing is that you haven’t to provide the files, so every plugin or theme which uses this scripts will use the same files: in our example, if another plugin uses jQuery, the library will only be included once.

Do Not Enqueue Your Scripts Everywhere!

The wp_enqueue_script() function ensures that a script is not included twice and includes it properly in the header or in the footer. But what if the displayed page does not even need your script?

Use the Action/Filter API

Take the example of adding a media button to the content editor: the JavaScript file is only needed when the user is on the editor. In fact, when an average visitor is reading an article, they don’t need this script: including it is useless and make the page heavier.

That’s why, when you want to include a script into a page, ask yourself the following question: when is this script needed? Of course, the answer to this question will be different depending on what your script does.

But once you find this answer, try to find a corresponding action. The WordPress Codex provides us a list of available actions, so you can find the one you search at this place. Found it? Great, create a new function which will enqueue your script(s), in the main file of your plugin or in the functions.php file or your theme for example.

function enqueue_my_scripts() {
    wp_enqueue_script('script0', plugin_dir_url(__FILE__) . 'lib/myscript.js', array('jquery'));
    wp_enqueue_script('script1', plugin_dir_url(__FILE__) . 'another-script.js');
}

Then, make it run when your action is triggered:

add_action('the_right_action', 'enqueue_my_scripts');

For example, when we wanted to add a media button, we used the wp_enqueue_media action, which was perfect:

add_action('wp_enqueue_media', 'include_media_button_js_file');

If you tried to search this action in the reference linked above, you probably found nothing: at the time or writing this lines, wp_enqueue_media is not listed. This list is not exhaustive, but it is a good place to begin with.

If you don’t find the right action, maybe you can find another which has a close behavior, or maybe you should try to search in the filters instead.

Use the Power of WordPress’ Functions!

Often, plugins are made for a specific reason, one that cannot use the Action/Filter API, or not completely. For instance, a plugin can modify some elements into a post, but not in all of them: shortcodes are a typical example of this.

Assume that your plugin needs some scripts used by the code which replaces a shortcode. There is no action or filter which will precisely target your shortcode. But there is a place where you can be sure that your shortcode has been found, where you can be sure that your scripts are needed.

This place is the callback function called by WordPress each time your shortcode is found. Call wp_enqueue_script() into this callback function and your scripts won’t be included unless there are needed.

But, what if your shortcode has been found twice or more? The answer is simple: nothing.

In fact, try to call the wp_enqueue_script() function twice, with the same script: this script will only be included once, and that’s why this function is a very good tool.

So you can insert this call into your callback function or into every other part of your plugin or theme where you can be sure that your scripts are needed: even if they are needed several times, they will only be included once.

Note that, depending on the place where your wp_enqueue_script() call is done, it can be too late to ask WordPress to include them into the head tag: your only choice will be the footer. If your script must be in the head tag for an obscure reason, think about it.

Maybe you have a question now: when is it too late?

Every theme must use two specific functions: wp_head() and wp_footer(). When the former is called, WordPress will add automatically all the lines needed in the head tag: if you asked for the inclusion of your scripts in the head tag, they will be included when wp_head() is called, so if you ask this inclusion after the wp_head() call, your scripts won’t be included in the head tag.

But WordPress is smart, and your scripts will still be included: you will be able to retrieve them in the footer, when the wp_footer() function is called and when the scripts which must be included at this place are included.

So you have your answer: if you absolutely want to include your script in the head tag, ask for the inclusion before the wp_head() call which should be at the end of the head tag in the theme. The wp_footer() call should be at the very end of the document, before the end of the body tag.

Conclusion

Your scripts are useful for what your plugin or theme does in a specific place, but including them into pages where they are not needed will make this same pages unnecessarily heavier.

WordPress provides us with several tools to let us include our scripts properly, only when they are needed. The only question to ask when you want to use these tools is the following: when or where are my scripts needed? The rest depends on the answer: finding an action or a filter, placing the wp_enqueue_script() call into the right function, using the power of this function, or combining all of that.

You can retrieve some examples described above in a test plugin available right here. It enqueues a script and a ‘library’, and it creates a shortcode using another useless script.

  • Oscar Blank

    Plugins that load assets on pages, posts, and archives that don’t need them always make me mad. A lot of paid plugins even do this. WordPress is so bloated without making it worse. Please always consider this!

  • https://imaginarymedia.com.au ImaginaryMedia

    Even major plugins, such as Jetpack, insist on loading JS assets in the head. It seems you have to deregister, then enqueue the WP version of jQuery to force loading in the footer. Worse, many plugins include their own versions of common libraries that are already shipping with WordPress. I’d argue that plugins should always use the WordPress asset and only include a single, custom JS file that is properly minified. Oh, and while I’m grousing about WP and JS, it would be nice if they output more simple script tags without the type attribute and allow a flag for async and defer…

  • http://nyasro.com/ Nyasro

    Nice one and I am currently working on WordPress plugin.

  • StudioK

    Good article. I was only recently scratching the surface of enqueueing scripts for a child theme but only for specific post type, as you don’t want scripts to load everywhere. Came across the following code which seems to work well (in functions.php) in restricting the script for your chosen post type:

    function mycustom_scripts_method() {
    global $wp_query;
    if ( "custom_post_type" == get_post_type() ) {
    wp_enqueue_script(
    'custom-script',
    get_stylesheet_directory_uri() . '/js/custom-jquery-script.js',
    array( 'jquery' )

    );
    }
    }

    add_action( 'wp_enqueue_scripts', 'mycustom_scripts_method' );

  • http://ladybuginfo.com/ Pranab Mitra

    Hi, Jeremy, very well described indeed.

    I am working on a
    Wordpress site. My client asked me to put a Google Map in one of the
    page to show their office locations. I am using the GMap JavaScript API.
    What I have a done, I have modified the header.php of the theme to
    insert a tag to invoke the GMap JS API. I put a condition
    to ascertain if it is the right page to do so.

    Is it a right approach or should I modify the theme functions to enqueue the script ?

  • http://ChiefAlchemist.com/ Mark Simchock

    Good stuff.

    It might also be a great time to mention wp_localize_script()

    http://codex.wordpress.org/Function_Reference/wp_localize_script

  • bassels

    Great article thanks Jeremy
    I was wondering and i don’t know if any one knows the answer

    if you have 2 script files and each of theme is related to a certain action ( lets say each one is related to a shortcodes ) when the shortcodes is called then each one is called accordingly.

    the issue is if you call shortcode1 at the same page with shortcode2 it is working, but if you call shortcode2 and then shortcode1 then the scripts is broken and none of the shortcodes working.

    do i have to change the script files to be able to work either way or i have a solution in WordPress for issue like this.
    regards

  • onexdata

    Please stop using so much fluff in articles and be direct… if you waste 10 minutes of the readers time and 4.2 million people read your article, you’ve just killed someone. Stop murdering people.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Instant Website Review

Use Woorank to analyze and optimize your website to improve your website to improve your ranking!

Run a review to see how your site can improve across 70+ metrics!

Get the latest in WordPress, once a week, for free.