Caching Ajax requests in WordPress

In modern WordPress themes, theme developers are serving the page requests via ajax. Both paginated blog page and single posts (might be in full or partial) are served. Though WordPress is very fast if properly tuned, but it’s meaningless to pull the same data from WordPress database again and again unless there is any change. Which means, you can safely cache such ajax requests and reduce loads on your database by adding a few lines of extra code in your theme’s functions.php. In this article, we will learn how to take advantage of such caching in WordPress

Step 1: Register Ajax callback for serving paginated blog pages
Here is a typical codeblock that can serve paginated blog pages via ajax. There is no caching yet

add_action("wp_ajax_blog", "get_blog");
add_action("wp_ajax_nopriv_blog", "get_blog");

function get_blog(){
	global $post;
	$page = $_REQUEST['page'];
	if(!$page) $page=1;
	$pp = get_option("posts_per_page");
	$offset = ($page*1-1)*$pp;
	$args = array(
		"posts_per_page"=>$pp,
		"offset"=>$offset
		);
	$posts = get_posts($args); //get the posts
	foreach($posts as $post){
		setup_postdata( $post );
		get_template_part("templates/post",get_post_format($post->ID));
	}
	die();
}

Now if you go to the url “http://your_blog_url/wp-admin/admin-ajax.php?page=1 ” you can see the latest posts, change the page value to 2,3,4 and so on to see previous posts. Each posts in the loop are rendered via get_templates(). Please note how we used the get_post_format() function in the loop to serve different templates based on post formats.

So what is bad in this code? Nothing, yet Everything! If 100 users are visiting your blog and they are visiting blog pages, each and every time these posts are pulled from database. Each and everytime they are pulling the very same data until you had edited any post, or created a new post. So why this extra load should go to DB? lets minimize it :)

Step 2: Add caching layer
here is a revised format of the code block above, but now with caching.

add_action("wp_ajax_blog", "get_blog");
add_action("wp_ajax_nopriv_blog", "get_blog");

function get_blog(){
	global $post;
	$page = $_REQUEST['page'];
	if(!$page) $page=1;

	/** supply from cache **/
	$page_from_cache = get_option( "artpress_page{$page}", 0 );
	if($page_from_cache){
		die($page_from_cache);
	}
	/** cache end **/

	$pp = get_option("posts_per_page");
	$offset = ($page*1-1)*$pp;
	$args = array(
		"posts_per_page"=>$pp,
		"offset"=>$offset

		);
	$posts = get_posts($args);

	ob_start();
	foreach($posts as $post){
		setup_postdata( $post );
		get_template_part("templates/post",get_post_format($post->ID));
	}
	$new_cache = ob_get_flush();

	/** save the cache **/
	update_option( "artpress_page{$page}",$new_cache);
	/** end cache **/
	die($new_cache);
}

In the code above, we first checked the page number. Then, checked in the wordpress options table if there is a cache present with a key named “artpress_page”. Now, for the first time it wont be there. So we just pull the records from the database as usually and then using the output buffering functions we capture the output, instead of pushing instantly to the browser. And then we update the options table with this output. So next time when same page will be requested, database wont be hit. Ok, database will be hit (this options table data is coming from the db) but you can see it wont touch the posts table again, and avoid running expensive queries (which includes many joins) in that table. It also saves CPU a bit.

Step 3: Invalidate cache whenever a post is edited, or created
This is an important step. We need to flush the cache whenever a new post or page is created to make sure our blog shows the up to date data.

add_action("save_post","invalidate_cache");
function invalidate_cache(){
	$counts = wp_count_posts();
	$total_published_posts = $counts->publish;
	$posts_per_page = get_option( "posts_per_page");
	$total_page = ceil($total_published_posts/$posts_per_page);
	for($i=1;$i<=$total_page;$i++){
		delete_option( "artpress_page{$i}" );
	}
}

Now, we are in good shape. Our ajax requests are served from cache and properly purges whenever necessary. You can serve your single post same way.

If you want to serve single posts from the cache, one thing you need to keep in mind is that you are loading up an important table “options” with a lot of data. So you can change the code above and store the cache in filesystem instead of options table. You should have write permission in the uploads directory by default. So that wont be tough at all.

I hope you enjoyed this article :)

About these ads

One thought on “Caching Ajax requests in WordPress

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s