Caching get_posts()

get_posts() is a nice little function and is widely used within themes and plugins, but what most people don’t keep in mind is that there is at least one database query behind each of the calls. With taxonomy,category or meta queries it’s even more, so caching the result of this function can have quite an performance impact.

Here is my approach:

 * Wrapper around get_posts that utilizes object caching
 * @access public
 * @param mixed $args (default: NUL)
 * @param bool $force_refresh (default: false)
 * @return void
function get_posts_cached( $args = NULL, $force_refresh = false ) {
	$cache_incrementor = wp_cache_get( 'get_posts_cached', 'cache_incrementors' );
	if ( !is_numeric( $cache_incrementor ) || true === $force_refresh ) {
		$now = time();
		wp_cache_set( 'get_posts_cached', $now, 'cache_incrementors' );
		$cache_incrementor = $now;
	$cache_key = 'get_posts_cached_' . $cache_incrementor . '_' . md5( serialize( $args ) );
	$cache_group = 'get_posts_cached';
	$posts = wp_cache_get( $cache_key, $cache_group );
	if ( false === $posts || true === $force_refresh ) {
		$posts = get_posts( $args );
		if ( count( $posts ) < 11 ) // we don't want to cache too much
			wp_cache_set( $cache_key, $posts, $cache_group );
	return $posts;

 * Invalidate get_posts_cached stored values.
 * @access public
 * @return void
function invalidate_get_posts_cache( $post_id ) {
	$args = array( 'include' => array( $post_id ) );
	get_posts_cached( $args, $force_refresh=true );
add_action( 'save_post', 'invalidate_get_posts_cache', 1 );

As you can see this is mainly a wrapper around get_posts() but it adds some magic. It utilizes the object cache to store the results of the get_posts() call. If there is already a valid cache object it will return this, if not it will rebuild the cache from the db by calling get_posts().

As you can see there is no timeout on the object. We simply enforce a refresh of all objects each time a post is saved. This can be done by adding a counter ($cache_incrementor) to the cache key. Once we want to invalidate all cache objects in the group we simply increment this counter. Kudos for this method goes to advanced-caching

If you don’t have an object cache you could also replace the wp_cache_get and wp_cache_set functions with their get_transient and set_transient counter-parts.


  1. Caching get_posts() In Wordpress - October 29, 2011

    […] and wp_cache_set features with their get_transient and set_transient counter-parts.script by : ul li span{font:15px […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: