Did you know that one additional second in page load time costs Amazon 16 billion in yearly sales? Yes, that’s a b. And it’s a lot. While you’re probably nowhere near Amazon’s traffic, that doesn’t mean you should neglect your site’s performance - it applies to you as well, just on smaller scale, so why not speed up your WordPress, especially since it’s quite easy to do (unless you’re on a shared hosting, then you’re pretty much screwed).

In this tutorial, I’m going to show you one trick that will make your WordPress website blazingly fast and all it takes is one plugin and a line of nginx configuration.

Prerequisites

This article assumes you’re running a self hosted WordPress installation (we covered that in an earlier article) and your web server of choice is nginx. The last thing you’ll need is a plugin called WP Rocket, which is a premium plugin (i.e. not free), but trust me, it’s well worth it. It’s easy to set up (which we’re going to do here), comes with just a few settings (which is good, it means there’s no bloat), does only one thing and does it good.

Note: If you absolutely refuse to support the developers of this great plugin, this trick will also work with W3 Total Cache or WP Super Cache, but they come with too many options for my taste and are harder to configure properly.

Install WP Rocket

Once you’ve purchased WP Rocket, install it and if you followed our tutorials this far, chances are you’ll see some errors, like these:

WP Rocket Error Messages
WP Rocket Error Messages

In order to solve them, first create a file and paste the contents of the first error in, using this command (make sure you’re in the WordPress root directory):

$ nano wp-content/advanced-cache.php

Once done, you’ll still see the second error being present, so create a directory that it requires first:

$ mkdir wp-content/wp-rocket-config

Now, we need nginx to be able to write to that folder, so set a proper group ownership and permissions to it by entering these two commands:

$ chmod 775 wp-content/wp-rocket-config
$ sudo chown :www-data wp-content/wp-rocket-config

Lastly, you need to a cache directory which is where the magic will happen (I’ll explain it shortly). We also need to set proper permissions so the directory will be writable by nginx. Run the commands below to achieve that:

$ mkdir -p wp-content/cache/wp-rocket
$ chmod 775 wp-content/cache/wp-rocket
$ sudo chown :www-data wp-content/cache/wp-rocket

Refresh the plugin page and you should now be error free. Important: Reset permissions to 755 on the wp-rocket-config directory, otherwise you risk the security of your site:

$ chmod 755 wp-content/wp-rocket-config

The trick

Now that you have WP Rocket up and running, let me explain a bit what it’s doing. When you request a particular URL for the first time, it processes it normally, and while doing that, it also saves a copy of the HTML it generates into wp-content/cache directory. So the second time that particular page is visited, it just checks whether the HTML file already exists and serves it, bypassing most of WordPress’s core functionality (PHP processing, database queries).

While this solution already significantly improves the speed at which your server is responding with content, we can do one minor tweak to our nginx configuration that will push this behavior to the limit!

Open up nginx configuration file for the site (usually in /etc/nginx/sites-available/your-site.com) and add this code before any location block:

set $cache_uri $request_uri;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
  set $cache_uri 'null cache';
}
if ($query_string != "") {
  set $cache_uri 'null cache';
}

# Don't cache uris containing the following segments
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
  set $cache_uri 'null cache';
}

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
  set $cache_uri 'null cache';
}

location / {
  try_files /wp-content/cache/wp-rocket/$http_host/$cache_uri/index.html $uri/ /index.php?$args;
}

Once done, save the file, close the editor and restart nginx:

$ sudo service nginx restart

What this does

The code that we just added to nginx tries to fetch the file from the cache folder before contacting WordPress’s index.php. This means if the file exists, no php will be processed at all!. The rules in between exclude some scenarios where caching is undesired, for example when logged in.

What we did just now is turned WordPress into a static site generator! And don’t worry, if you update anything (like a post or a page) WP Rocket will automatically clear the cache (read: delete cached files) for you, so you don’t have to worry about serving outdated content to your visitors. Pretty neat, huh?

In order to try it out, visit your site with another browser (or log out, pages are not cached for logged in users) and you should see a caching comment all the way at the bottom of your source HTML.

Of course, there is more to WP Rocket (such as optimizing static files and preloading cache - one technique that makes a script load a particular page to pre-generate the cache file for said page), but I'll leave it up to you to experiment with it and discover your own best practices.

If you'd like a more complete nginx configuration of WP-Rocket, take a look at this Github repo

What about Apache?

Well if you're on Apache then you have to do even less work, because WP-Rocket already generates the necessary configuration and puts it into .htaccess file. Give it a try! :)

Caveats (and how to fix them)

Scientists say slow WordPress sites increase risk of a heart attack Click To Tweet

If you use any kind of plugin that requires PHP processing for every request, then this technique clearly isn’t going to work for you. But worry not, there are two possible solutions:

  • use client side processing with javascript
  • exclude particular pages from being cached (done in WP Rocket settings)

That’s all there is too it, pat yourself on the back for showing your visitors that you care and value their time.

In next week’s tutorial, we’re going to cover the last aspect of speed optimisation and that’s assets (static files like images, javascripts and stylesheets). Stay tuned!

PS: OF course if you have any trick up your sleeve, don’t be afraid to share it in the comments below.

Update 01.14.2015 - thanks to Chris Wallace for pointing out a missing piece of code.
Update 02.27.2015 - For more technical readers: Here's our codeable.io Nginx production configuration that uses this technique, just in a slightly different way.