Add Defer & Async Attributes to WordPress Scripts


WordPress developers often enqueue scripts incorrectly and sometimes it was done for a reason because WordPress didn’t have a simple way to add the new’ish async and defer attributes.

Since Version 4.1 a new filter was introduced that finally provides a simple way to add async/defer attributes without bastardizing the process.

apply_filters('script_loader_tag', string $tag, string $handle, string $src);


function add_async_attribute($tag, $handle) {
    if ( 'my-js-handle' !== $handle )
        return $tag;
    return str_replace( ' src', ' async="async" src', $tag );
add_filter('script_loader_tag', 'add_async_attribute', 10, 2);

If you want to use the “defer” attribute just replace async=”async” with defer=”defer”.

Add this to your “functions.php” or equivalent file such as custom.php for Thesis.

You will need to change the handle which will be the first parameter of the enqueue method.

wp_register_script('my-js-handle', $src, $deps, $ver, $in_footer);

How you choose which tag to use depends entirely on the nature of the script itself, and there are three possible choices.

  • Standard – This is without the async or defer attribute and is the standard behavior for your browser.
  • Deferred – This delays the execution of the script until the HTML parser has finished.
  • Asynchronous – This executes when the script is ready and doesn’t disrupt HTML parsing.

As always you should test any changes you make. If you find that you have errors associated with either attribute then just don’t use them for that particular script.

What if you want to add the async or defer tag to multiple scripts?

Updated: 25/08/2015

To add the async/defer tag to multiple scripts we need to create an array and then loop through that array and add the async/defer tag to each script.

Add either of these snippets to your themes “functions.php” or “custom.php” for Thesis 2 and edit the array to include your script handles.


function add_defer_attribute($tag, $handle) {
   // add script handles to the array below
   $scripts_to_defer = array('my-js-handle', 'another-handle');
   foreach($scripts_to_defer as $defer_script) {
      if ($defer_script === $handle) {
         return str_replace(' src', ' defer="defer" src', $tag);
   return $tag;
add_filter('script_loader_tag', 'add_defer_attribute', 10, 2);


function add_async_attribute($tag, $handle) {
   // add script handles to the array below
   $scripts_to_async = array('my-js-handle', 'another-handle');
   foreach($scripts_to_async as $async_script) {
      if ($async_script === $handle) {
         return str_replace(' src', ' async="async" src', $tag);
   return $tag;
add_filter('script_loader_tag', 'add_async_attribute', 10, 2);

Let me know if you have any questions below.


Matthew Horne

Matthew is a web developer from the United Kingdom who taught himself PHP and JavaScript and never looked back. If you would like to hire me, shoot me an email.

  • Michael Darmanin 28th August 2015, 2:06 pm Link Reply

    Cheers for going through the trouble of making this useful article. Saves me having to install a plugin.

    • Matthew Horne 29th August 2015, 4:35 am Link Reply

      NO problem man, saves me time too!

  • manny 15th September 2015, 2:53 am Link Reply

    very helpful. thank you!

  • Dave 22nd September 2015, 9:23 pm Link Reply

    Hey Matthew,

    Thanks for this. Very helpful.

    One question: Let’s say I have 2 or 3 scripts that I ALL want to load asynchronously. Are arrays supported, and could you help me with the proper syntax? — I’d like to avoid writing a new function for each and every script.

    • Matthew Horne 30th September 2015, 2:18 pm Link Reply

      Hi Dave, I believe you could use an array and a foreach loop within the add_defer_attribute function.

      I will update the post once i have tested it.

  • Brian 17th November 2015, 6:57 pm Link Reply

    Hey Matthew – Thanks for putting this together! Definitely echo Dave’s sentiment, if you can get this to work with an array for multiple scripts I’d really appreciate it!

  • TheBerry 15th January 2016, 6:04 pm Link Reply

    Thanks for this post. I have a similar question to Dave above. I tried this below but it only works on the first element in the array.

    //array of all functions that I want to be asynchronous
    $GLOBALS[‘script_array’] = [‘jquery-cookie’,’autoloadpost’];

    //add way to have async capabilities of script files
    add_filter(‘script_loader_tag’,’add_defer_attribute’, 10,2);

    function add_defer_attribute($tag,$handle){
    foreach ($GLOBALS[‘script_array’] as $individual_script) {
    echo “This is individual report script “,$individual_script;
    if($individual_script !== $handle){
    return $tag;
    return str_replace(‘src’, ‘async=”async” src’, $tag);

    • Matthew Horne 9th March 2016, 10:21 am Link Reply

      I have updated the post to include a method for adding the async attribute to multiple scripts.

      • Nathan 23rd August 2016, 11:35 pm Link Reply

        I’m still only seeing it work in the first item in the array, too?

        • Matthew Horne 25th August 2016, 4:31 am Link Reply

          just updated it, should work now.

  • newbee 1st February 2016, 8:50 am Link Reply

    Hey Matthew ,
    I am not understanding how to use this code you mentioned,Can Please elaborate , ( I am sure there must be many like me out there 🙂 ), GTmetrics given me below warning

    236.4KiB of JavaScript is parsed during initial page load. Defer parsing JavaScript to reduce blocking of page rendering.

    what should I do ?

    • Matthew Horne 9th March 2016, 10:11 am Link Reply

      Not all scripts will be able to take advantage of async and defer tags. jQuery is one of them because too many scripts rely on it and not all developers properly enqueue scripts.

      Other scripts that might not benefit are adverts.

  • Ibrahim 18th March 2016, 3:05 pm Link Reply

    How do I apply both async AND defer for a single script?

    • Josh 3rd June 2016, 5:10 pm Link Reply

      You would not want to do this. Both do the same thing with one minor difference. Async will continue to parse and load the js file when it is done downloading. This means if you have multiple js files with async, they potentially can get loaded in a different order.
      Async Example – If file B finishes before file A it will get executed before file A. (This can be bad if B was dependent on code found in A).

      Defer corrects this. It still behaves like async but preserves the order.
      Defer Example – If file B finsihes downloading before file A it won’t get read/executed until file A has finished downloading, being read, and being executed.

      I simplified a tiny bit. Read more here

    • Josh Habdas 15th April 2017, 6:56 pm Link Reply

      You actually may want to do this. According to the specs it’s up to the browser to determine how best to load an asset when both async and defer are supplied. If you’re supporting legacy versions of Internet Explorer they will defer the script to prevent blocking behavior and, for more modern browsers, they will load the script asynchronously. Try it!

  • Geno 26th March 2016, 3:21 pm Link Reply

    First, thank you for this script! It seems to work with the javascripts that are in the wp-includes/js directory, but if they are not in that directory, the script doesn’t work. Do I use relative paths with wp-includes/js as starting directory?

    Thanks in advance for your answer.

    • Matthew Horne 28th March 2016, 3:49 am Link Reply

      As long as you enqueue a script correctly eg. wp_register_script(‘my-js-handle’, ‘/path/to/my/script.js’, $deps, $ver, $in_footer);

      Then script.js would be added the to the array of scrips to add the async attribute to.

  • Piotr 12th May 2016, 10:16 pm Link Reply

    For multiple scripts, instead of iterating use in_array function, much cleaner solution.

    • Matthew Horne 15th May 2016, 3:50 am Link Reply

      Good point.

  • INDOMASCOT 16th June 2016, 6:55 pm Link Reply

    Thanks friend,
    I follow your tutorial it to show google badge onto my website sidebar.
    And it works!


  • Asher Gomez 18th August 2016, 10:46 am Link Reply

    The multiscript version doesn’t seem to work on wordpress 4.6

    • Matthew Horne 25th August 2016, 4:01 am Link Reply

      I am going to do some testing now and see what the issue is.

  • Nilesh 23rd August 2016, 7:58 am Link Reply

    For multiple script it is not working for me. It is adding defer tag only for the first element of the array.

    • Matthew Horne 25th August 2016, 4:01 am Link Reply

      Ok, I will do some testing and see what is going on.

    • Pranab 16th January 2018, 10:52 am Link Reply

      Multiple script code array not automatically capture all .js files here, u have to manually put every js files enqueue name in that array, and then it will show defer or async only those .js files. That’s problem.

      • Matthew Horne 18th January 2018, 12:19 pm Link Reply

        The problem with adding all scripts by default is that you will almost certainly break your sites JS. That is because many scripts have dependencies and they must run first before the other script can run, defering or making scripts async can break this.

  • Venkatesh Bandari 27th September 2016, 10:07 am Link Reply

    Hi Sir, I site is not loading async script Ex. google adsense ads. By adding this code on my site will that ads get show up, and where i need to ad this code in my site. Please guide me.

    • Matthew Horne 29th September 2016, 2:57 am Link Reply

      Google adsense already has an async option when you configure your ads.

  • Dominic 5th October 2016, 7:48 am Link Reply

    Thanks for this post. Long time reader here 🙂 . Many people do not have an idea that there is no need to use plugins for this 🙂

  • Anh Tran 14th October 2016, 3:48 am Link Reply

    Nice technique. Just implemented on my website and it works nicely!

    Thanks for sharing.

  • Roee 23rd November 2016, 7:57 pm Link Reply

    Very nice technique ! i’ll use it 🙂

  • Michael 29th November 2016, 4:47 pm Link Reply

    I am a newbe. What should ‘my-js-handle’ be replaced with?

    • Matthew Horne 3rd December 2016, 3:05 am Link Reply

      Hi Michael,

      developers should always register their scripts as follows:

      wp_register_script('my-js-handle', $src, $deps, $ver, $in_footer);

      so you would replace my-js-handle with whatever the scripts registered handle is, the handle is just a unique identifier.

  • vinoth 20th December 2016, 4:54 pm Link Reply

    Awesome man, Worked like charm!.

  • Josh Habdas 15th April 2017, 4:28 pm Link Reply

    How does this differ from the universal method proposed on StackOverflow in ’13?

  • Josh Habdas 15th April 2017, 5:29 pm Link Reply

    Never mind. I see it now. Would be nice to pay homage to the bastardization approach as it likely paved the way for the filtering stuff (and is quite clever IMHO). You can delete or keep these comments.

  • Josh Habdas 16th April 2017, 6:58 am Link Reply

    Here’s what I ended up doing to tackle the jQuery performance issue:

  • Chris 7th May 2017, 9:14 pm Link Reply

    Doesn’t seem to work for me in 4.7.4. I just get a white screen when I try implementing the scripts to defer multiple scripts.

    • Matthew Horne 8th May 2017, 11:46 am Link Reply

      Can you paste your code here?

  • gary 24th May 2017, 5:19 pm Link Reply

    Getting undefined jquery error after adding above code in wordpress.It adds the async and defer to the script but getting undefined js errors

    • Matthew Horne 27th May 2017, 10:23 am Link Reply

      Hi Gary,

      do you have a link to the site? I can see what might be going on. I suspect you might have loaded a file that depends on jQuery asynchronously which can sometimes cause issues.

  • Stephen 8th August 2017, 11:44 am Link Reply

    src=’′ defer
    rather than
    src=’′ defer=”defer”

    • Matthew Horne 8th August 2017, 3:28 pm Link Reply

      Yes just change async to defer and it will work the same way.

  • Lewis S 21st November 2017, 1:45 pm Link Reply

    Great article! Glad I didn’t have to install a plugin to add async 🙂

  • mbahjadol 28th December 2017, 7:24 am Link Reply

    Wow many thanks, it is very simple, now some my script is load in async without use any plugin.

  • Jonas 21st March 2018, 12:21 pm Link Reply

    Simple and easy way to do it, well done.

  • Kirill 23rd March 2018, 9:14 am Link Reply

    Thankkssss so much

  • Ricardo Lima Gonçalves 9th May 2018, 7:53 pm Link Reply

    Great post! Thanks for sharing it…
    I just want to add a note here… Instead of using foreach loop, I’m using in_array() for multiples scripts. I’ve made a gist with my final code, take a look:

  • Andrés 28th November 2018, 12:45 am Link Reply

    An excellent post. One more step for the tedious task of web optimization. Thank you.

  • sagive 8th March 2019, 8:46 pm Link Reply

    A tutorial without an indication of when it was published is misleading and might cause serious waste of time don’t you think?

    • Matthew Horne 2nd June 2019, 9:54 am Link Reply

      You’re right, I have added the updated and posted dates.

  • MakeOnlineShops 4th April 2019, 8:42 pm Link Reply

    hello, is there a plugin that can do that ? or we really need to use the code ?


    • Matthew Horne 19th May 2019, 7:26 pm Link Reply

      There are probably plugins that can do it, but I prefer to include it in my code.

  • Alex 5th May 2019, 8:37 pm Link Reply

    Very nice solution, I hope that there will be a better way of adding attributes to scripts in future versions of WordPress. Seems like it is almost a need.

  • Damir 14th June 2019, 9:13 am Link Reply

    Hey Matthew,

    thanks for this article, is it still a good way to solve this issue or are there some better ways today?
    Another question is.
    Is this line hard coded?

    // add script handles to the array below
    $scripts_to_async = array(‘my-js-handle’, ‘another-handle’);

    I mean, do I need to find all of my script handles and put the manually in here? Thanks in advance

    • Matthew Horne 15th June 2019, 5:18 pm Link Reply

      The script handles are the unique identifiers for your scripts.

      When you enqueue a script in wordpress, the first parameter is the handle.

Leave a Comment