Meertalige cache van WP Rocket: waarom de cache van vertaalde pagina's verdwijnt bij het opslaan van een concept, en de oplossing

De meertalige cache van WP Rocket is een paginacache die per vertaalde URL van TranslatePress apart onder een taalmap wordt opgeslagen. Op een WordPress-server met Nginx + Apache hebben we in de code van WP Rocket nagegaan waarom de cache van vertaalde pagina's met de hele taalmap verdween telkens als een concept werd opgeslagen, en hebben het opgelost met code die niet-gepubliceerde berichten buiten het wissen van de cache van vertaalde pagina's houdt en de preload opnieuw informeert over URL's die we zelf verwijderen.
De tijd tot de eerste byte, gemeten binnen dezelfde server, was 0,015 seconde met de cache van de vertaalde pagina en 2,492 seconden zonder. Zodra een taalmap leeg is, krijgen bezoekers van de vertaalde pagina's deze trage reactie, totdat iemand de URL weer opent en de cache opnieuw wordt opgebouwd.
1️⃣ Hoe de meertalige cache van WP Rocket is opgebouwd: taalmappen en het wissen van vertaalde pagina's
Een vertaalde pagina toont het oorspronkelijke bericht in vertaling, dus je zou denken dat de cache ervan bij het origineel hoort, maar WP Rocket cachet vertaalde URL's als aparte pagina's. Onder de cachemap verschijnen taalmappen zoals [en] en [ja] naast de mappen van de oorspronkelijke berichten, en vertaalde berichten worden daarin onder hun vertaalde slug opgeslagen.
Als je een bericht bewerkt, verwijdert de TranslatePress-integratie van WP Rocket ook de cache van de vertaalde pagina's van dat bericht. Ook de officiële documentatie zegt dat een gewone bewerking alle vertaalde versies wist, terwijl een bewerking in de vertaaleditor van TranslatePress alleen de gewijzigde taal wist.
// wp-rocket/inc/ThirdParty/Plugins/I18n/TranslatePress.php (3.23.5.1)
'post_updated' => 'clear_post_languages', // draait telkens als een bericht wordt opgeslagen
public function clear_post_languages( $post_id ) {
// …
$default_permalink = get_permalink( $post_id ); // berichtstatus wordt niet gecontroleerd
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 );
}De integratiefunctie zet de URL van het bericht per taal om in de vertaalde URL en geeft die dan door aan de functie voor het opruimen van cache, [rocket_clean_files]. Niets in dit proces controleert de berichtstatus, dus vertaalde URL's worden op dezelfde manier gemaakt en verwijderd, of het bericht nu gepubliceerd is of een concept.
2️⃣ Een concept opslaan: de hele taalmap wordt verwijderd
Een concept opslaan staat niet los van de cache van vertaalde pagina's. Voordat een bericht is gepubliceerd, is de permalink geen slug maar de vorm [?p=bericht-ID], en TranslatePress zet die URL om in een URL met een taalpad, zoals [/en/?p=bericht-ID].
[rocket_clean_files] laat de query uit de URL weg en zoekt de cachelocatie alleen op pad. Als het overgebleven pad [/en/] is, betekent dat de hele cachemap van die taal, en als het doel een map is, wordt die recursief verwijderd, inclusief submappen.
// wp-rocket/inc/functions/files.php (3.23.5.1) — binnen rocket_clean_files()
$parsed_url = get_rocket_parse_url( $url ); // splitst het pad en de query
// …
$entry = $dir . $parsed_url['path']; // …/example.com/en/
// …
if ( $filesystem->is_dir( $entry ) ) {
rocket_rrmdir( $entry, [], $filesystem ); // verwijdert de hele map recursief
} else {
$filesystem->delete( $entry );
}De voorpagina gaat via hetzelfde pad. De URL [/] wordt omgezet in [/en/], dus zelfs het opslaan van de gepubliceerde voorpagina verwijdert de hele taalmap. Alleen de titel van een concept aanpassen en opnieuw opslaan maakte de cachemappen van alle vier talen leeg, en uit opslagtijden en logboeken van cacheverwijdering bevestigden we dat dezelfde verwijdering in één nacht met veel conceptopslagen meer dan 30 keer terugkwam.
In de code volgt ook de autosave van de editor hetzelfde pad. Revisies die worden opgeslagen terwijl je een gepubliceerd bericht bewerkt, gebruiken ook een URL in de vorm [?p=].
Op een testsite met Nginx + Apache bewerkten we een gepubliceerd bericht in de editor en telden we de bestanden in de taalmappen. Na de eerste autosave hadden de Engelse en Japanse map nog elk 20 bestanden, en na de tweede autosave een minuut later stonden beide mappen op 0.
De eerste autosave maakt een nieuwe revisie, en vanaf de tweede wordt dezelfde revisie bijgewerkt en opgeslagen, waardoor [post_updated] wordt uitgevoerd. Blijf je na de eerste autosave bewerken, dan wordt de cache van vertaalde pagina's met de taalmap verwijderd, ook zonder op de opslagknop te drukken.
Hetzelfde symptoom staat sinds 31 augustus 2023 open als issue #6130 in de officiële repository van WP Rocket. Pull request #7616 om het op te lossen werd in september 2025 ingediend maar niet samengevoegd, en ook de changelog van 3.23.5.1, uitgebracht op 2 oktober 2026, bevat geen oplossing.
3️⃣ De oplossing: de cache van vertaalde pagina's alleen wissen voor gepubliceerde berichten
Tot er een officiële oplossing is, maak je de integratiefunctie los en vervang je die door een functie die vertaalde pagina's alleen wist als de URL zeker is. De workaround in de reacties bij het issue gaat dezelfde kant op en keert direct terug uit de integratiefunctie als het bericht niet is gepubliceerd.
Een voorwaarde die alleen de berichtstatus controleert, laat echter twee gevallen over. De voorpagina wist bij het opslaan de hele taalmap, ook al is die gepubliceerd, en als je een gepubliceerd bericht terugzet naar concept, wordt de cache van de vertaalde pagina's niet verwijderd, zodat het teruggetrokken bericht op de vertaalde URL's blijft openen.
<?php
/**
* Plugin Name: Rocket TranslatePress Draft Fix
* Description: Beperkt het verwijderen van de cache van vertaalde pagina's door de TranslatePress-integratie van WP Rocket tot gevallen waarin de URL zeker is
*/
// 1. Maak de integratiefunctie van WP Rocket los van post_updated en bewaar die
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. Vervangende functie
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'] ] );
// Voorpagina — alleen de cachebestanden van de taalhomepage, niet de taalmap
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 ); // de preload informeren (5️⃣)
return;
}
// Een gepubliceerd bericht opslaan — de oorspronkelijke functie van WP Rocket zoals die is
if ( 'publish' === $after->post_status ) {
call_user_func( $GLOBALS['rtdf_original'], $post_id );
return;
}
// Gepubliceerd → concept·privé·prullenbak — alleen de vertaalde pagina's van de URL van vóór het terugtrekken
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 );
}
// Al het andere (concepten·revisies·autosave) heeft geen vertaalde URL, dus er wordt niets verwijderd
}, 10, 3 );Het eerste deel zoekt de integratiefunctie die WP Rocket heeft geregistreerd, maakt die los van [post_updated] en bewaart de oorspronkelijke functie. De vervangende functie wist voor de voorpagina alleen de cachebestanden van de taalhomepage, voert voor gepubliceerde berichten de bewaarde oorspronkelijke functie ongewijzigd uit en zoekt, als een gepubliceerd bericht wordt teruggetrokken, de vertaalde pagina's op via de URL van daarvoor en verwijdert ze.
Opgeslagen als PHP-bestand in de map [wp-content/mu-plugins/] werkt het meteen zonder activatie, en als je het bestand verwijdert, keert WP Rocket terug naar zijn oorspronkelijke gedrag. In een test met code die zich hetzelfde gedraagt, bleef bij het opnieuw opslaan van een concept het aantal bestanden in de taalmappen gelijk, en bij het opnieuw opslaan van een gepubliceerd bericht werden alleen de mappen van het origineel en de vertaalde pagina's van dat bericht gewist.
Voor en na het toevoegen van bovenstaande code vergeleken we het aantal bestanden in de taalmappen voor vier gevallen in dezelfde omgeving. De Engelse en Japanse map bevatten elk 20 cachebestanden voor pc en mobiel van de taalhomepage en vier berichten.
Vóór de code brachten het opslaan van een concept, het opslaan van de voorpagina en het terugtrekken van een publicatie beide mappen naar 0, en alleen het opslaan van een gepubliceerd bericht verwijderde alleen de cache van de vertaalde pagina's van dat bericht.
Na de code bleven alle 20 bestanden staan bij het opslaan van een concept en bij autosave in de editor. Het opslaan van de voorpagina verwijderde de 4 cachebestanden van de taalhomepage, en het opslaan of terugtrekken van een gepubliceerd bericht verwijderde alleen de 4 vertaalde pagina's van dat bericht, zodat er 16 overbleven; de Engelse vertaalde URL van het teruggetrokken bericht gaf 404.
| Geval | Vóór de oplossing | Na het toevoegen van de code | Cache verwijderd na de oplossing |
|---|---|---|---|
| Een concept opslaan | 20 → 0 | 20 → 20 | Geen |
| Een gepubliceerd bericht opslaan | Alleen de vertaalde pagina's van dat bericht verwijderd | 20 → 16 | 4 vertaalde pagina's van dat bericht |
| De voorpagina opslaan | 20 → 0 | 20 → 16 | 4 cachebestanden van de taalhomepage |
| Publicatie terugtrekken | 20 → 0 | 20 → 16 | 4 vertaalde pagina's van dat bericht · vertaalde URL geeft 404 |
4️⃣ Gemiste preload-herbouw: de status voltooid blijft in de wachtrij staan
Ook met het opslaan van concepten geblokkeerd, vult de preload cachebestanden die zonder het verwijdersignaal van een WP Rocket-functie zijn verwijderd niet opnieuw. De preload van WP Rocket gebruikt een wachtrijtabel die per URL een status bijhoudt: URL's die nog moeten worden opgevraagd zijn pending, opgevraagde zijn in progress, gecachete worden completed, en URL's die niet binnen 3 minuten klaar zijn worden failed.
Een voltooide URL gaat in drie gevallen terug naar pending: als het bestand is verwijderd omdat de cacheduur afliep, als WP Rocket bij het wissen een verwijdersignaal stuurde, of als het meer dan 12 uur geleden mislukte. Geef je false mee als derde argument van [rocket_clean_files] of verwijder je bestanden rechtstreeks, dan wordt dat signaal niet gestuurd, zodat alleen de cachebestanden verdwijnen terwijl de wachtrij ze nog als voltooid toont.
Code die het verwijdersignaal ontvangt en daarna andere caches wist, geeft false mee als derde argument om herhaalde aanroepen te voorkomen. Toen we de caches van vertaalde pagina's controleerden, stonden 3 van de 65 Engelse en 7 van de 65 Japanse vertaalde pagina's nog als voltooid in de wachtrij terwijl hun cachebestanden ontbraken.
Ook een supportmedewerker van WP Rocket erkende in de reacties bij issue #6130 dat URL's in de tabel na het wissen van de cache voltooid blijven en de status uit de pas raakt. Een voorstel om de tabel periodiek met de cachebestanden af te stemmen (#2939) werd in 2020 gesloten zonder te worden uitgevoerd.
5️⃣ Opnieuw aanmelden bij de preload: de wachtrij informeren over URL's die je zelf hebt gewist
Voor URL's die je zelf verwijdert, lost één regel die de preload direct na het verwijderen informeert het op. Als de preload het signaal [rocket_after_clean_terms] ontvangt, zet het de ontvangen URL's terug op pending en voegt het URL's toe die in de tabel ontbreken.
// Na verwijderen zonder verwijdersignaal — meld de array met verwijderde URL's opnieuw aan in de preload-wachtrij
rocket_clean_files( $urls, null, false ); // derde argument false = geen verwijdersignaal
do_action( 'rocket_after_clean_terms', $urls ); // de preload zet deze URL's terug op wachten (pending)Binnen WP Rocket ontvangen alleen de wachtrijfunctie van de preload en de hostingintegratie van SpinUpWP dit signaal, en de preloadfunctie werkt alleen wachtrijregels bij zonder cachebestanden van WP Rocket te verwijderen of het verwijdersignaal opnieuw te sturen, dus er ontstaan geen herhaalde aanroepen. Sites die de cache alleen via functies van WP Rocket wissen en het derde argument op de standaard laten, sturen het signaal al en hebben deze regel niet nodig.
Na het toevoegen van deze regel wisten we de cache van één bericht met vertaalde pagina's in vier talen, en binnen 2 seconden schakelden de vier wachtrijregels naar pending. Bij twee tests op een server die elke minuut cron draait, waren alle 8 cachebestanden voor pc en mobiel van de vertaalde pagina's na 101 en 153 seconden opnieuw opgebouwd. Je controleert dit via de status in de wachtrijtabel en de bestanden in de cachemap.
# Status van die URL in de wachtrijtabel (de wp_ voor de tabelnaam is het voorvoegsel van de site)
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# Of de cachebestanden na ongeveer een minuut terug zijn
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_gzipDirect na het verwijderen verandert de status in [pending], en zodra de preload zijn verzoek stuurt en het cachebestand is gemaakt, wordt het [completed]. Is de status [completed] maar is er geen cachebestand, dan is die URL zonder het signaal verwijderd.
Toen we de voorpagina opsloegen en bovenstaande code de cachebestanden van de taalhomepage verwijderde en het signaal stuurde, gingen de Engelse en Japanse home-URL's terug in de wachtrij. De caches voor pc en mobiel van de taalhomepages werden uiterlijk bij de tweede cronrun opnieuw opgebouwd.
In twee tests duurde het 47 en 91 seconden van opslaan tot het laatste cachebestand.
🔢 FAQ & aanbevolen content














ℹ️ Affiliatemelding
De content van deze site bevat affiliatelinks. Koopt een bezoeker via een van deze links een product of dienst, dan ontvangt deze site een commissie van de verkoper. Het bedrag dat de koper betaalt (bij acties gaat het omlaag ↓) wordt daardoor niet hoger. De vermelde prijzen, kortingen en voorraad gelden op het moment van schrijven en kunnen afwijken; controleer ze daarom vóór je aankoop bij de verkoper. Producten worden gekozen en beoordeeld volgens onze eigen criteria, en commissies hebben geen invloed op de volgorde of de inhoud van de beoordelingen.

