SWELLの投稿リストブロックは多機能で便利です。
便利だからといって、TOPページで投稿リストブロックをカテゴリごとに分けて複数配置している人も多いと思います。
投稿リストブロックは一つのブロックごとにクエリを発行しますので、複数配置かつ記事の数が多くなってくるとページ表示速度が遅くなる欠点があります。
この記事では、SWELLの投稿リストをキャッシュ付きにするカスタマイズをご紹介します。
このカスタマイズは、投稿リストのショートコード[post_list]
にも有効です。
投稿リストブロックが記事一覧を表示するまでの流れ
投稿リストブロックはサブループで実行される
WordPressで記事一覧を取得する場合、クエリを発行して取得しますが、メインループとサブループの場合で処理方法が異なります。
SWELLの投稿リストブロックは、メインループになるアーカイブページと異なりサブループの処理になります。

投稿リストブロックの処理フロー
投稿リストブロックは、パラメータを取得してサブループを回します。
- パラメータを引数にして
list_on_block()
関数を呼び出す。 list_on_block()
関数内部で、parts/post_list/loop_sub
を呼び出し、サブループを実行する。parts/post_list/loop_sub
がHTMLを出力する
この流れの中でキャッシュすべきは、3の部分です。
パラメータごとに結果はユニークなはずですからパラメータをキーにしてキャッシュを生成して、キャッシュを読み込む処理を追加します。
クエリの発行時間が少なくなれば、処理速度が速くなり、ページ表示も高速になります。
キャッシュ付きのサブループを実装する
parts/post_list/loop_sub
のファイルは子テーマでカスタマイズ可能ですから、parts/post_list/loop_sub
をカスタマイズすればキャッシュ付きのサブループを実装できます。
ブロックエディタにブロックを配置した時に、キャッシュを読み込まないように判定しています。
ブロックエディタ表示時は、キャッシュスルーにしたいのですが、is_admin()などの判定が効きません。
以下の記事にブロックエディタを開いていることを判定する方法があったのでそれを使っています。
<?php
use \SWELL_THEME\Parts\Post_List;
if ( ! defined( 'ABSPATH' ) ) exit;
if( is_admin() || (defined( 'REST_REQUEST' ) && REST_REQUEST && 'edit' === $_GET['context'])) {
$cache_bypass = 1;
}else{
$cache_bypass = 0;
}
/**
* サブループでの投稿リスト出力テンプレート
*/
if ( isset( $variable['query'] ) ) {
$transient_key = 'sub_loop_'.md5(serialize($variable['query']));
$res = get_transient($transient_key);
if($res===false || $cache_bypass ):
// すでにクエリが生成済みの場合
$the_query = $variable['query'];
endif;
} elseif ( isset( $variable['query_args'] ) ) {
$transient_key = 'sub_loop_'.md5(serialize($variable['query_args']));
$res = get_transient($transient_key);
if(( $res===false || $cache_bypass) || !empty($variable['list_args']['cacheoff'])):
// クエリ生成
$the_query = new \WP_Query( $variable['query_args'] );
endif;
} else {
// クエリに関する情報がない時
return;
}
if($res!==false && !$cache_bypass){
echo $res."<!-- cached -->";
return;
}
ob_start();
// リストの設定情報
$list_args = isset( $variable['list_args'] ) ? $variable['list_args'] : [];
// リストデータ整理
$list_data = Post_List::get_list_data( $list_args );
$li_args = $list_data['li_args'];
$ul_class = $list_data['ul_class'];
$parts_name = $list_data['parts_name'];
$infeed_interval = $list_data['infeed_interval'];
// 記事がなかった場合
if ( ! $the_query->have_posts() ) :
$not_founded_text = __( '記事が見つかりませんでした。', 'swell' );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo apply_filters( 'swell_posts_404_text', '<p>' . $not_founded_text . '</p>' );
return;
endif;
// ループ
$loop_ct = 0;
echo '<ul class="' . esc_attr( $ul_class ) . '">';
while ( $the_query->have_posts() ) :
$the_query->the_post();
// インフィード
if ( $infeed_interval && $loop_ct && ( 0 === $loop_ct % $infeed_interval ) ) :
SWELL_Theme::get_parts( 'parts/post_list/infeed_ad', $loop_ct );
endif;
SWELL_Theme::get_parts( 'parts/post_list/' . $parts_name, $li_args );
$loop_ct++;
endwhile;
echo '</ul>';
$res = ob_get_clean();
if(!$cache_bypass):
set_transient(
$transient_key,
$res,
60 * 60 * 24 * 7//秒で指定(サンプルは一日)
);
endif;
echo $res;
wp_reset_postdata();
キャッシュ削除の処理
記事を更新した時にキャッシュを削除する処理をしないと、transientの期限まで更新されなくなります。
add_action( 'save_post', 'wpdocs_delete_my_important_transient',9,1);
add_action( 'deleted_post', 'wpdocs_delete_my_important_transient',9,1 );
//add_action( 'edit_post', 'wpdocs_delete_my_important_transient',9,3 );
function wpdocs_delete_my_important_transient($post_ID) {
$prefix="sub_loop_";
delete_transient_prefix($prefix);
}
function delete_transient_all(){
global $wpdb;
$db_prefix = $wpdb->prefix;
$wpdb->query("delete from `".$db_prefix."options` where `option_name` like '%_transient_%'");
}
function delete_transient_prefix($prefix){
global $wpdb;
$db_prefix = $wpdb->prefix;
$wpdb->query("delete from `".$db_prefix."options` where `option_name` like '%_transient_".$prefix."_%'");
}
まとめ
今回のカスタマイズは、サブループを使っている他の機能でも同様にキャッシュされるので、投稿リストブロックだけではなく、投稿リストのショートコードに対しても有効です。
何でもかんでもキャッシュしてしまうので、問題が起きることも考えられます。
適用する場合は、自己責任でよろしくお願いします。
コメント