In this post, we’ll show you advanced website speed optimisation tips for WordPress. But before we nerd out, we should probably talk about the impact site speed can have on your SEO.

Google Search Console Speed Report

In November 2019, Google rolled out an update to Search Console. Instead of checking your pages individually using GT-metrix or Google Page Speed Insights, Big G decided to include a site wide page speed report.

wordpress website speed optimisation tips

This got me thinking, what if site speed plays a bigger role in rankings than we thought? In the past, Google publicly mentioned site speed was a ranking factor but any SEO will tell you, it’s a pretty weak one.

After this update, it’s possible site speed could play a bigger role for the future of rankings. Judging by the “Speed” section of Search Console, the two metrics Google cares about are First Content Paint and Time Input Delay.

What Is First Contentful Paint?

First Contentful paint or FCP is the time it takes for content to appear in front of the user’s screen.

From the second you enter the URL and click enter to the time it takes the user to see content above the fold, that’s the first contentful paint. Here’s how Google benchmarks FCP:

first contentful paint graphic
How Google Classifies Fast, Moderate and Slow URLs for FCP

What is First Input Delay?

Time input delay is the amount of time users wait until they can interact with your site (touch, click, scroll, etc.). According to Google, here’s how they benchmark it:

How Google Classifies Fast, Moderate and Slow URLs for FID

So how can we improve both FCP and FID? Google “website speed optimsation tips” and every blog will tell you the same thing: 

  • compress your images
  • combine CSS/JS
  • use a cache plugin

Yeah we get it. Rather than give you some basic solution that everyone covers, here are some advanced tips and tricks to take your site speed to the next level.

Tip #1: Eliminate Render Blocking Resources

First, what the heck is render blocking? Render blocking means downtime. It means the browser could be doing a million other things but instead it’s waiting for a resource to download.

Render Blocking JS

Render blocking javascript is actually pretty easy to fix. Script tags can use attributes called async.

By including an async tag attribute, you tell the browser to load the script file in the background instead of waiting. When the script file is done loading, then it will execute.

To make your script files async, use this code within your functions.php:

Render Blocking CSS

CSS files render block by nature. Your CSS files exist in the <head> section of your website HTML. If you want to remove render blocking, simply take your stylesheets and move them to the footer.

Problem solved, right? Ehh sort of.

We just eliminated render blocking CSS but since the stylesheet is in the footer, everytime someone visits your site, they’re going to see a white flash before the content loads. 

That’s less than ideal. So what’s the alternative?

You’ve got to get your hands dirty with some code and use in-line CSS styles. 

Inline CSS or Critical CSS is stylesheet code that’s only used for above the fold content.

When I said this post was going to get advance, I wasn’t kidding. We’re about to pull out all the stops and use some node JS.

Node JS has a module called minimalcss. This module uses a headless chrome browser to visit your webpage. Once the fake browser visits your page, it automatically rips all the CSS needed for above the fold content.

Here’s how to set it up and install it:

Next we have to run our script.

const minimalcss = require('minimalcss');
const fs = require('fs');

async function criticalCSS(url){

    return new Promise((resolve)=>{
        minimalcss
          .minimize({ urls: [url]})
          .then(result => {
            console.log('OUTPUT', result.finalCss.length, result.finalCss);
            return resolve(result.finalCss);
          })
          .catch(error => {
            console.error(`Failed the minimize CSS: ${error}`);
          });
    })
}

main();

async function main(){

    var urls = [
        'URL #1',
        'URL #2',
    ]

    for(let i=0;i<urls.length;i++){
        var css = await criticalCSS(urls[i]);
        await new Promise(function(resolve, reject) {
            fs.writeFile("page - " + i + '.txt', css, function(err) {
                if (err) reject(err);
                else resolve(css);
            });
        });
    }

}

main();

Time to Implement the txt file CSS code inside our wordpress functions.php:

//Inline Critical CSS & Async load CSS
function criticalCSS() {

global $wp_query;

if ( isset( $wp_query ) && (bool) $wp_query->is_posts_page ) {
//If It's the Blog Page, use this CSS
echo <<< EOT
<style>Blog Page CSS Here</style>
EOT;

echo <<<EOT
<link rel="preload" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style">
<noscript><link rel="stylesheet" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style"></noscript>
EOT;
}
elseif( comments_open() ) {
//If it's a Single Blog Post, use this CSS
echo <<<EOT
<style>Single Blog Post CSS Here</style>
EOT;

echo <<<EOT
<link rel="preload" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style">
<noscript><link rel="stylesheet" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style"></noscript>
EOT;
}

if( in_category('Your Category Name Here') ) {
echo <<<EOT
<link rel="preload" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style">
<noscript><link rel="stylesheet" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style"></noscript>
EOT;
} else{
echo <<<EOT
<link rel="preload" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style">
<noscript><link rel="stylesheet" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style"></noscript>
EOT;
}

}

elseif( is_front_page() ) {
//If it's the Home Page, use this CSS
echo <<< EOT
<style>Home Page CSS Here</style>
EOT;

echo <<<EOT
<link rel="preload" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style">
<noscript><link rel="stylesheet" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style"></noscript>
EOT;
}

elseif ( is_page( 'Your Custom Page' ) ) {
//If It's a Custom Page On Your Site, Use This CSS
echo <<< EOT
<style></style>
EOT;

echo <<<EOT
<link rel="preload" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style">
<noscript><link rel="stylesheet" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style"></noscript>
EOT;
}
else{
//Default CSS For All Other Pages
echo <<< EOT
<style>Default CSS Styles For All Other Pages</style>
EOT;

echo <<<EOT
<link rel="preload" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style">
<noscript><link rel="stylesheet" href="https://yourdomain.com/wp-content/themes/yourTheme/assets/css/style-main.min.css?ver=1.0.0" as="style"></noscript>
EOT;
}
}
add_action('wp_head', 'criticalCSS', 0);

