WP Rocket 多言語キャッシュ:下書き保存のたびに翻訳版のキャッシュが消える原因と解決

公正取引委員会の広告文 Ver 3.1
公正取引委員会の広告文 Ver 3.2(モバイル専用)
テスト環境 RHEL系AlmaLinux 9.8Nginx 1.28 + Apache 2.4WP Rocket 3.23.5.1TranslatePress 3.3.82026-10-17 確認

WP Rocketの多言語キャッシュは、TranslatePressの翻訳版アドレスごとに言語フォルダの下へ別々に保存されるページキャッシュです。Nginx + Apache構成のWordPressサーバーで、下書きを保存するたびに翻訳版キャッシュが言語フォルダごと消える原因をWP Rocketのコードで追跡した結果、公開されていない投稿を翻訳版キャッシュの削除から外し、直接削除したアドレスはプリロードに改めて知らせるコードで解決しました。

同じサーバー内で測った最初のバイトまでの時間は、翻訳版キャッシュがあるときは0.015秒、ないときは2.492秒でした。言語フォルダが空になると、誰かがそのアドレスを開き直してキャッシュが作られるまで、翻訳版の訪問者はこの遅い応答を受けることになります。

1️⃣ WP Rocket 多言語キャッシュの構造:言語別フォルダと翻訳版の削除

翻訳版は原文の投稿を翻訳して見せる画面なので、キャッシュも原文とひとまとまりだと考えがちですが、WP Rocketは翻訳版のアドレスを別のページとしてキャッシュします。キャッシュフォルダの下には原文の投稿フォルダと並んで[en]・[ja]のような言語フォルダができ、翻訳版の投稿はその中に翻訳スラッグの名前で保存されます。

wp-content/cache/wp-rocket/example.com/
sample-post/原文の投稿
index-https.html
index-mobile-https.html
en/英語の言語フォルダ
index-https.html英語の言語ホーム
sample-post-en/英語の翻訳版の投稿(翻訳スラッグ)
index-https.html
index-mobile-https.html
ja/日本語の言語フォルダ
index-https.html
sample-post-ja/

投稿を編集すると、WP RocketのTranslatePress連携がその投稿の翻訳版キャッシュも一緒に削除します。公式ドキュメントでも、通常の編集ではすべての翻訳版を、TranslatePressの翻訳エディターで直した場合は変わった言語だけを削除すると案内しています。

// wp-rocket/inc/ThirdParty/Plugins/I18n/TranslatePress.php (3.23.5.1)
'post_updated' => 'clear_post_languages',            // 投稿が保存されるたびに実行

public function clear_post_languages( $post_id ) {
    // …
    $default_permalink = get_permalink( $post_id );   // 投稿の状態は確認しない

    foreach ( $trp_settings['translation-languages'] as $language ) {
        if ( $language === $trp_settings['default-language'] ) {
            continue;
        }
        $clear_urls[] = $converter->get_url_for_language( $language, $default_permalink, '' );
    }
    // …
    rocket_clean_files( $clear_urls );
}

連携関数は投稿のアドレスを言語ごとに翻訳版のアドレスへ変換してから、キャッシュファイルを整理する関数[rocket_clean_files]に渡します。この過程に投稿の状態を確認する行がないため、公開済みの投稿でも下書きでも同じ手順で翻訳版のアドレスを作って削除することになります。

2️⃣ 下書きの保存:言語フォルダ全体の削除

下書きの保存は翻訳版キャッシュと無関係ではありません。公開前の投稿のパーマリンクはスラッグではなく[?p=投稿番号]の形で、TranslatePressがこのアドレスを[/en/?p=投稿番号]のように言語パスを付けたアドレスへ変換するためです。

下書きの保存エディターで保存・サーバーでwp_update_post・タイトルだけ変更
post_updated
clear_post_languages( 123 )WP Rocket TranslatePress連携
get_permalink()→ https://example.com/?p=123 · 公開前なのでスラッグなし
get_url_for_language()→ https://example.com/en/?p=123(ja・es・deも同じ)
rocket_clean_files()
クエリ ?p=123 を除外→ パス /en/
キャッシュの場所→ wp-content/cache/wp-rocket/example.com/en/
フォルダなので再帰的に削除→ 英語の翻訳版キャッシュがすべて削除

