Home Articles Dev Journal How to speed up WordPress and pass the Google Page Speed Test

How to speed up WordPress and pass the Google Page Speed Test


Updated: Feb 2021

In order to speed up your website, you need to do the following 10 things. This will not only help you pass the Google Page Speed test but also make your site load under 3 seconds and your scores will be very high with sites like Pingdom and WebPageTest. These are not hacks or tricks but simply real methods of actually speeding up your WordPress website.

Make sure you’re on a CDN

Content Delivery Networks are free and will greatly speed up your website. Cloud Flare is a good start and web host like SiteGround can get you setup in a few clicks.

Switch your site to HTTPS

You can see all the speed gains in this article.

Optimize all your images


When you’re slicing out images in Photoshop, XD or whatever program you’re building your live site from it’s important to optimize the images.

Photoshop has a really good export option called Save for Web and Devices. Open this up and play with the settings until you get the smallest file size but acceptable image quality.

If you have a ton of jpeg photos, jPegMini does a great job of greatly reducing the file size without losing any image quality.

You can also install a WordPress plugin called “Ewww Image Optimizer” that will go through your upload and theme files to cut down your image sizes.

Write all your CSS in one file

I still see developers doing it—creating separate CSS files for sections of their site. I understand it, but I abandoned that practice long ago after finding out that it slows download time because of multiple requests for each file. It’s much faster to download one file instead of multiple ones.

I’ve grown accustomed to just placing all my CSS for my theme in one file. It makes finding things easier too as there is only one file I have to open up to edit.

Enqueue your CSS and JS files

You shouldn’t hard code CSS link files or javascript into your theme. Enqueuing is the WordPress best practice. Here’s an example of this code in the functions.php file:

