WP Rocket çok dilli önbellek: Taslak kaydedilince çeviri sayfalarının önbelleğinin silinme nedeni ve çözümü

WP Rocket çok dilli önbelleği, TranslatePress'in her çeviri adresi için dil klasörü altında ayrı saklanan sayfa önbelleğidir. Nginx + Apache yapılandırmalı bir WordPress sunucusunda her taslak kaydında çeviri sayfası önbelleğinin dil klasörüyle birlikte neden silindiğini WP Rocket kodunda izledik ve yayımlanmamış yazıları çeviri sayfası önbelleği silme işleminden çıkaran, kendi sildiğimiz adresleri ön yüklemeye yeniden bildiren kodla çözdük.
Aynı sunucu içinde ölçülen ilk bayt süresi çeviri sayfası önbelleği varken 0,015 saniye, yokken 2,492 saniyeydi. Dil klasörü boşalınca çeviri sayfası ziyaretçileri, biri adresi yeniden açıp önbellek oluşana kadar bu yavaş yanıtı alır.
1️⃣ WP Rocket çok dilli önbellek yapısı: dil klasörleri ve çeviri sayfalarını silme
Çeviri sayfası özgün yazıyı çevirerek gösterdiği için önbelleğinin de özgün yazıyla bir arada olduğunu düşünmek kolaydır, ama WP Rocket çeviri adreslerini ayrı sayfalar olarak önbelleğe alır. Önbellek klasörü altında özgün yazı klasörlerinin yanında [en] ve [ja] gibi dil klasörleri oluşur; çevrilmiş yazılar bunların içinde çeviri kısa adlarıyla saklanır.
Bir yazıyı düzenlediğinizde WP Rocket'ın TranslatePress entegrasyonu o yazının çeviri sayfası önbelleğini de siler. Resmî belgeler de normal düzenlemenin tüm çevirileri, TranslatePress çeviri düzenleyicisinde yapılan düzenlemenin ise yalnızca değişen dili sildiğini belirtir.
// wp-rocket/inc/ThirdParty/Plugins/I18n/TranslatePress.php (3.23.5.1)
'post_updated' => 'clear_post_languages', // her yazı kaydında çalışır
public function clear_post_languages( $post_id ) {
// …
$default_permalink = get_permalink( $post_id ); // yazı durumu kontrol edilmez
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 );
}Entegrasyon işlevi yazı adresini her dil için çeviri adresine dönüştürür ve önbellek temizleme işlevi [rocket_clean_files]'a verir. Bu süreçte yazı durumunu kontrol eden bir satır olmadığından yazı yayımlanmış da olsa taslak da olsa çeviri adresleri aynı sırayla oluşturulup silinir.
2️⃣ Taslak kaydetme: dil klasörünün tamamı silinir
Taslak kaydetmek çeviri sayfası önbelleğiyle ilgisiz değildir. Yayımlanmadan önce yazının kalıcı bağlantısı kısa ad değil [?p=yazı kimliği] biçimindedir ve TranslatePress bu adresi [/en/?p=yazı kimliği] gibi dil yolu eklenmiş bir adrese dönüştürür.
[rocket_clean_files] adresteki sorguyu çıkarır ve önbellek konumunu yalnızca yola göre bulur. Kalan yol [/en/] ise bu o dilin önbellek klasörünün tamamı demektir; hedef bir klasörse alt klasörleriyle birlikte özyinelemeli silinir.
// wp-rocket/inc/functions/files.php (3.23.5.1) — rocket_clean_files() içinde
$parsed_url = get_rocket_parse_url( $url ); // yolu ve sorguyu ayırır
// …
$entry = $dir . $parsed_url['path']; // …/example.com/en/
// …
if ( $filesystem->is_dir( $entry ) ) {
rocket_rrmdir( $entry, [], $filesystem ); // klasörü tamamen özyinelemeli siler
} else {
$filesystem->delete( $entry );
}Ana sayfa da aynı yoldan geçer. [/] adresi [/en/]'e dönüştüğü için yayımlanmış ana sayfayı kaydetmek bile dil klasörünün tamamını siler. Yalnızca bir taslağın başlığını değiştirip yeniden kaydetmek dört dilin önbellek klasörlerinin hepsini boşalttı; taslak kayıtlarının yoğunlaştığı bir gecede aynı silmenin 30'dan fazla tekrarlandığını kayıt saatleri ve önbellek silme kayıtlarıyla doğruladık.
Kodda düzenleyicinin otomatik kaydı da aynı yoldan geçer. Yayımlanmış yazıyı düzenlerken kaydedilen revizyonlar da [?p=] biçiminde adres kullanır.
Nginx + Apache yapılandırmalı bir test sitesinde yayımlanmış bir yazıyı düzenleyicide düzenlerken dil klasörlerindeki dosya sayısını izledik. İlk otomatik kayıttan sonra İngilizce ve Japonca klasörlerde hâlâ 20'şer dosya vardı; bir dakika sonraki ikinci otomatik kayıtta iki klasör de 0 oldu.
İlk otomatik kayıt yeni bir revizyon oluşturur, ikinciden itibaren aynı revizyon güncellenip kaydedilir ve [post_updated] çalışır. İlk otomatik kayıttan sonra düzenlemeye devam ederseniz kaydet düğmesine basmasanız bile çeviri sayfası önbelleği dil klasörüyle birlikte silinir.
Aynı belirti WP Rocket'ın resmî deposunda 31 Ağustos 2023'ten beri #6130 numaralı konu olarak açık. Düzeltmek için gönderilen #7616 çekme isteği Eylül 2025'te açıldı ama birleştirilmedi; 2 Ekim 2026'da çıkan 3.23.5.1 değişiklik kaydında da düzeltme yok.
3️⃣ Çözüm kodu: çeviri sayfası önbelleğini yalnızca yayımlanmış yazılar için silme
Resmî düzeltme gelene kadar entegrasyon işlevini ayırıp yalnızca adres kesin olduğunda çeviri sayfalarını silen bir işlevle değiştirirsiniz. Konu yorumlarında paylaşılan geçici çözüm de yazı yayımlanmamışsa entegrasyon işlevinden hemen çıkan aynı yöndedir.
Ancak yalnızca yazı durumunu kontrol eden bir koşulla iki durum kalır. Ana sayfa yayımlanmış olsa da kaydedildiğinde dil klasörünün tamamını siler; yayımlanmış bir yazıyı taslağa geri alırsanız çeviri sayfası önbelleği silinmez ve geri alınan yazı çeviri adreslerinde açılmaya devam eder.
<?php
/**
* Plugin Name: Rocket TranslatePress Draft Fix
* Description: WP Rocket TranslatePress entegrasyonunun çeviri sayfası önbelleği silmesini adresin kesin olduğu durumlarla sınırlar
*/
// 1. WP Rocket entegrasyon işlevini post_updated'dan ayır ve sakla
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. Yerine geçen işlev
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'] ] );
// Ana sayfa — dil klasörü değil, yalnızca dil ana sayfası önbellek dosyaları
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 ); // ön yüklemeye bildir (5️⃣)
return;
}
// Yayımlanmış yazı kaydı — WP Rocket'ın özgün işlevi olduğu gibi
if ( 'publish' === $after->post_status ) {
call_user_func( $GLOBALS['rtdf_original'], $post_id );
return;
}
// Yayımlanmış → taslak·özel·çöp — yalnızca geri almadan önceki adresin çeviri sayfaları
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 );
}
// Diğerleri (taslak·revizyon·otomatik kayıt) çeviri adresi olmadığından silinmez
}, 10, 3 );İlk bölüm WP Rocket'ın kaydettiği entegrasyon işlevini bulup [post_updated]'dan ayırır ve özgün işlevi saklar. Yerine geçen işlev ana sayfada yalnızca dil ana sayfasının önbellek dosyalarını siler, yayımlanmış yazılarda saklanan özgün işlevi olduğu gibi çalıştırır, yayımlanmış yazı geri alındığında da geri almadan önceki adresle çeviri sayfalarını bulup siler.
[wp-content/mu-plugins/] klasörüne PHP dosyası olarak kaydedilince etkinleştirme gerekmeden hemen uygulanır; dosyayı silince WP Rocket özgün davranışına döner. Aynı şekilde çalışan kodla yaptığımız testte taslağı yeniden kaydetmek dil klasörlerindeki dosya sayısını değiştirmedi; yayımlanmış yazıyı yeniden kaydetmek yalnızca o yazının özgün ve çeviri sayfası klasörlerini sildi.
Yukarıdaki kodu eklemeden önce ve sonra aynı ortamda dört durum için dil klasörlerindeki dosya sayısını karşılaştırdık. İngilizce ve Japonca klasörlerde dil ana sayfası ve dört yazının PC ve mobil önbellekleri 20'şer dosyaydı.
Kodu eklemeden önce taslak kaydetme, ana sayfa kaydetme ve yayımdan kaldırma üç durumda da iki klasörü 0'a indirdi; yalnızca yayımlanmış yazı kaydı sadece o yazının çeviri sayfası önbelleğini sildi.
Kodu ekledikten sonra taslak kaydında ve düzenleyicinin otomatik kaydında 20 dosyanın hepsi kaldı. Ana sayfa kaydı dil ana sayfasının 4 önbellek dosyasını, yayımlanmış yazı kaydı ve yayımdan kaldırma ise yalnızca o yazının 4 çeviri sayfasını sildi ve 16 dosya kaldı; geri alınan yazının İngilizce çeviri adresi 404 döndü.
| Durum | Düzeltmeden önce | Kodu ekledikten sonra | Düzeltmeden sonra silinen önbellek |
|---|---|---|---|
| Taslak kaydetme | 20 → 0 | 20 → 20 | Yok |
| Yayımlanmış yazı kaydı | Yalnızca o yazının çeviri sayfaları silindi | 20 → 16 | O yazının 4 çeviri sayfası |
| Ana sayfa kaydı | 20 → 0 | 20 → 16 | Dil ana sayfasının 4 önbellek dosyası |
| Yayımdan kaldırma | 20 → 0 | 20 → 16 | O yazının 4 çeviri sayfası · çeviri adresi 404 |
4️⃣ Ön yükleme yeniden oluşturmasının atlanması: kuyrukta kalan tamamlandı durumu
Taslak kaydını engelleseniz bile WP Rocket işlevinin silme sinyali olmadan silinen önbellek dosyalarını ön yükleme yeniden doldurmaz. WP Rocket ön yüklemesi her adres için durum kaydeden bir kuyruk tablosu kullanır: istenecek adresler bekliyor, istek gönderilenler sürüyor, önbelleği oluşanlar tamamlandı olur; 3 dakikada bitmeyenler başarısız sayılır.
Tamamlanmış bir adres üç durumda yeniden beklemeye döner: önbellek ömrü bitip dosyası silindiğinde, WP Rocket silerken silme sinyali gönderdiğinde ya da 12 saatten uzun süre önce başarısız olduğunda. [rocket_clean_files]'a üçüncü bağımsız değişken olarak false verirseniz ya da dosyaları doğrudan silerseniz bu sinyal gitmez; kuyruk tamamlandı gösterirken yalnızca önbellek dosyaları kaybolur.
Silme sinyalini alıp ardından başka önbellekleri silen kod, yinelenen çağrıları önlemek için üçüncü bağımsız değişkene false verir. Çeviri sayfası önbelleklerini karşılaştırdığımızda 65 İngilizce çeviri sayfasından 3'ü, 65 Japonca çeviri sayfasından 7'si kuyrukta tamamlandı olarak dururken önbellek dosyaları yoktu.
WP Rocket destek ekibinden bir katkıcı da #6130 yorumlarında önbellek silindikten sonra tablodaki adreslerin tamamlandı olarak kaldığını ve durumun uyuşmadığını kabul etti. Tabloyu önbellek dosyalarıyla düzenli olarak eşitleme önerisi (#2939) 2020'de uygulanmadan kapatıldı.
5️⃣ Ön yüklemeye yeniden kayıt: kendi sildiğiniz adresleri kuyruğa bildirme
Kendi sildiğiniz adresler için sildikten hemen sonra ön yüklemeye bildiren tek satır sorunu çözer. Ön yükleme [rocket_after_clean_terms] sinyalini alınca kendisine verilen adresleri yeniden beklemeye alır ve tabloda olmayan adresleri ekler.
// Silme sinyali olmadan sildikten sonra — silinen adres dizisini ön yükleme kuyruğuna yeniden kaydet
rocket_clean_files( $urls, null, false ); // üçüncü bağımsız değişken false = silme sinyali yok
do_action( 'rocket_after_clean_terms', $urls ); // ön yükleme bu adresleri beklemeye (pending) alırWP Rocket içinde bu sinyali alan yerler yalnızca ön yükleme kuyruk işlevi ve SpinUpWP hosting entegrasyonudur; ön yükleme işlevi yalnızca kuyruk satırlarını günceller, WP Rocket önbellek dosyalarını silmez ya da silme sinyalini yeniden göndermez, bu yüzden yinelenen çağrı oluşmaz. Önbelleği yalnızca WP Rocket işlevleriyle silen ve üçüncü bağımsız değişkeni varsayılanda bırakan siteler sinyali zaten gönderir; bu satıra ihtiyaç duymaz.
Bu satırı ekledikten sonra dört dilde çeviri sayfası olan bir yazının önbelleğini sildik; 2 saniye içinde dört kuyruk satırı beklemeye geçti. Her dakika cron çalıştıran bir sunucuda iki kez test ettiğimizde çeviri sayfalarının PC ve mobil 8 önbellek dosyasının tamamı 101 ve 153 saniye sonra yeniden oluştu. Kuyruk tablosundaki durum ve önbellek klasöründeki dosyalarla kontrol edersiniz.
# Kuyruk tablosunda o adresin durumu (tablo adının önündeki wp_ site önekidir)
wp db query <<'SQL'
SELECT url, status, modified FROM wp_wpr_rocket_cache WHERE url LIKE '%/en/sample-post-en'
SQLurl status modified
https://example.com/en/sample-post-en pending 2026-10-17 09:10:48# Yaklaşık bir dakika sonra önbellek dosyaları yeniden oluştu mu
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_gzipSilindikten hemen sonra durum [pending] olur; ön yükleme isteğini gönderip önbellek dosyası oluşunca [completed] olur. Durum [completed] olduğu hâlde önbellek dosyası yoksa o adres sinyalsiz silinmiştir.
Ana sayfayı kaydedip yukarıdaki kod dil ana sayfası önbellek dosyalarını silerek sinyal gönderince İngilizce ve Japonca ana sayfa adresleri kuyruğa geri döndü. Dil ana sayfalarının PC ve mobil önbellekleri en geç ikinci cron çalışmasında yeniden oluştu.
İki testte kayıttan son önbellek dosyasına kadar 47 ve 91 saniye sürdü.
🔢 SSS & önerilen içerikler














ℹ️ Satış ortaklığı bildirimi
Bu sitenin içeriklerinde satış ortaklığı bağlantıları bulunur. Bir ziyaretçi bu bağlantılar üzerinden ürün veya hizmet satın alırsa bu site satıcıdan komisyon alır. Bu süreçte alıcının ödediği tutar (kampanya indirimlerinde tutar düşer↓) artmaz. Yayımlanan fiyat, indirim ve stok bilgileri yazının yazıldığı zamana aittir ve gerçek durumdan farklı olabilir; bu yüzden satın almadan önce son bilgiyi satıcıdan kontrol etmenizi rica ederiz. Ürünler kendi ölçütlerimize göre seçilir ve değerlendirilir; komisyon alınıp alınmaması tanıtım sırasını veya değerlendirme içeriğini etkilemez.

