WordPress – Load enqueued JavaScript in async or defer

Lately I have been working with WordPress, creating a complete website (even original theme) with it for my college capstone. Generally, things have been fair but there have been some things I have wanted to write a rant-y blog post about (but will not because I value my readers too much 🙂 ). One of those things is loading JavaScript into a site.

According to the documentation, wp_enqueue_script is “the recommended method of linking JavaScript to a WordPress generated page.” So as a good developer I have used this for loading my JavaScript. Aside from the rather crazy parameter order and defaults, I was quickly irked by the inability to load scripts asynchronously. After much searching though the WordPress docs and various programming sites, I came across the following article which uses a simple hash to denote async scripts, use the clean_url hook to filter all external URLs for JavaScript files (although file extensions are only hints) and add the async HTML attribute. However, the function was a bit too naive and limited for my taste (what if I wanted to defer a script?), so I wrote my own function using the basic idea of that snippet, which is the topic of this article. 🙂

I started by continuing to use wp_enqueue_script to load my JavaScript, but I denote how I want it loaded by appending #async or #defer to the URL, like so:

                  get_template_directory_uri() . '/js/script.min.js#async',
                  array(), false, true);

Then later after I hook into the wp_enqueue_scripts action, I filter clean_url using the following function in my functions.php file:

 * Load JavaScript in an async/defer manner.
 * @link {https://ikreativ.com/async-with-wordpress-enqueue/|Inspiration}
 * @link {http://wp.me/p1V5ge-24n|Blog post}
 * @returns {String} A <script> tag with the desired attribute applied.
function triangular_scripts_html5($url) {
  // Test for a JS file and extract the attribute
  if (!preg_match('/[.]js(?:[?]ver=.{5})?#(async|defer)$/', $url, $results)) {
    // This is not a JS file or should be loaded as-is
    return $url;

  // Generate the attribute
  $htmlAttr = "' " . $results[1] . "='" . $results[1];
  $url = str_replace('#' . $results[1], '', $url) . $htmlAttr;
  return $url;

Using a regex, this function checks if 1. we are looking at a JavaScript file and 2. if an appropriate attribute hash is present. If either of these cases fail, we return the URL as-is. Using the extracted attribute, we then amend the src URL to add the HTML attribute then give it back to WordPress to use when loading the page. The resulting HTML looks something like this (sans the spaces I had to add to prevent WordPress.com from stripping the markup and auto-linking :\ ):

< script type='text/javascript' src='http://localhost/wordpress/wp-content/themes/bornagain/js/script.min.js?ver=4.3.1' async='async' > < /script >

I confirmed this method worked using the Google Developers PageSpeed Insights tool (great tool, by the way) and fiddling with the attribute with it and the few other scripts and observing the resulting effect (page load time, layout changes, etc.). With all confirmed, I pushed to the site and watched as some loading time was shaved off the site!

I will add that while writing this post, I came across a WordPress-focused Stack Exchange answer which accomplishes the same thing by filtering only JavaScript URLs using the script_loader_tag hook. I did come across this hook in my initial searching but was unable to get it working. Now that I have a clear example showing how it used, I may rework the above function to use it instead, but for now I will stick to clean_url. 🙂

Now you know how to load your WordPress enqueued JavaScript in an async or deferred fashion! Go forth with your newfound knowledge and increase your site loading times! 😀