WordPress高速化:最新記事などウィジェット系のキャッシュ

WordPress高速化:最新記事などウィジェット系のキャッシュ

プラグインもほんとど使わずに作った自作テーマが結構快調です。このサイトではなく下の別サイトです。さらなる高速化を考えます。

01Transients API を使ってキャッシュする

該当のサイトの個別ページのサイドバーには、最新記事5件、おすすめ記事5件、人気記事5件を表示しています。このうち、最新記事とおすすめ記事は新規記事を公開しない限り変更はありません。

じゃあ、アクセスがあるたびにデータベースに読みにいかずに静的ファイルで保存しておけばいいのではないかと思ったのが出発点です。

Transients API という API があり、これはキャッシュされた情報を一時的にデータベースに有効期限付きで保存できるものとのことです。

set_transient(), get_transient(), delete_transient() と保存、取得、削除の関数がそろっています。

set_transient( $transient, $value, $expiration );
$transient
(文字列) キャッシュされるデータにつけるユニークな識別子。長さ 45 文字以下であること。注意: site_ の Transient を使う場合は 40 文字以下とする。
$value
(配列|オブジェクト) 保存するデータ。ふつうの変数または配列/オブジェクト。複雑なデータはこの API がシリアライズしてくれる。
$expiration
(整数) データを更新するまでの最大の秒数。Transient は $expiration より前に期限切れする場合があるが(外部オブジェクトキャッシュや、データベースのアップグレードによる)、$expiration を過ぎると値を決して返さない。

get_transient( $transient );

delete_transient( $transient );

(Transients API)

02transition_post_status で記事公開時にキャッシュ作成

で、いつキャッシュを保存するかですが、アクセスがあったらということでも問題ありませんが、記事を公開、あるいは修正した際に保存できればそれに越したことはありませんので、なにかフックはないかと探しましたら、transition_post_status というピッタリのものがありました。

このフックは、記事の投稿ステータス、例えば公開済みは publish、下書きは draft ですが、そのステータスが変更された場合に呼ばれるものです。

具体的には次のように使います。

function on_all_status_transitions( $new_status, $old_status, $post ) {
if ( $new_status != $old_status ) {
// 投稿ステータスが任意に変わるとき実行する処理。
}
}
add_action( ‘transition_post_status’, ‘on_all_status_transitions’, 10, 3 );

transition_post_status フック

03実際の運用例

該当のサイトでは次のように運用しています。

functions.php

function imz_create_cache( $new_status, $old_status, $post ) {
    if( 'publish' !== $old_status && 'publish' !== $new_status )
        return;
    
    // 最新映画レビュー5件キャッシュ
    $transient_name = 'new_post_list';
    $query = new WP_Query(array('post_status' => 'publish', 'posts_per_page' => 5));
    set_transient( $transient_name, $query, WEEK_IN_SECONDS );
    
    // おすすめ映画5件キャッシュ
    $transient_name = 'recommend_post_list';
    $query = new WP_Query(array('post_status' => 'publish', 'category_name' => 'recommend', 'posts_per_page' => 5));
    set_transient( $transient_name, $query, WEEK_IN_SECONDS );
}
add_action( 'transition_post_status', 'imz_create_cache', 10, 3 );

公開されたときに呼ばれる publish_post フックでやっていたのですが、これですと記事を更新したときや公開記事を一旦下書きに戻したときに呼ばれませんので上記のようにしています。

Transient の期限は、次に記事を公開する場合に更新されるわけですから無期限でもいいのですが、ドキュメントに次の記述があり、どういうことかよくわかりませんので1週間にしているということです。週に2、3記事は書きますので結果は同じことです。

無期限の Transient はオートロードされますが、有効期限を持つ Transient はオートロードされません。

(set transient)

sidebar.php

サイドバーに新規記事5件を表示するケースです。

<?php
$query = get_transient('new_post_list');
$cache = true;
if(empty($query)){
	$query = new WP_Query(array('post_status' => 'publish', 'posts_per_page' => 5));
	$cache = false;
}
if ( $query->have_posts() ) :
	while ( $query->have_posts() ) : $query->the_post();
?>
<a class="widget-card-link" href="<?php the_permalink(); ?>">
<article class="widget-article">
<figure class="widget-thumbnail"><?php has_post_thumbnail() ? the_post_thumbnail('thumbnail') : get_dummy_img(''); ?></figure>
<p class="widget-article-title"><?php the_title(); ?></p>
<time class="widget-date"><?php the_time('Y.m.d'); ?></time>
</article>
</a>
<?php endwhile; endif; ?>
<?php if(!$cache) wp_reset_postdata(); ?>

04キャッシュデータの保存場所

キャッシュされたデータはデータベースの wp_options テーブルに保存されます。

最新記事とおすすめ記事がそれぞれデータと期限で保存されています。

ということで多少は高速化できたのでしょうか。多分誤差程度だと思います(笑)。