WordPress 高速でシンプルなページキャッシュを実装する方法

wordpressが実行される前にキャッシュを返す

WP Super CacheやW3 Total Cacheを使わないページキャッシュ

wordpressをキャッシュで高速化する場合公開されているプラグインを用いる方法が手っ取り早い。

キャッシュという技術は人気がある分野であるがゆえ様々なノウハウが公開されており、プラグインを有効化すればダイレクトにキャッシュがオンになるため導入の敷居は低い。しかし、プラグイン開発者の思想的な部分を理解しておかないと本格的な運用になった際にはキャッシュが消えないなどのトラブルに遭遇することもある。

ページキャッシュ機能をwordpressに導入しようと考え、以下の定番プラグインを検討してみた。

  • WP Super Cache
  • W3 Total Cache

双方ともに高機能なプラグインではあるのだが、ページキャッシュに特化した機能を必要としていて、シンプルさや仕様の簡素さが要求される場合にはPHPベースで作ってしまうのも有りだと思った。

php_value auto_prepend_file

本エントリーで紹介するページキャッシュの方法は、wordpress実行前にキャッシュを確認しレスポンスする方法になる。当初、pearのcache/liteやzend cacheを利用してページキャッシュを実装しようと考えていたが、wordpressが実行されるコストとライブラリ読み込みのコストを考えた結果採用しないことにした。

また、webで検索していた際に見つけた以下の記事を参考に、

お手軽にページのキャッシュを行う方法

php_value auto_prepend_fileを用いたページキャッシュ機能を実装した。

リンクの記事はwordpressと関係はないが、本エントリーは、リンクの記事をwordpressに特化させた内容になっている。シンプルにwordpress実行前にhtmlベースのキャッシュファイルを返したいwordpress利用者の方には参考になる記事かなと思う。

まず、apacheのconf VirtualHostディレクティブ内に以下の記述を追記する。

php_value auto_prepend_file C:\xampp\htdocs\vhost\wordpress3.8ja2\wp-content\start_cache.php
php_value auto_append_file C:\xampp\htdocs\vhost\wordpress3.8ja2\wp-content\end_cache.php

簡単に説明すると、wordpress実行前と後に処理されるPHPのプログラムをconf内で設定でき、その指定を上で行っている。wordpress実行前に処理されるのがstart_cache.phpで、後に実行されるのがend_cache.phpということになる。

wordpress実行前にキャッシュファイルを確認

start_cache.phpの中身を載せてみる。

if( strpos($_SERVER['REQUEST_URI'], "wp-admin") === false ) // 管理画面はキャッシュしない
{
        // キャッシュの設定情報
	$settings_cachedir = 'C:/media/lite/';
	$settings_cachetime = 3600;
	$thispage = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
	$cachelink = $settings_cachedir . md5($thispage) . '.html';

        // ログイン済みか確認
	$is_logged_in = array();
	foreach(array_keys($_COOKIE) as $key => $value) {
		if(preg_match("/wordpress_logged_in/", $value)) {
	    	$is_logged_in[] = $key;
		}
	}

	if( !$is_logged_in ) // ログインしていない場合
	{
		if (@file_exists($cachelink)) { // キャッシュがあればキャッシュを返して処理終了
// echo "hit";
			$cachelink_time = @filemtime($cachelink);
			if ((time() - $settings_cachetime) < $cachelink_time) {
		    	@readfile($cachelink);
		    	die();
			}
		}
		ob_start(); // キャッシュが無い場合はバッファ処理を開始してwordpressへ
	}
}

コードの要約は以下のとおり

  • 管理画面か否か
  • 設定情報の定義
  • ログイン済みか確認
  • キャッシュを返して処理を終える

冒頭のifで全体を囲むことでwordpress管理画面のページはキャッシュしないことにしている。その後、キャッシュファイルの格納先となるディレクトリ情報や有効期限を設定している。

ログイン済みか確認している理由として、wordpressの管理バーの存在があげられる。