[rocket_clean_files]はアドレスからクエリを除き、パスだけでキャッシュの場所を探します。残ったパスが[/en/]ならその言語のキャッシュフォルダ全体になり、対象がフォルダなら下位フォルダまで再帰的に削除します。

// wp-rocket/inc/functions/files.php (3.23.5.1) — rocket_clean_files() の中
$parsed_url = get_rocket_parse_url( $url );               // パスとクエリを分ける
// …
$entry = $dir . $parsed_url['path'];                      // …/example.com/en/
// …
if ( $filesystem->is_dir( $entry ) ) {
    rocket_rrmdir( $entry, [], $filesystem );             // フォルダごと再帰的に削除
} else {
    $filesystem->delete( $entry );
}

トップページも同じ経路を通ります。トップのアドレス[/]が[/en/]に変換されるため、公開済みのトップページを保存しても言語フォルダ全体が削除されます。下書きのタイトルだけ直して保存し直しても4言語のキャッシュフォルダがすべて空になり、下書きの保存が集中した一晩で同じ削除が30回以上繰り返されたことを、保存時刻とキャッシュ削除の記録で確認しました。

🧭 投稿の保存と翻訳版キャッシュの削除
WP Rocket解説ダイアグラム
📝 保存した投稿
📝 パーマリンク
[get_permalink]
/sample-post/公開済みの投稿・スラッグのアドレス
/?p=123公開前・自動保存のリビジョンも同じ
/トップページ
post_updated→
🌐 翻訳版のアドレス
TranslatePressの言語パス
/en/sample-post-en/
/en/?p=123
/en/
ja・es・deも同じ
✅ パス /en/sample-post-en/・その投稿のフォルダ
❌ ?p=123 を除外・パス /en/ だけが残る
❌ パス /en/・言語フォルダ
rocket_clean_files→
🗑️ 削除されるキャッシュ
① その投稿の翻訳版フォルダだけen/sample-post-en/言語ホームとほかの投稿の翻訳版はそのまま
② 言語フォルダ全体en/言語ホーム・ほかの投稿の翻訳版まで・20個 → 0個
公開済みの投稿はパーマリンクがスラッグなので翻訳版のアドレスもその投稿を指し、その投稿の翻訳版キャッシュフォルダだけが削除されます。
下書きのパーマリンクは[?p=123]の形なので、翻訳版のアドレスは[/en/?p=123]になります。[rocket_clean_files]がクエリを除くと[/en/]だけが残って英語の言語フォルダ全体が削除され、エディターの自動保存のリビジョンも同じアドレスを使います。
トップページのアドレス[/]は[/en/]に変換されるため、公開済みのトップページを保存しても言語フォルダ全体が削除されます。

コード上、エディターの自動保存も同じ経路です。公開済みの投稿を編集している間に保存されるリビジョンも[?p=]の形のアドレスを使います。

Nginx + Apache構成のテストサイトで、公開済みの投稿をエディターで直しながら言語フォルダのファイル数を確認しました。最初の自動保存では英語・日本語フォルダがそれぞれ20個のままで、1分後の2回目の自動保存で両方のフォルダが0個になりました。

最初の自動保存はリビジョンを新しく作り、2回目からは同じリビジョンを直して保存するため[post_updated]が実行されます。最初の自動保存の後も本文を直し続けると、保存ボタンを押さなくても翻訳版キャッシュが言語フォルダごと削除されます。

WP Rocketの公式リポジトリにも同じ症状が2023年8月31日からIssue #6130として開かれています。修正するプルリクエスト#7616は2025年9月に出されましたがマージされておらず、2026年10月2日に出た3.23.5.1の変更履歴にも修正は入っていません。

3️⃣ 解決コード:公開済みの投稿だけ翻訳版のキャッシュを削除

