結論
- transient(
set_transient): 有効期限つきで保存する仕組み。外部オブジェクトキャッシュが無ければwp_optionsテーブルに保存され、リクエストをまたいで残ります。外部オブジェクトキャッシュがあれば、そちらに保存されます。 - オブジェクトキャッシュ(
wp_cache_set): 既定ではメモリ上にだけ置かれ、そのリクエストが終われば消えます。Redis や Memcached などの永続バックエンドを入れたときに、はじめてリクエストをまたいで残ります。
「外部 API の結果を数分〜数時間保持したい」なら transient、「同じリクエスト内で同じ重い処理を2回しない」ならオブジェクトキャッシュ、が基本の使い分けです。
原因・仕組み
公式リファレンスによると、set_transient( $transient, $value, $expiration ) の名前は172文字まで、期限は秒数で、0(既定)は期限なしです。外部オブジェクトキャッシュが有効な場合、transient はデータベースを使わずそのキャッシュに保存されます。また、期限なしの transient は autoload(毎ページ読み込み)の対象になり、期限つきのものは対象になりません。
一方 wp_cache_set( $key, $data, $group, $expire ) は WordPress が内部で使っているキャッシュ API で、投稿やオプションの取得結果もここに入っています。永続化は差し込まれたバックエンド次第です。つまり、テーマやプラグインの作者は、サイトにどちらがあるか分からない前提で書く必要があります。
手順(サンプルコード)
外部 API の結果を1時間 transient に保存する典型例です。
function my_get_rates() {
$rates = get_transient( 'my_rates' );
if ( false !== $rates ) {
return $rates;
}
$res = wp_remote_get( 'https://example.com/api/rates' );
if ( is_wp_error( $res ) || 200 !== wp_remote_retrieve_response_code( $res ) ) {
return array(); // 失敗は保存しない(または短い期限で保存)
}
$rates = json_decode( wp_remote_retrieve_body( $res ), true );
set_transient( 'my_rates', $rates, HOUR_IN_SECONDS );
return $rates;
}
同じリクエスト内の重複計算を避けるには、オブジェクトキャッシュを使います。$found を受け取ると、false や空配列を保存した場合も区別できます。
function my_expensive_count() {
$count = wp_cache_get( 'my_count', 'my_plugin', false, $found );
if ( $found ) {
return $count;
}
$count = my_heavy_query();
wp_cache_set( 'my_count', $count, 'my_plugin' );
return $count;
}
データを更新したときは、delete_transient( 'my_rates' ) や wp_cache_delete( 'my_count', 'my_plugin' ) で古い値を消します。
動作確認(検証環境と結果)
WordPress 7.1.2(ja)/PHP 8.2.12/MariaDB 10.4.32、外部オブジェクトキャッシュなしの環境で、run.php から実行しました(tests フォルダの p2.php)。
same request: 'v'
transient: {"a":1}
options row: true
timeout row: future
autoload: off
miss hit
set_transientの値はwp_optionsに_transient_demo_tとして保存され、期限(_transient_timeout_demo_t)は未来の時刻でした。期限つきの autoload はoffでした。wp_cache_getの2回呼びは、1回目が miss、2回目が hit でした。- レビュー時に、1回目の実行で
wp_cache_set( 'rp2k', 'v', 'rp2g' )し、別プロセスの2回目の実行でwp_cache_get()したところ、値はfalse、$foundもfalseでした。外部オブジェクトキャッシュが無い環境では、wp_cache の値は次のリクエストに残りません。
transient とオブジェクトキャッシュの違いの注意点
- transient の期限は「最短でこの時間は残さない」ではなく、期限を過ぎても自動では消えない場合があります(期限切れ行は取得時や掃除処理で削除されます)。期限を過ぎた値は
get_transientがfalseを返すだけだと考えてください。 - 外部キャッシュの有無で保存先が変わるため、「
wp_optionsに transient がある前提」でデータベースを直接読む実装は避けます。 - 保存する値が
falseだと、未保存と区別できません。falseを入れたいときは配列に包むか、0や空文字を使います。 - 既存の transient を期限指定なし(
0)でset_transient()し直すと、値だけが更新され、前回の期限はそのまま残ります(レビュー時の検証: 60秒で保存→期限なしで再保存→_transient_timeout_は残り約60秒のまま、値は新しいもの)。期限を延ばしたいときは、更新時も期限を渡します。
transient とオブジェクトキャッシュの違いでよくあるミス
wp_cache_setを「永続キャッシュ」と思い込み、次のリクエストでも残ると期待する。- 利用者ごとに異なる値を共通のキー名で transient に入れる。キーにユーザーIDやパラメータのハッシュを含めます。
- 失敗した API 応答をそのまま1時間保存してしまい、復旧後も古いエラーが返る。
- 管理画面で更新した設定が反映されない原因が、削除し忘れた transient だった、というケース。
transient とオブジェクトキャッシュの違いのチェックリスト
- [ ] リクエストをまたいで残したい値は transient(または option)にしている
- [ ] 同一リクエスト内の重複処理は
wp_cache_*で省いている - [ ] キー名に衝突しない接頭辞を付けた(172文字以内)
- [ ] 更新時に古いキャッシュを削除する処理がある
- [ ]
falseを保存する場合の区別方法を決めた
transient とオブジェクトキャッシュの違いのFAQ(よくある質問)
Q. transient と option はどちらがよいですか。
A. 期限が必要で再取得できる値は transient、設定値のように消えては困るものは option です。
Q. 外部オブジェクトキャッシュを入れると、コードは変えるべきですか。
A. 基本的に不要です。同じ API のまま、保存先だけが切り替わります。
Q. マルチサイトでは。
A. サイト全体で共有したい値には set_site_transient を使います。
筆者の見解(transient とオブジェクトキャッシュの違い)
私見では、迷ったときは「消えても再生成できる値か」で判断するのが分かりやすいと考えます。再生成できて、しかも複数リクエストで使い回したいなら transient、リクエスト内だけなら wp_cache_*、消えると困るなら option です。外部キャッシュの有無は環境次第なので、どちらの環境でも動く書き方にしておくのが無難です。
transient とオブジェクトキャッシュの違いの関連項目
- set_transient() の使い方|説明・引数・注意点
- get_transient() の使い方|説明・引数・注意点
- delete_transient() の使い方|説明・引数・注意点
- wp_cache_set() の使い方|説明・引数・注意点
- wp_cache_get() の使い方|説明・引数・注意点
