How do I defer or async this WordPress javascript snippet to load lastly for faster page load times?

I have various javascripts that are necessary plugins in one of my WordPress domains, and I know where in the php file it’s called from.

I’m taking every measure I can take to speed up page loading times, and every speed tester on the web says to defer javascripts if possible.

Read More

I have read about the defer=’defer’ and the async functions in javascript and I think one of these will accomplish what I’m trying to accomplish. But I’m not understanding how I’d do so in a php file.

For instance, here is a snippet from one particular plugin’s php file where the javascript file is being called:

function add_dcsnt_scripts() {

    wp_enqueue_script( 'jquery' );
    wp_enqueue_script( 'dcsnt', dc_jqsocialtabs::get_plugin_directory() . '/js/jquery.social.media.tabs.1.7.1.min.js' );

}

I’ve read that it’s best to do something like this for faster page loading times:

<script defer async src="..."></script>

But I don’t know how to accomplish that within a php file. I want to do this with all of my javascript files.

How would I accomplish deferring or asyncing this javascript snippet to is loads last and speeds up page load times? What would be the ideal way to increase page load times across all browsers? Thanks for any guidance anybody can offer!

Related posts

Leave a Reply

10 comments

  1. Or more universal way:

    function add_async_forscript($url)
    {
        if (strpos($url, '#asyncload')===false)
            return $url;
        else if (is_admin())
            return str_replace('#asyncload', '', $url);
        else
            return str_replace('#asyncload', '', $url)."' async='async"; 
    }
    add_filter('clean_url', 'add_async_forscript', 11, 1);
    

    so you can add async to any script without code changes, just add #asyncload to script url as:

    wp_enqueue_script('dcsnt', '/js/jquery.social.media.tabs.1.7.1.min.js#asyncload' )
    
  2. Trying to keep things somewhat modular and all encompassing, the following approach dynamically chooses how to embed the tag with the async or defer attributes by just appending a small identifier to the $handle name:

    /**
    * Add async or defer attributes to script enqueues
    * @author Mike Kormendy
    * @param  String  $tag     The original enqueued <script src="...> tag
    * @param  String  $handle  The registered unique name of the script
    * @return String  $tag     The modified <script async|defer src="...> tag
    */
    // only on the front-end
    if(!is_admin()) {
        function add_asyncdefer_attribute($tag, $handle) {
            // if the unique handle/name of the registered script has 'async' in it
            if (strpos($handle, 'async') !== false) {
                // return the tag with the async attribute
                return str_replace( '<script ', '<script async ', $tag );
            }
            // if the unique handle/name of the registered script has 'defer' in it
            else if (strpos($handle, 'defer') !== false) {
                // return the tag with the defer attribute
                return str_replace( '<script ', '<script defer ', $tag );
            }
            // otherwise skip
            else {
                return $tag;
            }
        }
        add_filter('script_loader_tag', 'add_asyncdefer_attribute', 10, 2);
    }
    

    Example usage:

    function enqueue_my_scripts() {
    
        // script to load asynchronously
        wp_register_script('firstscript-async', '//www.domain.com/somescript.js', '', 2, false);
        wp_enqueue_script('firstscript-async');
    
        // script to be deferred
        wp_register_script('secondscript-defer', '//www.domain.com/otherscript.js', '', 2, false);
        wp_enqueue_script('secondscript-defer');
    
    
        // standard script embed
        wp_register_script('thirdscript', '//www.domain.com/anotherscript.js', '', 2, false);
        wp_enqueue_script('thirdscript');
    }
    add_action('wp_enqueue_scripts', 'enqueue_my_scripts', 9999);
    

    Outputs:

    <script async type='text/javascript' src='//www.domain.com/somescript.js'></script>
    <script defer type='text/javascript' src='//www.domain.com/otherscript.js'></script>
    <script type='text/javascript' src='//www.domain.com/anothercript.js'></script>
    

    Thanks to @MattKeys @crissoca for inspiring my answer here.

  3. This blog post links to two plugins of interest:

    Haven’t tested them but checked the code and they do pretty fancy stuff with WordPress scripts enqueuing process.

    But then WPSE comes to rescue:

    // Adapted from https://gist.github.com/toscho/1584783
    add_filter( 'clean_url', function( $url ) {
        if ( FALSE === strpos( $url, '.js' ) ) {
            // not our file
            return $url;
        }
        // Must be a ', not "!
        return "$url' defer='defer";
    }, 11, 1 );
    
  4. Another solution using a different filter, which can be used to target a specific script handle:

    function frontend_scripts()
    {
        wp_enqueue_script( 'my-unique-script-handle', 'path/to/my/script.js' );
    }
    add_action( 'wp_enqueue_scripts', 'frontend_script' );
    
    function make_script_async( $tag, $handle, $src )
    {
        if ( 'my-unique-script-handle' != $handle ) {
            return $tag;
        }
    
        return str_replace( '<script', '<script async', $tag );
    }
    add_filter( 'script_loader_tag', 'make_script_async', 10, 3 );
    
  5. A simplified method. Add to your functions.php file to make make JavaScript asynchronous in WordPress

    // Make JavaScript Asynchronous in WordPress
    add_filter( 'script_loader_tag', function ( $tag, $handle ) {    
        if( is_admin() ) {
            return $tag;
        }
        return str_replace( ' src', ' async src', $tag );
    }, 10, 2 );
    
  6. To gain control over which js files to defer and avoid conflicts you can append a variable to the url in the wp_register_script function like below.

    wp_register_script( 'menu', get_template_directory_uri() . '/js/script.js?defer', array('jquery'), '1.0', true );
    

    Then change the line:

    if ( FALSE === strpos( $url, '.js' ))
    

    To:

    if ( FALSE === strpos( $url, '.js?defer' ))
    

    The new filter looks like this.

    add_filter( 'clean_url', function( $url )
    {
        if ( FALSE === strpos( $url, '.js?defer' ) )
        { // not our file
        return $url;
        }
        // Must be a ', not "!
        return "$url' defer='defer";
    }, 11, 1 );
    
  7. Very little modification code Mike Kormendy, which allows you to add 2 attributes at once:

    // Async load
    function add_asyncdefer_attribute($tag, $handle)
    {
        $param = '';
        if ( strpos($handle, 'async') !== false ) $param = 'async ';
        if ( strpos($handle, 'defer') !== false ) $param .= 'defer ';
        if ( $param )
            return str_replace('<script ', '<script ' . $param, $tag);
        else
            return $tag;
    }
    

    Result:

    <script async defer type='text/javascript' src='#URL'></script>
    
  8. I believe it’s bad practice to defer/async WordPress jQuery. Better solution would be to exclude jQuery from the filter:

    if (!is_admin()) {
        add_filter( 'script_loader_tag', function ( $tag, $handle ) {    
            if ( strpos( $tag, "jquery.js" ) || strpos( $tag, "jquery-migrate.min.js") ) {
                return $tag;
            }
            return str_replace( ' src', ' async src', $tag );
        }, 10, 2 );
    }
    

    You can use defer instead of async

  9. Incorporate the async attribute to the scripts so that they are only loaded once the whole page is loaded

    <script type="text/javascript">
        function ngfbJavascript( d, s, id, url ) {
            var js, ngfb_js = d.getElementsByTagName( s )[0];
            if ( d.getElementById( id ) ) return;
            js = d.createElement( s );
            js.id = id;
            js.async = true;
            js.src = url;
            ngfb_js.parentNode.insertBefore( js, ngfb_js );
        };
    </script>
    

    Source:Here

  10. Something to add the clean_url filter solution, make sure to validate to use it only on the font-end maybe using if( ! is_admin() ){} popular plugins like ACF might give you a headache.

    Update

    Here is my modified version of the solution:

    if( ! is_admin() ){
      add_filter( 'clean_url', 'so_18944027_front_end_defer', 11, 1 );
      function so_18944027_front_end_defer( $url ) {
        if ( FALSE === strpos( $url, '.js' ) )
        { // not our file
            return $url;
        }
        // Must be a ', not "!
        return "$url' defer='defer";
      }
    }