
WordPress Transients API 完全ガイド - キャッシュ・落とし穴・オブジェクトキャッシュ連携まで
Transients API とは
Transients API(トランジェント API)は、WordPress 標準で用意されている 「有効期限付きの一時キャッシュ」 の仕組みです。Options API と似ていますが、expiration(秒)を指定できる点が決定的に異なります。
外部 API のレスポンス、複雑な WP_Query の集計結果、サイドバーの人気記事など 「毎回計算したくないが、最新でなくてもよいデータ」 を保存するのに最適です。
本記事は WordPress 6.8 系、2026年5月時点 の公式リファレンス(developer.wordpress.org/apis/transients)に基づきます。コードは PHP 8.2 を想定しています。
3つの基本関数
| 関数 | 役割 |
|---|---|
set_transient( $key, $value, $expiration ) | キャッシュをセット/更新 |
get_transient( $key ) | キャッシュを取得(期限切れ・未設定なら false) |
delete_transient( $key ) | キャッシュを明示的に削除 |
// 30分間キャッシュ
set_transient( 'my_popular_posts', $posts, 30 * MINUTE_IN_SECONDS );
// 取得(フォールバック必須)
$posts = get_transient( 'my_popular_posts' );
if ( false === $posts ) {
$posts = expensive_query(); // 重い処理
set_transient( 'my_popular_posts', $posts, 30 * MINUTE_IN_SECONDS );
}
// 明示削除
delete_transient( 'my_popular_posts' );WordPress には MINUTE_IN_SECONDS / HOUR_IN_SECONDS / DAY_IN_SECONDS / WEEK_IN_SECONDS / MONTH_IN_SECONDS / YEAR_IN_SECONDS といった定数が定義されているので、こちらを使うとマジックナンバーを避けられて可読性が上がります。
どこに保存されるのか
Transients の挙動は オブジェクトキャッシュの有無 で大きく変わります。
オブジェクトキャッシュなし(標準環境)
wp_options テーブルに 2行ペア で保存されます。
| option_name | 内容 |
|---|---|
_transient_my_popular_posts | キャッシュ本体 |
_transient_timeout_my_popular_posts | UNIX タイムスタンプ(有効期限) |
get_transient() 呼び出し時に _transient_timeout_* を見て、現在時刻と比較。期限切れであれば両行を削除し false を返します。
オブジェクトキャッシュあり(Redis / Memcached)
wp_using_ext_object_cache() が true の場合、Transients は wp_options に書かれず、wp_cache_set() 経由でメモリストアに保存 されます。これは公式ドキュメントにも明記されている重要な挙動です(Transients - Common APIs Handbook)。
// Redis Object Cache 等が有効な環境では、内部的に下記とほぼ等価になる
wp_cache_set( $key, $value, 'transient', $expiration );これが Transients が 「キャッシュプラグインを入れるだけで自動的に高速化される」 理由です。Options API(update_option)はこの恩恵を受けません。
site_transient との違い
マルチサイト環境では、サイト単体のキャッシュ か ネットワーク全体のキャッシュ かを使い分けます。
| 関数 | スコープ | 保存先(マルチサイト) |
|---|---|---|
set_transient() | 各サブサイト | 各サイトの wp_options |
set_site_transient() | ネットワーク全体 | wp_sitemeta |
シングルサイトであっても、WordPress 本体のアップデート情報(update_core トランジェント等)は site_transient で保存されます。プラグイン作者なら覚えておきたい違いです。
キーの命名と長さ制限
公式リファレンスに 明示されている上限 があります。
| 関数 | キーの最大長 |
|---|---|
set_transient() | 172 文字 |
set_site_transient() | 167 文字 |
_transient_ プレフィックスや _transient_timeout_ プレフィックスを足したときに、wp_options.option_name の VARCHAR(191) に収まるための制約です。
実用的な命名パターン
- プラグイン/テーマ名をプレフィックスに付ける:
mytheme_popular_posts - 入力値の
md5()ハッシュ で動的キーを安全に短縮:mytheme_api_. md5( $endpoint . $user_id ) - バージョン番号を入れる:
mytheme_v2_popular_posts(破壊的変更時にいっせいに無効化できる)
実用パターン集
1. 外部 API のレスポンスをキャッシュ
おそらく Transients でもっとも一般的なユースケースです。
function mytheme_get_github_repos( $user ) {
$key = 'mytheme_gh_' . md5( $user );
$cached = get_transient( $key );
if ( false !== $cached ) {
return $cached;
}
$response = wp_remote_get( "https://api.github.com/users/{$user}/repos" );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
return array();
}
$repos = json_decode( wp_remote_retrieve_body( $response ), true );
set_transient( $key, $repos, HOUR_IN_SECONDS );
return $repos;
}2. 重い WP_Query の集計結果をキャッシュ
function mytheme_popular_posts( int $limit = 5 ): array {
$key = 'mytheme_popular_' . $limit;
$cached = get_transient( $key );
if ( false !== $cached ) {
return $cached;
}
$query = new WP_Query( array(
'posts_per_page' => $limit,
'meta_key' => 'post_views',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'no_found_rows' => true,
) );
$posts = array_map( fn( $p ) => array(
'id' => $p->ID,
'title' => $p->post_title,
'url' => get_permalink( $p ),
), $query->posts );
set_transient( $key, $posts, 6 * HOUR_IN_SECONDS );
return $posts;
}3. 投稿の更新時にキャッシュをパージ
「データが変わったタイミングでキャッシュも消す」をフックで自動化します。
add_action( 'save_post', 'mytheme_purge_popular_cache' );
add_action( 'deleted_post', 'mytheme_purge_popular_cache' );
function mytheme_purge_popular_cache(): void {
foreach ( array( 5, 10, 20 ) as $limit ) {
delete_transient( 'mytheme_popular_' . $limit );
}
}4. 「ストリームライン」パターン(推奨ヘルパー)
毎回フォールバックを書くのは煩雑なので、汎用ヘルパー関数 を一つ用意しておくとプロジェクト全体で楽になります。
/**
* キャッシュからの取得を試み、なければコールバックで再計算してキャッシュする
*
* @template T
* @param string $key
* @param int $ttl_seconds
* @param callable():T $producer
* @return T
*/
function mytheme_remember( string $key, int $ttl_seconds, callable $producer ) {
$cached = get_transient( $key );
if ( false !== $cached ) {
return $cached;
}
$value = $producer();
set_transient( $key, $value, $ttl_seconds );
return $value;
}
// 使い方
$repos = mytheme_remember( 'mytheme_gh_' . md5( $user ), HOUR_IN_SECONDS, function () use ( $user ) {
return fetch_github_repos( $user );
} );Laravel の Cache::remember() を WordPress に持ち込んだイメージです。
落とし穴 - 本番で踏みやすいワナ
ワナ 1:「期限切れまでは存在する」と仮定する
公式ドキュメントが何度も警告している通り、Transients は最大期限であって最小期限ではありません。
Transients can disappear anytime after being set—they might expire in one second or persist for hours, but will never persist past the expiration time.
LRU 退避のあるオブジェクトキャッシュ環境 や、object-cache.php がない環境で Cron 実行が遅延した場合 など、いつでも false が返ってくる可能性があります。フォールバック処理は必須 です。
ワナ 2:遅延ガベージコレクション(最大の罠)
WordPress は get_transient() が呼ばれた時にしか期限切れトランジェントを削除しません(Jasper's blog)。
つまり、次のような 動的キーで毎回違うキャッシュを作る コードは要注意です。
// アンチパターン:ユーザーIDごとに別キーを作っている
$key = 'api_response_' . md5( $endpoint . $user_id );
set_transient( $key, $data, HOUR_IN_SECONDS );このコードは、同じキーでもう一度 get_transient() が呼ばれない限り、期限切れデータが永遠に wp_options に居座ります。1日に何万人もアクセスがあるサイトでは、wp_options が肥大化して autoload の遅延 や DB バックアップサイズの異常増加 を引き起こします。
対策:定期掃除を WP-Cron に登録する
add_action( 'init', function () {
if ( ! wp_next_scheduled( 'mytheme_cleanup_expired_transients' ) ) {
wp_schedule_event( time(), 'hourly', 'mytheme_cleanup_expired_transients' );
}
} );
add_action( 'mytheme_cleanup_expired_transients', function () {
global $wpdb;
$now = time();
// 自分のプレフィックスだけ対象にする(他プラグインに影響を与えない)
$rows = $wpdb->get_results( $wpdb->prepare(
"SELECT option_name FROM {$wpdb->options}
WHERE option_name LIKE %s
AND option_value < %d",
$wpdb->esc_like( '_transient_timeout_mytheme_' ) . '%',
$now
) );
foreach ( $rows as $row ) {
$key = str_replace( '_transient_timeout_', '', $row->option_name );
delete_transient( $key );
}
} );delete_transient() を呼べば、本体(_transient_*)とタイムアウト行(_transient_timeout_*)の両方をきれいに削除してくれます。自プラグイン/自テーマのプレフィックスだけ を対象にすることがマナーです。
ワナ 3:オブジェクトキャッシュ環境では wp_options を覗いても出てこない
「Transients が動いていないかも?」とデバッグで wp_options を SELECT * WHERE option_name LIKE '_transient_%' しても、Redis Object Cache が有効なら何も返ってこない のが正常です。
確認は wp_using_ext_object_cache() か、WP-CLI の wp transient list を使います。
# WP-CLI で一覧
wp transient list --network=false
# 個別の取得・設定・削除
wp transient get my_popular_posts
wp transient set my_popular_posts "value" 3600
wp transient delete my_popular_posts
# 期限切れだけ一括削除
wp transient delete --expired
# 全部削除(注意!)
wp transient delete --allワナ 4:シリアライズできない値を渡す
PHP のリソース(DB 接続ハンドル、Stream など)や クロージャ を渡すと serialize() 時に Fatal が出ます。配列・スカラー・標準クラスのインスタンスに留めるのが安全です。
ワナ 5:「巨大な配列」を1キーに詰める
wp_options のレコードを大きくするほど、autoload との兼ね合いやレプリケーション・バックアップで効いてきます。1MB を超えるようなレスポンスはトランジェントに直接入れず、ファイル/メディアにして URL だけキャッシュする などの工夫を検討してください。
オブジェクトキャッシュとの関係
WordPress でパフォーマンスを真面目にやるなら、Redis Object Cache か Memcached を入れるのが定番です。導入後、Transients は自動的にメモリストアに移ります。
| 項目 | DB保存(標準) | Redis/Memcached |
|---|---|---|
| 速度 | 〇(1回のSELECT) | ◎(メモリアクセス) |
| 書き込み負荷 | DB に書く | メモリに書く |
| 永続性 | 〇(DB なので原則残る) | △(メモリなので再起動で消える) |
| GC | 遅延(get 時のみ) | LRU 等が効く |
wp_options 肥大化 | 起こりうる | 起こらない |
| 監視 | SQL でできる | redis-cli / WP-CLI |
「Transients を本気で使うなら Object Cache を必須化する」は、中規模以上の WordPress 案件では既にデフォルトの考え方です。
いつ使う/いつ使わない
使うべきケース
- 外部 API の 読み取り結果(GitHub、天気、SNS、為替など)
- 重い
WP_Queryの 読み取り 集計 - ナビゲーションメニュー・サイドバーなど 更新頻度の低い HTML 断片
- プラグイン更新チェックや 定期的なバックグラウンドタスクの結果
使わない方がよいケース
- トランザクションが必要な業務データ(注文、決済、在庫)
- 永続性が必要な設定値 → Options API へ
- ユーザー固有のセッション情報 → セッション管理 or Cookie
- 巨大データ(>1MB)
まとめ
WordPress Transients API は、
- 3関数だけで使える お手軽な期限付きキャッシュ
- 標準では
wp_optionsに保存、Redis/Memcached 環境では自動的にメモリへ移行 - ただし 「最大期限」「遅延 GC」「永続性なし」 の3点を理解しないと事故る
- 動的キー × 大量アクセスのサイトは、自前 GC をスケジュールする のが必須
- 業務データには使わず、「再計算可能な読み取りキャッシュ」専用 と割り切る
中規模以上の WordPress を運用しているなら、Redis Object Cache + Transients API + 自前 GC の3点セットがほぼ万能解です。逆に、何も考えずに動的キーで Transients を散らすと wp_options 肥大化のサイレントキラー になりかねません。本番投入前に、必ず本記事のワナ章を一読してから採用してください。
参考リンク
- 公式 API ハンドブック:Transients - Common APIs Handbook
- WordPress Developer Blog:An introduction to the Transients API(2024年6月)
- 関数リファレンス:set_transient() / get_transient() / delete_transient() / set_site_transient()
- WP-CLI:wp transient コマンド
- 落とし穴解説:The Hidden Pitfall of Lazy Garbage Collection
- CSS-Tricks:The Deal with WordPress Transients
- Object Cache:Redis Object Cache(公式プラグイン)