George Garside Blog

A place of many ramblings about macOS and development. If you find something useful on here, it's probably an accident.

Adding Cloudflare in front of a WordPress site can help with slow load times. I've seen improvements of 10x regularly just with Cloudflare's default cache settings. However, we can go further!

By default, Cloudflare only caches static content like pictures. WordPress doesn't add Cache-Control headers to pages on the public site and CloudFlare doesn't cache HTML by default, so every request made to your orange-cloud site will still go to your origin.

WordPress can take a while to generate a response. Various plugins can cache the output produced by WordPress, like WP Super Cache, but the request still has to go to your origin, through PHP (by default), and return the cached HTML.

Cache-Control can be configured to cache your HTML on Cloudflare's proxy, drastically speeding up your site.

Set up the page rule

  1. Go to your Cloudflare dashboard, open your zone, and choose Page Rules at the top.
  2. Create a new page rule for ‘*’ or equivalent. I use* to apply to every page under my domain name.
  3. Set ‘Cache Level’ to ‘Cache Everything’. This will allow Cloudflare to cache pages that don't match the strict list of file extensions that would otherwise exclude HTML responses.
  4. Set ‘Origin Cache Control’ to On. Cloudflare will pass on the Cache-Control header it receives from the origin server to the client.
Cloudflare Page Rule to Cache Everything

Set up the Cache-Control headers

  1. Create a blank WordPress plugin. If you've never done this before, there's a Getting Started guide on WordPress Developer Plugin Handbook at All you need to do is…
    1. Create a new folder in wp-content/plugins/your-plugin-name choosing a unique name for your plugin.
    2. Add a functions.php file within the new folder you created, with the following contents at the top of the file:
       * Plugin Name: Your Plugin Name
  2. In functions.php, add a new action to the template_redirect hook. This hook is only called on pages that load a WordPress template.

This action calls header to add a new Cache-Control header to the response. The response should only be cached when not logged in, to avoid caching any content which is private to the user.

add_action('template_redirect', 'g_cache_control');
function g_cache_control() {
	if (!is_user_logged_in()) {
		header('Cache-Control: public, max-age=600, s-maxage=604800, stale-while-revalidate=86400, stale-if-error=604800');
}Code language: PHP (php)

if (!is_user_logged_in()) makes sure the header is only added for anonymous users. WordPress adds its own admin area Cache-Control header, so we only need to add the Cache-Control header outside the admin area. is_admin() could have been used instead, but personally I prefer caching for anonymous users.

The Cache-Control header has numerous components that tell both browsers and Cloudflare how to cache the content.

Set up the .htaccess resource caching

Finally, many resources can be cached for much longer by both browsers and Cloudflare.

Resources on this site can be ‘detected’ in htaccess by file extension. FilesMatch takes a regex, which in this example matches a list of file extensions.

<FilesMatch "\.(ico|pdf|jpg|jpeg|png|gif|jp2|webp|css|js)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>Code language: HTML, XML (xml)

In this case, these file extensions refer to static resources that will never change. For CSS and JS, updates are released with a new version in the query string, so the resource can be cached ‘forever’ as versions will be cached independently.

Leave a Reply

No comments