2026年6月3日
2026年6月3日
WordPressのトランジェントAPIでキャッシュを実装する方法
はじめに
「重いDBクエリの結果をキャッシュしてページを高速化したい」「外部APIのレスポンスをキャッシュして無駄なリクエストを減らしたい」「WordPress標準のキャッシュ機能を使いたい」——トランジェントAPIはWordPress標準の一時データ保存機構で、Redis/Memcachedとも自動連携します。
症状・原因
WP_Queryによる複雑な検索や外部APIコールを毎ページリクエストで実行するとサーバー負荷が高くなります。トランジェントAPIで結果をDBまたはオブジェクトキャッシュに保存することで、TTL(有効期間)内は高速な取得が可能になります。
解決手順
ステップ1:基本的なトランジェントの使い方
// functions.php: トランジェントの基本操作
// 保存(TTL: 1時間)
set_transient( 'my_cache_key', $data, HOUR_IN_SECONDS );
// 取得(falseならキャッシュなし)
$data = get_transient( 'my_cache_key' );
if ( false === $data ) {
// キャッシュがない場合は新しく取得
$data = fetch_expensive_data();
set_transient( 'my_cache_key', $data, HOUR_IN_SECONDS );
}
// 削除
delete_transient( 'my_cache_key' );
// WordPress定数(TTL指定に使う)
// MINUTE_IN_SECONDS = 60
// HOUR_IN_SECONDS = 3600
// DAY_IN_SECONDS = 86400
// WEEK_IN_SECONDS = 604800
// MONTH_IN_SECONDS = 2592000
// YEAR_IN_SECONDS = 31536000
// TTL = 0 にすると有効期限なし(非推奨・肥大化する)
set_transient( 'my_permanent_cache', $data, 0 );
ステップ2:WP_Queryの結果をキャッシュする
// functions.php: 重いクエリのキャッシュパターン
function get_popular_posts( $count = 5 ) {
$cache_key = 'popular_posts_' . $count;
$posts = get_transient( $cache_key );
if ( false !== $posts ) {
return $posts; // キャッシュヒット
}
// キャッシュミス:DBから取得
$posts = get_posts( [
'posts_per_page' => $count,
'meta_key' => 'post_views_count',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'post_status' => 'publish',
'no_found_rows' => true,
'suppress_filters' => false,
] );
// 結果をキャッシュ(6時間)
set_transient( $cache_key, $posts, 6 * HOUR_IN_SECONDS );
return $posts;
}
// 投稿更新時にキャッシュを自動削除
add_action( 'save_post', function( $post_id ) {
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
return;
}
// 関連するキャッシュを削除
for ( $i = 1; $i <= 20; $i++ ) {
delete_transient( 'popular_posts_' . $i );
}
} );
ステップ3:外部APIレスポンスをキャッシュする
// functions.php: 外部APIキャッシュパターン(エラー時は古いキャッシュを使う)
function get_weather_data( $city = 'Tokyo' ) {
$cache_key = 'weather_' . sanitize_key( $city );
$stale_key = $cache_key . '_stale'; // 期限切れでも保持する古いデータ
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached;
}
// APIリクエスト
$api_key = get_option( 'weather_api_key' );
$response = wp_remote_get(
add_query_arg( [ 'q' => $city, 'appid' => $api_key ],
'https://api.openweathermap.org/data/2.5/weather' ),
[ 'timeout' => 10 ]
);
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
// エラー時は古いキャッシュ(stale)を返す
$stale = get_transient( $stale_key );
return $stale ?: [];
}
$data = json_decode( wp_remote_retrieve_body( $response ), true );
// 30分キャッシュ
set_transient( $cache_key, $data, 30 * MINUTE_IN_SECONDS );
// staleは24時間保持(エラー時のフォールバック用)
set_transient( $stale_key, $data, DAY_IN_SECONDS );
return $data;
}
ステップ4:サイト全体のトランジェントを管理する
// functions.php: グループキャッシュパターン(バージョン番号でまとめて無効化)
function get_cache_version( $group ) {
$version = get_option( 'cache_version_' . $group, 1 );
return $version;
}
function bump_cache_version( $group ) {
$version = get_cache_version( $group );
update_option( 'cache_version_' . $group, $version + 1, false );
}
function get_versioned_transient( $key, $group ) {
$versioned_key = $key . '_v' . get_cache_version( $group );
return get_transient( $versioned_key );
}
function set_versioned_transient( $key, $group, $data, $ttl = HOUR_IN_SECONDS ) {
$versioned_key = $key . '_v' . get_cache_version( $group );
set_transient( $versioned_key, $data, $ttl );
}
// グループ全体を無効化(バージョンをインクリメント)
// bump_cache_version('products');
// これ以降は新しいバージョン番号のキーが使われ、古いキャッシュは自然に期限切れになる
// 期限切れトランジェントの一括削除(cronで定期実行)
function delete_expired_transients() {
global $wpdb;
$wpdb->query(
$wpdb->prepare(
"DELETE a, b FROM {$wpdb->options} a
INNER JOIN {$wpdb->options} b ON b.option_name = REPLACE(a.option_name, '_transient_timeout_', '_transient_')
WHERE a.option_name LIKE '_transient_timeout_%%'
AND a.option_value < %d",
time()
)
);
}
add_action( 'my_daily_cleanup', 'delete_expired_transients' );
ステップ5:Redis・Memcachedでオブジェクトキャッシュに昇格させる
// Redis Object Cacheプラグイン(tillkruss/redis-cache)またはW3 Total Cacheを導入すると
// set_transient() / get_transient() が自動的にRedis/Memcachedを使用する
// コードの変更は不要
// wp-config.phpでRedisの接続設定
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_PASSWORD', 'your_password' ); // 認証が必要な場合
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_PREFIX', 'mysite_' ); // 複数サイトでRedisを共有する場合
// オブジェクトキャッシュが有効かチェック
if ( wp_using_ext_object_cache() ) {
// Redis/Memcachedが使われている
// トランジェントはDBを使わずキャッシュサーバーに保存される
}
// オブジェクトキャッシュを直接使う(TTLなし・リクエスト内のみ)
wp_cache_set( 'my_key', $data, 'my_group' );
$data = wp_cache_get( 'my_key', 'my_group' );
wp_cache_delete( 'my_key', 'my_group' );
注意事項
- トランジェントは
wp_optionsテーブルに保存されます。大量のトランジェントを作成するとテーブルが肥大化し、autoloadオプションの読み込みが遅くなります。キーの命名規則を統一し、不要になったら削除してください。 get_transient()がfalseを返す場合、キャッシュが存在しないか期限切れのどちらかです。値がfalseのデータをキャッシュしてはいけません。必要な場合はラッパー配列に入れて保存してください(例:['value' => false])。- Redisが導入されている環境では
set_transient()のTTL=0は動作が異なります。Redisではキーが永続化されますが、DBではwp_optionsに無期限で残ります。TTL=0は避けるか、用途を明確にしてください。
まとめ
トランジェントAPIの実装は「get_transient()でキャッシュヒット確認→falseなら処理実行→set_transient()でTTL付きキャッシュ保存→save_postフックで関連キャッシュを自動削除→Redis Object Cacheプラグイン導入でDBレスのキャッシュに昇格」の流れで整備します。関連記事:WordPressのwp_cronで定期処理を実装する方法、WordPressのページ表示速度を改善する方法。