Defer JavaScript in WordPress – fixed

I was recently contacted by a past WordPress site client, desperate because they couldn’t create new posts or pages, and all of their media had gone! Why had the site broken? Was it something I did a couple of years ago coming back to bite me? Time to do some debugging.

I’ll cut a long story short, and say that I did all the usual things here – updated core, theme, and plugins, ran a security check to verify no compromised files, used the excellent Health Check & Troubleshooting plugin, all to no avail. My final, dreadful thought – has somebody made changes to my repository managed, custom child theme‽

Dear reader, even with **DO NOT EDIT** notices front and centre in the themes files, somebody had gone ahead and made edits to those files, and while they had fixed the issue on the front end, they had badly broken the admin.

“What was the issues that they fixed?” I hear you ask – Deferring loading of JavaScript to decrease the load time of pages. The method used to achieve this is a simple snippet which can be found on numerous sites with a simple search, is often coupled with a request or aim to “get a better GTMetrix score”, and almost every snippet presented is WRONG.

The fix was really quick to implement, and I’ll post the right way to implement the snippet, if that’s the way you want to go, at the end of this post. But first, a background on why it might be used, and what is wrong with it.

Why should you defer parsing of JavaScript?

When you visit a web page it loads top to bottom, parsing files as it goes. If it hits a JavaScript file the loading stops until that files is parsed, and any functions in it are run, before continuing to load the page. You may have seen mention of render blocking scripts in your dev tools, well that’s what this is.

To alleviate this issue, JavaScript files can be individually marked to make their loading deferred, that is, they won’t stop the page loading and will be processed after the page has loaded. This makes the page appear to load faster, though it can have some undesirable effects if a particular script is required to layout the page correctly.

How do you defer Javascript?

Simply by adding a defer attribute to the JavaScript file script tag. But with WordPress things aren’t so simple. I use WP Rocket cache plugin, which handles deferring for me. But this post is about a snippet, so let’s focus on that.

By hooking into the clean_url WordPress filter we are able to modify the URL that is passed through the filter function, and in this instance we close the URL string with a quote, and append defer to the string. It looks something like this:

function js_defer($url) {
    return "$url' defer ";
}

And with a few more conditionals in the function that is what is posted in the other places. So what’s wrong with what the others post? Simple, this filter runs everywhere – front end, admin, everywhere. So now we can see what the issue is going to be. Scripts on the admin side that are required to make admin functionality work as the page is loaded are being deferred, and so the admin breaks.

How do you defer parsing of JavaScript in WordPress using a filter without breaking admin?

Another simple fix, wrap the filter instantiation in a conditional to exclude admin pages. The fixed snippet is shown below:

function defer_parsing_of_js ( $url ) {
    // Don't do anything if it's not a JS file
    if ( FALSE === strpos( $url, '.js' ) ) return $url;
    // Don't touch jquery
    if ( strpos( $url, 'jquery.js' ) ) return $url;
    // return "$url' defer ";
    return "$url' defer ";
}
// Only run defer parsing on front end otherwise it breaks admin
if( !is_admin() ){
    add_filter( 'clean_url', 'defer_parsing_of_js', 11, 1 );
}

NOTE: as with any code sourced from the internet, before using it in your production website make sure you read and understand the code, and modify it as required to suit your particular requirements.

Leave a Reply

Your email address will not be published. Required fields are marked *