公式の修正が出るまでは、連携関数を外し、アドレスが確実な場合にだけ翻訳版を削除する関数で置き換えることになります。Issueのコメントに投稿された回避策も、公開されていない投稿なら連携関数からすぐ抜ける同じ方向です。

ただし、投稿の状態だけを確認する条件では2つのケースが残ります。トップページは公開状態でも保存すると言語フォルダ全体を消し、公開済みの投稿を下書きに戻すと翻訳版キャッシュが削除されないため、戻した投稿が翻訳版のアドレスで開き続けます。

<?php
/**
 * Plugin Name: Rocket TranslatePress Draft Fix
 * Description: WP Rocket TranslatePress連携の翻訳版キャッシュ削除を、アドレスが確実な場合に限定
 */

// 1. WP Rocketの連携関数をpost_updatedから外して保管
add_action( 'init', function () {
    global $wp_filter;
    if ( empty( $wp_filter['post_updated'] ) ) {
        return;
    }
    foreach ( $wp_filter['post_updated']->callbacks as $priority => $callbacks ) {
        foreach ( $callbacks as $cb ) {
            $fn = $cb['function'];
            if ( is_array( $fn ) && is_object( $fn[0] )
                && 0 === strpos( get_class( $fn[0] ), 'WP_Rocket\\' )
                && false !== stripos( get_class( $fn[0] ), 'TranslatePress' ) ) {
                remove_action( 'post_updated', $fn, $priority );
                $GLOBALS['rtdf_original'] = $fn;
            }
        }
    }
}, 9999 );

// 2. 代わりの関数
add_action( 'post_updated', function ( $post_id, $after, $before ) {
    if ( empty( $GLOBALS['rtdf_original'] ) || ! class_exists( 'TRP_Translate_Press' ) ) {
        return;
    }
    $trp       = TRP_Translate_Press::get_trp_instance();
    $converter = $trp->get_component( 'url_converter' );
    $settings  = $trp->get_component( 'settings' )->get_settings();
    $languages = array_diff( $settings['translation-languages'], [ $settings['default-language'] ] );

    // トップページ — 言語フォルダではなく言語ホームのキャッシュファイルだけ
    if ( 'page' === get_option( 'show_on_front' ) && (int) get_option( 'page_on_front' ) === (int) $post_id ) {
        $urls = [];
        add_filter( 'trp_add_language_to_home_url_check_for_admin', '__return_false' );
        foreach ( $languages as $lang ) {
            $home = $converter->get_url_for_language( $lang, home_url( '/' ), '' );
            $dir  = WP_ROCKET_CACHE_PATH . wp_parse_url( $home, PHP_URL_HOST ) . wp_parse_url( $home, PHP_URL_PATH );
            array_map( 'unlink', glob( $dir . 'index*.html*' ) ?: [] );
            $urls[] = $home;
        }
        remove_filter( 'trp_add_language_to_home_url_check_for_admin', '__return_false' );
        do_action( 'rocket_after_clean_terms', $urls );   // プリロードに通知(5️⃣)
        return;
    }

    // 公開済みの投稿の保存 — WP Rocketの元の関数をそのまま
    if ( 'publish' === $after->post_status ) {
        call_user_func( $GLOBALS['rtdf_original'], $post_id );
        return;
    }

    // 公開 → 下書き・非公開・ゴミ箱 — 取り下げる前のアドレスの翻訳版だけ
    if ( 'publish' === $before->post_status ) {
        $old  = get_permalink( $before );
        $urls = [];
        add_filter( 'trp_add_language_to_home_url_check_for_admin', '__return_false' );
        foreach ( $languages as $lang ) {
            $urls[] = $converter->get_url_for_language( $lang, $old, '' );
        }
        remove_filter( 'trp_add_language_to_home_url_check_for_admin', '__return_false' );
        rocket_clean_files( $urls );
    }

    // それ以外(下書き・リビジョン・自動保存)は翻訳版のアドレスがないので削除しない
}, 10, 3 );