add_action( 'wp_enqueue_scripts', 'load_my_styles_scripts', 20 );
 function load_my_styles_scripts() {
     // Load my stylesheet
     wp_enqueue_style( 'child-styles', get_stylesheet_uri(), '', 1, 'screen' ); 

     // Load my javascripts
     wp_enqueue_script( 'jquery-addon', get_stylesheet_directory_uri() . '/js/jquery-addon.min.js',
     array('jquery'), '', true );

Load non-critical javascript in the foot of your website

As you can see in the last parameter where I loaded the Javascript file, it’s set to “true”. This means it will load this javascript file in the footer and not the header. Even if you manually add JS to your website’s theme for any reason, you should add it just before the closing </body> tag.

Many popular plugins have their own enqueue functions (like Gravity Forms) so don’t hesitate to use these and place them in the footer of your theme file as well, but test your scripts to make sure everything works. Depending on what type of Gravity Form and its features you embedded, it may require jQuery to load in the header.

Load jQuery from a CDN instead of locally

I know, people say “don’t do this; this could screw with a plugin.” But if you know your plugins don’t require the local jQuery shipped with WordPress to function properly, load the one from Google’s CDN. It’s most likely already cached and loaded by thousands of other sites and therefore will speed up your site.

The following is the code that disables the local jQuery only for the front-end and loads it in the footer. Please note that any other properly enqueued scripts that require jQuery will also load in the footer.

if( !is_admin()){
      wp_register_script('jquery', ("https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"), 
      false, '1.11.3', true);

Now of days, I just load the local version of jQuery in the header and take the performance hit because some plugins just need jQuery to load first. You have to test this to see if this works for you.

Copy Google Fonts’ CSS styles to you local stylesheet

Using Google Web Fonts is the best way to add custom fonts to your website, but their embedding options could slow down the rendering of your website. To eliminate this, just copy the CSS of Google font file found in the <link> file and paste it in your own theme CSS file. You can find the URL inside the link; it looks like:

<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i" rel="stylesheet">

Inline your CSS

I know I said you need to enqueue and place all your CSS in one external file, but all this will do is output the CSS file using the <link> tag which will be placed in the <head>. This is considered “render blocking” and Google will lower your score because of it. To fix this, use a plugin that will inline your CSS for you. In other words, it will move the external CSS inside a <style> tag and place it in the <head> of your website. I use a plugin called Autoptimize to do this, and it works great.

Minify your CSS and JS

You can minify your CSS and JS with the same plugin, but I’ve found that I’ve run into problems with javascript minification so I sometimes don’t use that option. Test for yourself in these cases. Minification will shred a few nanoseconds off.

Combine your javascript files

Using the same plugin, you can combine most of the javascript that your theme and plugins have enqueued into a few javascript files. If you’ve created multiple javascript files for your theme, considering adding them all to one file.

Defer Javascript source files

Defer means to refrain from loading the javascript until the page has finished loading. In basic HTML5 a deferred javascript looks like this:

<script type="text/javascript" src="/link-to-file.js" defer="defer"></script>

In WordPress, in order to defer enqueued javascript files both from plugins and the theme, we have to use a function. Open your functions.php and add the following:

function add_defer_attribute($tag, $handle) {

   function add_defer_attribute($tag, $handle) {  

   // add script handles to the array below   
   $scripts_to_defer = array( 
   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);

The highlighted names are the handles to the scripts you want to defer. Change those to handle names of your scripts. If you don’t the handle names of scripts that are being loaded by plugins, add the following code to your functions.php file.

add_action( 'wp_print_scripts', 'wsds_detect_enqueued_scripts' );

function wsds_detect_enqueued_scripts() { 
   global $wp_scripts; foreach( $wp_scripts->queue as $handle ) : echo $handle . ' | '; endforeach;

This will display all the handle names on the frontend of your website. Once you’ve copied them, remove or comment out the function as you don’t want that information displayed to the public.

Defer using a plugin

The same developers who made Autoptimize plugin also created a plugin called Async Javascript. Use this plugin to defer or async javascript without writing all the code above.

Leverage browser caching

Place the following code in your .htaccess file. This will leverage browser caching. When the user visits another page, the HTML, CSS, images, and JS will be loaded from their device locally instead of asking the server again, which increases speed.


<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 month"
ExpiresByType image/jpeg "access 1 month"
ExpiresByType image/gif "access 1 month"
ExpiresByType image/png "access 1 month"
ExpiresByType text/css "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month" 
ExpiresByType application/javascript "access 1 month" 
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType application/x-font-woff "access 1 month"
ExpiresByType application/x-font-ttf "access 1 month"
ExpiresByType application/x-font-opentype "access 1 month"
ExpiresByType image/x-icon "access 1 month"
ExpiresByType image/svg+xml "access 1 month"

## Or to handle all file types at once use the following: ##
<IfModule mod_expires.c>
   ExpiresActive On
   ExpiresDefault "access 1 month"

Enable GZIP compression on your Apache server

Place this under the above code in the same .htaccess file:

<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE 
"application/atom+xml" \ "application/javascript" \ "application/json" \ 
"application/ld+json" \ "application/manifest+json" \ "application/rdf+xml" \ 
"application/rss+xml" \ "application/schema+json" \ "application/vnd.geo+json" \ 
"application/vnd.ms-fontobject" \ "application/x-font-ttf" \ "application/x-javascript" \ 
"application/x-web-app-manifest+json" \ "application/xhtml+xml" \ "application/xml" \ 
"font/eot" \ "font/opentype" \ "image/bmp" \ "image/svg+xml" \ "image/vnd.microsoft.icon" \ 
"image/x-icon" \ "text/cache-manifest" \ "text/css" \ "text/html" \ "text/javascript" \ 
"text/plain" \ "text/vcard" \ "text/vnd.rim.location.xloc" \ "text/vtt" \ "text/x-component" \ 
"text/x-cross-domain-policy" \ "text/xml" 

Or, if your server is missing mod_deflate/mod_filter, open your php.ini file and add this line: zlib.output_compression = on

Cache your WordPress website

Finally, once all this is done, you should install a caching plugin. A caching plugin will get rid of the server response warning message. When your WP site is cached, it doesn’t have to go to the database to fetch information, all it has to do is serve a complete page from the cache; this cuts down on server processing which causes server slow down.

After you’ve done all your optimizations, check your website’s layout to make sure it looks good, the scripts are functioning properly, and then run it through Pingdom, WebPageTest and Google Page Speed Insights to see your score. it should be greatly improved!

If you’d like my help, email me at neal@nullnealchester.com