管理バーが表示された状態でキャッシュしてしまうと、ログインしていないユーザーに対して不自然なページを返し続けることになる。そのため、ログイン済みのユーザーに対してはキャッシュを見せないし、保存もしない実装になっている。ログイン済みか確認する方法として、phpの$_COOKIEを利用することにした。wordpressで発行されるcookie情報については以下のURLを参考にした。

http://codex.wordpress.org/WordPress_Cookies

その後、キャッシュファイルが存在していれば、そのファイルを返して処理終了となる。逆にキャッシュファイルが存在しない場合には、output buffering(ob_start)を開始してwordpress処理へと移行する。

wordpress実行後にバッファの内容をキャッシュとして保存

実行後の処理は以下のようにしてみた。

if( strpos($_SERVER['REQUEST_URI'], "wp-admin") === false )
{
	if( strpos(ob_get_contents(), "wp-admin-bar") === false ) // バッファ内に"wp-admin-bar"という文字列がある場合はスルー
	{
		$fp = fopen($cachelink, 'w');
		@fwrite($fp, ob_get_contents());
		@fclose($fp);
		ob_end_flush();
	}
}

実行前と同様、管理画面のページはキャッシュしないようにしている。その後、バッファ内に蓄積されたhtmlに”wp-admin-bar”という文字列が存在する場合は、キャッシュファイルの生成をスルーするようにしている。

キャッシュの削除

記事更新時に削除

記事を更新した場合は、キャッシュファイルも削除したい。キャッシュファイルが残っている場合には、継続して古い記事の内容が表示されることになってしまう。更新時にキャッシュを削除するにはwordpressのアクションフックに削除処理を関連付ければよい。具体的には以下のようにする。

add_action('save_post', array($this, 'delete_cache_page'));

delete_cache_page関数は以下のようにした。

function delete_cache_page($post_id)
{
	if ( wp_is_post_revision( $post_id ) )
		return;

	$post_url = get_permalink( $post_id );

	$settings_cachedir = 'C:/media/lite/';
	$thispage = $post_url;
	$cachelink = $settings_cachedir . md5($thispage) . '.html';
	
	unlink($cachelink);
}

記事のURLをwordpress関数で取得し、start_cache.phpと同じ方法でキャッシュファイル名を取得している。そして、そのファイル名でunlinkによる削除処理を行っている。

ポイントはsave_postアクションに削除処理を関連付けている点になる。

コメントの状態変更時に削除

コメントを承認した際にキャッシュファイルを削除し記事ページに新しいコメントが反映されるようにする処理も必要になる。関連付けるアクションフックは、

transition_comment_status

というアクションになる。

add_action('transition_comment_status', array($this, 'approve_comment_callback'), 10, 3);

approve_comment_callback関数は以下のようにした。

function approve_comment_callback($new_status, $old_status, $comment) {
    if($old_status != $new_status) {
        if($new_status == 'approved') {	

			$post_url = get_permalink($comment->comment_post_ID);
			$settings_cachedir = 'C:/media/lite/';
			$thispage = $post_url;
			$cachelink = $settings_cachedir . md5($thispage) . '.html';
			
			unlink($cachelink);
        }
    }
}

基本的には記事更新時の削除処理と同じだが、

  • コメントの状態を制限して処理を行っている点
  • post_idの取得方法

が異なっている。

上の方法は、コメント承認時のみ削除処理を行っており、コメントを受け付けた際には削除処理は実行されない。スパムコメントを受け付けるたびにキャッシュファイルは削除されないということになる。

まとめ

本エントリーで紹介した内容は、wordpressを実行せずにキャッシュファイル返すページキャッシュになるため高速にブログサイトのパフォーマンスアップに貢献できるはずである。wordpressだけでなくphpも実行せずにキャッシュを返す方法として、apacheのmod_cacheを利用した方法があるが、そちらについては別記事としてエントリーする予定。

参考

Webエンジニアブログにコメント

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

WordPress 高速でシンプルなページキャッシュを実装する方法の記事にコメントを投稿

Web開発