最初の部分はWP Rocketが登録した連携関数を見つけて[post_updated]から外し、元の関数は保管しておきます。代わりの関数は、トップページなら言語ホームのキャッシュファイルだけを消し、公開済みの投稿なら保管した元の関数をそのまま実行し、公開済みの投稿を取り下げた場合は取り下げる前のアドレスで翻訳版を探して削除します。

[wp-content/mu-plugins/]フォルダにPHPファイルとして保存すると有効化なしですぐに適用され、ファイルを消せばWP Rocket本来の動作に戻ります。同じ動作のコードで試した結果、下書きを保存し直しても言語フォルダのファイル数はそのままで、公開済みの投稿を保存し直すとその投稿の原文と翻訳版のフォルダだけが消えました。

上のコードを入れる前と入れた後で、同じ環境の4つのケースについて言語フォルダのファイル数を比べました。英語・日本語フォルダには、言語ホームと投稿4本のPC・モバイルのキャッシュがそれぞれ20個ありました。

コードを入れる前は、下書きの保存、トップページの保存、公開の取り消しの3つのケースすべてで両方のフォルダが0個になり、公開済みの投稿の保存だけがその投稿の翻訳版キャッシュを削除しました。

コードを入れた後は、下書きの保存とエディターの自動保存で20個がそのまま残りました。トップページの保存では言語ホームのキャッシュ4個、公開済みの投稿の保存と公開の取り消しではその投稿の翻訳版4個だけが削除されて16個が残り、取り下げた投稿の英語の翻訳版アドレスは404を返しました。

ケース修正前コードを入れた後入れた後に削除されたキャッシュ
下書きの保存20 → 020 → 20なし
公開済みの投稿の保存その投稿の翻訳版だけ削除20 → 16その投稿の翻訳版4個
トップページの保存20 → 020 → 16言語ホームのキャッシュ4個
公開の取り消し20 → 020 → 16その投稿の翻訳版4個・翻訳版のアドレスは404

4️⃣ プリロード再生成の漏れ:キューに残る完了状態

下書きの保存を防いでも、WP Rocketの関数の削除シグナルなしに消したキャッシュファイルはプリロードが再び埋めません。 WP Rocketのプリロードは、アドレスごとに状態を記録するキューのテーブルを使い、リクエスト予定のアドレスは待機、リクエストを送ったアドレスは進行中、キャッシュが作られたアドレスは完了に変わり、3分以内に終わらなければ失敗になります。

完了したアドレスが待機に戻るのは、キャッシュの寿命が尽きて消えたファイル、WP Rocketが削除しながら削除シグナルを出したアドレス、失敗してから12時間が過ぎたアドレスの3つです。[rocket_clean_files]の3番目の引数にfalseを渡すか、ファイルを直接削除するとこのシグナルが出ないため、キューには完了のまま残り、キャッシュファイルだけが消えます。

3番目の引数は、削除シグナルを受けてほかのキャッシュを続けて消すコードが、繰り返し呼び出しを防ぐためにfalseで渡すことになります。翻訳版キャッシュを照合した時点で、英語の翻訳版65個のうち3個、日本語の翻訳版65個のうち7個が、キューには完了のまま残ってキャッシュファイルだけがありませんでした。

WP Rocketのサポートチームの貢献者も、Issue #6130のコメントで、キャッシュを消した後にテーブルのアドレスが完了のまま残って状態がずれることを認めました。テーブルとキャッシュファイルを定期的に合わせようという提案(#2939)は、2020年に実装されないまま閉じられています。

5️⃣ プリロードへの再登録:直接削除したアドレスをキューに知らせる

直接削除したアドレスは、削除した直後にプリロードへ知らせる1行で解決します。プリロードは[rocket_after_clean_terms]シグナルを受けると、受け取ったアドレスを待機状態に戻し、テーブルにないアドレスは新しく追加します。