Tip #2: Load CSS Asynchronously

CSS is synchronous by nature, meaning it blocks. So when your browser tries to load your website it stops everything it’s doing and waits for your CSS file to load.

To improve load time, we want the browser to continue working until the CSS is done loading in the background.

In order to trick the browser into loading CSS asynchronously, we have to use the media attribute and the on-load attribute.

Here’s the code you’ll need to implement in your functions.php:

function add_stylesheet_attributes( $html, $handle ) {
    if ( 'maincss' === $handle) {
        return str_replace( "rel='stylesheet'", "rel='stylesheet' media=\"print\" onload=\"this.media='all'\"", $html );
    }
    return $html;
}
add_filter( 'style_loader_tag', 'add_stylesheet_attributes', 10, 2 );

Essentially how this works is it intercepts your CSS stylesheets from the page HTML. It checks to see if ‘maincss’ is the id attribute.

If it matches, then it replaces “rel=stylesheet” with “rel=’stylesheet’ media=”print” onload=”this.media=’all’”.

Media=”print”

This tells the browser your CSS file isn’t for devices like phones, laptops, tablets, it’s only for printing from a web browser. So the browser will download the CSS file in the background but won’t apply it unless you try to print. This removes the blocking we mentioned earlier. 

onload=”this.media=’all’”

On load uses javascript to wait until page rendering is done. After rendering is complete, it switches the media attribute to all. This tells the browser the CSS stylesheet is for all devices (laptops, mobile phones, tablets etc.) so the browser applies the styles.

Tip #3: Speed Up DNS Lookup

What is DNS?

To understand DNS Lookup, we’ve gotta understand DNS. DNS stands for Domain Name Service.

Every website on the internet uses a domain but behind every domain is an IP address. When your browser needs to download information, it has to establish a connection through an IP address.

What is DNS Lookup?

In case it’s not obvious, it’s the time it takes for your browser to lookup the website domain name and figure out the IP address.

Why Is Your DNS Lookup So Slow?

Your DNS lookup time depends on your registrar. That means you’re at the mercy of GoDaddy, Namecheap, Bluehost or wherever you bought the domain.

Your browser asks the domain provider for the IP address registered to the domain name. They take their sweet time to return the address, which increases your TTFB (Time To First Byte).

How To Speed Up DNS Lookup For Free?

According to dnsperfs.com, Cloudflare has the fastest DNS lookup available on the internet. And the best part is, it’s absolutely free.

dns perf speed comparisons

Here’s how to set it up for your website:

Step 1) Sign up with Cloudflare

Step 2) Copy your domain name records

Step 3) Log into your domain provider and replace the new records.

Step 4) Go to the “” tab on Cloudflare.

Step 5) Click on each orange cloud.

Clicking on each orange cloud tells Cloudflare you only want to use them for DNS lookup.

Tip #4: DNS Prefetch

Your browser has to lookup not only your websites IP address but also every single external requests IP address.

So if you’re using Google Analytics, Tag Manager, Fonts, Hotjar, Gravatar or anything that is hosted externally, it significantly slows down the browser.

DNS prefetch let’s you lookup IP addresses asynchronously in the background so you can load external resources quicker.

Here’s the code to implement DNS Prefetch within your wordpress functions PHP:

//Prefetch DNS
function dns_prefetch() {
    echo '<meta http-equiv="x-dns-prefetch-control" content="on">
	<link rel="dns-prefetch" href="https://www.googletagmanager.com" />
	<link rel="preconnect" href="https://www.google-analytics.com" />
	<link rel="dns-prefetch" href="https://www.google-analytics.com" />
	<link rel="dns-prefetch" href="https://ajax.googleapis.com" />
	<link rel="dns-prefetch" href="https://secure.gravatar.com" />
	<link rel="preconnect" href="https://fonts.gstatic.com" />
	<link rel="dns-prefetch" href="https://fonts.gstatic.com" />
	<link rel="dns-prefetch" href="https://fonts.googleapis.com" />';
}
add_action('wp_head', 'dns_prefetch', 0);

If you don’t use any of those external requests, you can remove them or replace them with your own.

Tip #5: Load Plugin CSS In The Footer

Plugins add unnecessary CSS files that really kill page loading time, especially when they are included in the head section of your HTML.

To move plugin CSS to the footer, you need to figure out the handle of the plugin and then deregister it.

The handle of a plugin comes from the id attribute of the CSS file.

Here’s the code you can use in your wordpress functions PHP:

//Deregister CSS
add_action( 'wp_print_styles', 'deregister_my_styles', 1000 );

function deregister_my_styles() {
	wp_deregister_style( 'myplugin-main' );
}

After you deregister the style, you have to re-register it in the footer. Here’s the code to implement that change:

function prefix_add_footer_styles() {
    wp_enqueue_style( 'toc', WP_PLUGIN_URL . '/path-to-plugin-css/name-of-css-file.css' );
};
add_action( 'get_footer', 'prefix_add_footer_styles' );

Conclusion

I hope these tips were helpful. Page speed may not be the most important ranking factor but it does count. With Google including a page speed module section within Search Console, page speed could be weighted more in the future.

Thanks for stopping by. Feel free to drop us a comment if we bored you to death or if you have any questions.