Documentation Caching

Caching

Overview #

Site speed is essential to a great web experience. WordPress.com employs multiple levels of caching automatically.

  • Full page cache: using the Batcache plugin, this caches full pageviews for a period of 5 minutes for all logged-out users
  • CDN / front-end caching: all scripts and stylesheets are served from our CDN. Images are served from our dedicated *.files.wordpress.com domain.
  • Object cache: using memcached, this provides a persistent backend for WordPress’ built-in Object cache and is used for storing transient data and short-lived data that needs to persist across page loads.
  • Advanced Post Cache: Caches WP_Query calls to minimize database queries.

While we do our part to optimize load performance, we need your help. This page has information on how to make the most of our performance optimizations in your development work.

↑ Top ↑

CDN / Front-End Caching #

As noted, our CDN handles serving Javascript, CSS and theme image, while uploaded images are served from our dedicated *.files.wordpress.com domain. When new versions of CDN-served files are deployed, the CDN will automatically flush its own cache and start serving the new version. This does not necessarily affect browser-side caching.

For CSS and Javascript, we automatically bust browser caches by appending a query string, ?m=[modified_time] to them in the source with a filter. For images, you will need to either change the file name or add a query string where the URL to the image is referenced.

Although not exactly caching, we concatenate, and in some cases minify all of the Javascript and CSS code we serve to make pages load faster for our users. You will not need to change the way your Javascript or CSS is written to take advantage of this optimization.

↑ Top ↑

Database Queries #

You should avoid direct database queries and always use the WordPress API. Many of the existing WordPress functions contain internal caching and will serve previously queried data if it’s still valid. Be wary of uncached functions, though.

For cases when you are sure that you cannot use a function that contains caching and need to do something that is resource intensive, you should cache the results using one of the options noted below.

↑ Top ↑

Object cache and Transients #

There are two approaches to caching within WordPress core, transients and the object cache. For a standard WordPress.org install, the difference is that transients are persistent and write to the options table with a timestamp whereas object cache functions are not persistent and cache on a page-by-page basis.

However, if you have persistent caching enabled on the server, then the transient functions become wrappers for the normal cache functions. On WordPress.com, transients act essentially identically to data stored in the object cache. Data stored in the cache will be available across multiple page loads but they can be cleared outside of your control.

This means that for both, you’ll need to check whether a value was returned from cache, and regenerate the data if it wasn’t. It can look something like this:

// Load my data from cache
$my_data = wp_cache_get( 'my-data' );
// Check if the cache actually returned something
if ( false === $my_data ) {
	$my_data = $wpdb->get_results( $query );
	wp_cache_set( 'my-data', $my_data );
}
// Present $my_data

↑ Top ↑

Options table #

Only when you’re storing a small amount of data that can’t easily be regenerated from a page request should you cache data in the options table.

↑ Top ↑

Example: caching WP_Query #

Here’s what a typical WP_Query loop looks like:

<?php
$args = array( 'orderby' => 'comment_count', 'posts_per_page' => '1', 'ignore_sticky_posts' => 1 );
$query = new WP_Query( $args );
while ( $query->have_posts() ) : $query->the_post();
	// do stuff
endwhile;

Here’s how to modify that loop to cache the results of the WP_Query object:

// First, let's see if we have the data in the cache already
$query = wp_cache_get( 'ordered_comments_query' ); // the cache key is a unique identifier for this data

if( $query == false ) {
	// Looks like the cache didn't have our data
	// Let's generate the query
	$args = array( 'orderby' => 'comment_count', 'posts_per_page' => '1', 'ignore_sticky_posts' => 1 );
	$query = new WP_Query( $args );

	// Now, let's save the data to the cache
	// In this case, we're telling the cache to expire the data after 300 seconds
	wp_cache_set( 'ordered_comments_query', $query, '', 300 ); // the third parameter is $group, which can be useful if you're looking to group related cached values together
}

// Once we're here, the $query var will be set either from the cache or from manually generating the WP_Query object
while ( $query->have_posts() ) : $query->the_post();
	// do stuff
endwhile;

↑ Top ↑

Other considerations #

Keep in mind that even though the object cache is meant to be a persistant data store, cache entries can and do get evicted. As such, your code should fail gracefully or regenerate the data as needed.

Ideally, you wouldn’t pass an expires value and do smart cache invalidation instead. For example, hook into save_post and call wp_cache_delete with the cache key(s). That way you ensure that you only really need to regenerate the cache data when it’s changed.

There are certain cases where you would use unique cache keys, for example, say you have a gallery slider on different category pages and you’re caching the results of the query used to generate it. If you used the same key across the board, you’d end up with the same data everywhere. Instead, you can suffix the cache key with something like the category id to make sure you have unique key for each cached data set. In particularly complex cases, you can use an md5 value of the query args as the cache key.

↑ Top ↑

Caching Remote Data #

The most common cause of slow page load times for our customers has been with 3rd party services and pulling in content from other sites. For 3rd party services try to late load them when possible, keywords: load without blocking, lazy load, and delay loading. For second group of common problems check out Fetching Remote Data.