// 削除シグナルなしで消した後 — 消したアドレスの配列をプリロードのキューに再登録
rocket_clean_files( $urls, null, false );          // 3番目の引数 false = 削除シグナルなし
do_action( 'rocket_after_clean_terms', $urls );     // プリロードがこれらのアドレスを待機(pending)に

WP Rocketの中でこのシグナルを受け取るのはプリロードのキュー関数とSpinUpWPホスティング連携だけで、プリロード関数はキューの行を直すだけでWP Rocketのキャッシュファイルを消したり削除シグナルを再び出したりしないため、繰り返し呼び出しは起きません。キャッシュをWP Rocketの関数だけで消し、3番目の引数を既定値のままにしているサイトは、すでにシグナルが出るのでこの行は必要ありません。

この行を入れた後、翻訳版が4言語ある投稿1本のキャッシュを消すと、2秒以内にキューの行4つが待機に変わりました。cronを1分ごとに実行するサーバーで2回試し、101秒後と153秒後に翻訳版のPC・モバイルのキャッシュファイル8個がすべて作り直されました。確認はキューのテーブルの状態とキャッシュフォルダのファイルで行います。

# キューのテーブルでのそのアドレスの状態(テーブル名の前の wp_ はサイトの接頭辞)
wp db query <<'SQL'
SELECT url, status, modified FROM wp_wpr_rocket_cache WHERE url LIKE '%/en/sample-post-en'
SQL
url	status	modified
https://example.com/en/sample-post-en	pending	2026-10-17 09:10:48
# 1分ほど後にキャッシュファイルが再び作られたか
ls -l wp-content/cache/wp-rocket/example.com/en/sample-post-en/
total 240
-rw-r--r-- 1 example nobody 95084 Oct 17 18:12 index-https.html
-rw-r--r-- 1 example nobody 22352 Oct 17 18:12 index-https.html_gzip
-rw-r--r-- 1 example nobody 95083 Oct 17 18:12 index-mobile-https.html
-rw-r--r-- 1 example nobody 22348 Oct 17 18:12 index-mobile-https.html_gzip

削除した直後は状態が[pending]に変わり、プリロードがリクエストを送ってキャッシュファイルができると[completed]になります。状態が[completed]なのにキャッシュファイルがなければ、そのアドレスはシグナルなしで消されたものです。

トップページを保存して上のコードが言語ホームのキャッシュファイルを消してシグナルを出すと、英語・日本語のホームのアドレスが再びキューに入りました。言語ホームのPC・モバイルのキャッシュは、遅くとも2回目のcron実行で作り直されました。

2回試して、保存から最後のキャッシュファイルまで47秒と91秒かかりました。

🔢 FAQ & おすすめコンテンツ

この記事はWP RocketのTranslatePress連携を基準にしており、WPML・Polylangの連携は確認していません。ほかのキャッシュプラグインとPolylangの組み合わせでも、クエリだけが残ったアドレスがキャッシュの最上位フォルダに変換されて丸ごと消えた事例が2026年7月にWordPress.orgのサポートフォーラムに投稿されており、その事例も該当のコールバックを外して包むコードで解決しています。

2026年10月16日にWP Rocketのリポジトリで開かれたIssue #9028です。プリロードがキャッシュを記録するときに翻訳スラッグのアドレスではなく元のスラッグのアドレスで記録するため、翻訳版アドレスの行は完了状態と最終アクセス時刻を受け取れず、1か月アクセスのない行を消す週1回の整理作業で一緒に削除されます。期間は[rocket_preload_delay_delete_non_accessed]フィルターで延ばせ、公式ドキュメントの例は1年で、修正する下書き#9029は2026年10月17日時点でマージされていません。

Issue #6130の修正が変更履歴に載り、連携関数が投稿の状態やクエリのアドレスを確認するようになれば外せます。関数名や登録フックが変わると外すコードが対象を見つけられず元の動作がそのまま残るため、更新後は下書きを1つ保存して言語フォルダがそのままか確認します。

🧭 WP Rocket・Perfmatters関連記事 記事15・ツール3
🗂️ WPとは?
📋 WP Rocket設定ガイド 📄 Perfmattersガイド 📄 WP Rocket With Perfmatters 📄 WP Rocket MCP Server 📄 WP Rocket 韓国語URL 📄 nginx njs 📄 WP Rocket 多言語キャッシュ 📄 gclid キャッシュ
📄 WP Rocket速度テスト 📝 キャッシュ・最適化プラグイン 📝 速度改善の事例
📋 キャッシュ:定義とすべての分野 📄 ウェブサイトキャッシュ&サーバー内部キャッシュ
📋 BESTホスティングTOP 7 📄 高速ホスティング2026
🛠️ WordPressの検出 🛠️ Whoisドメイン検索 🛠️ 自分のIPアドレスを確認する
WP Rocket設定ガイド:メニュー別の基本設定と20% Promo Code
WordPress · WP Rocket
WP Rocket設定ガイド:メニュー別の基本設定と20% Promo Code
WP Rocketのメニューごとの基本設定と料金をまとめた記事です。
記事を見る →現在の記事
Perfmattersプラグインのレビュー & ガイド:5年間使ったWordPressパフォーマンス最適化の設定方法
WordPress · Perfmatters
Perfmattersプラグインのレビュー & ガイド:5年間使ったWordPressパフォーマンス最適化の設定方法
Perfmattersのメニューごとの推奨設定とScript Managerの使い方です。
記事を見る →現在の記事
WP Rocket With Perfmattersの使い方:最適化機能の設定ガイド
WordPress · Perfmatters
WP Rocket With Perfmattersの使い方:最適化機能の設定ガイド
WP RocketとPerfmattersを併用するときの設定方法です。
記事を見る →現在の記事
WP Rocket MCP Server:AIツールでキャッシュと設定を扱う
WordPress · MCP
WP Rocket MCP Server:AIツールでキャッシュと設定を扱う
AIツールからWP Rocketのキャッシュと設定を扱う方法です。
記事を見る →現在の記事
WP Rocket 韓国語URLのリクエストの流れ図
WordPress · WP Rocket
WP Rocket 韓国語URL
韓国語URLへのリクエストでエンコードの大文字・小文字が違うためにnginxがキャッシュファイルを見つけられない原因と、njsで直す方法です。
記事を見る →現在の記事
nginx njs の変数とキャッシュファイルのパスの図
Server · nginx
nginx njs:モジュールのインストールと js_set の設定、reload の適用で JavaScript 変数を作る
nginx の設定の中で JavaScript 関数から変数を作る njs モジュールをインストールし、js_set 変数を reload で適用する方法です。
記事を見る →現在の記事
WP Rocket 多言語キャッシュの記事保存の流れ図
WordPress · WP Rocket
WP Rocket 多言語キャッシュ
下書きを保存すると翻訳版のキャッシュが言語フォルダごと削除される原因と、それを防ぐコードです。
記事を見る →現在の記事
広告クエリ付きのリクエストが CDN にコピーがないとき元のサーバーへ渡り、nginx から Apache に移った後、WP Rocket が広告クエリを外して同じキャッシュファイルで応答する流れ
Server・キャッシュ
gclid キャッシュ:広告クリックのクエリとページキャッシュキー、最初のバイトの実測
広告クリックの URL 末尾に付く gclid クエリを無視し、クエリのない URL のキャッシュファイルで応答する動作を、最初のバイトまでの時間で測った記事です。
記事を見る →現在の記事

ℹ️ 提携について
当サイトのコンテンツにはアフィリエイトリンクが含まれています。訪問者がこのリンクを通じて商品やサービスを購入すると、当サイトは販売元から手数料を受け取ります。この過程において、購入者が支払う金額(イベント割引適用で金額が下がります↓)は上昇しません。掲載されている価格・割引・在庫情報は作成時点のものであり、実際とは異なる場合がありますので、ご購入前に販売元にて最終確認をお願いいたします。商品の選定および評価は独自の基準に基づいて行われており、手数料の支払いの有無は紹介順や評価内容に影響を与えません。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

人間であることを証明してください: 8   +   8   =