Caché multilingüe de WP Rocket: por qué desaparece la caché de las versiones traducidas al guardar un borrador y cómo solucionarlo

La caché multilingüe de WP Rocket es una caché de página que se guarda por separado, en una carpeta de idioma, para cada URL traducida de TranslatePress. En un servidor WordPress con Nginx + Apache, seguimos en el código de WP Rocket por qué la caché de las versiones traducidas desaparecía con toda su carpeta de idioma cada vez que se guardaba un borrador, y lo resolvimos con un código que deja las entradas sin publicar fuera del borrado de la caché traducida y vuelve a avisar a la precarga de las URL que borramos a mano.
El tiempo hasta el primer byte, medido dentro del mismo servidor, fue de 0,015 segundos con la caché traducida y de 2,492 segundos sin ella. Si la carpeta de idioma queda vacía, los visitantes de las versiones traducidas reciben esta respuesta lenta hasta que alguien vuelve a abrir la URL y se crea la caché.
1️⃣ Estructura de la caché multilingüe de WP Rocket: carpetas por idioma y borrado de las versiones traducidas
Una versión traducida muestra la entrada original traducida, así que es fácil pensar que su caché va unida a la del original, pero WP Rocket guarda en caché las URL traducidas como páginas aparte. Dentro de la carpeta de caché aparecen, junto a las carpetas de las entradas originales, carpetas de idioma como [en] y [ja], y las entradas traducidas se guardan dentro con el nombre de su slug traducido.
Al editar una entrada, la integración de WP Rocket con TranslatePress borra también la caché de sus versiones traducidas. La documentación oficial indica igualmente que una edición normal borra todas las versiones traducidas y que, si se corrige en el editor de traducciones de TranslatePress, solo se borra el idioma modificado.
// wp-rocket/inc/ThirdParty/Plugins/I18n/TranslatePress.php (3.23.5.1)
'post_updated' => 'clear_post_languages', // se ejecuta cada vez que se guarda una entrada
public function clear_post_languages( $post_id ) {
// …
$default_permalink = get_permalink( $post_id ); // no se comprueba el estado de la entrada
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 );
}La función de la integración convierte la URL de la entrada en la URL traducida de cada idioma y luego la pasa a la función que limpia los archivos de caché, [rocket_clean_files]. En este proceso ninguna línea comprueba el estado de la entrada, así que las URL traducidas se generan y se borran igual tanto si la entrada está publicada como si es un borrador.
2️⃣ Guardar un borrador: se borra toda la carpeta del idioma
Guardar un borrador no es ajeno a la caché de las versiones traducidas. Antes de publicarse, el enlace permanente de una entrada no es un slug sino la forma [?p=ID de la entrada], y TranslatePress convierte esa URL en otra con la ruta del idioma, como [/en/?p=ID de la entrada].
[rocket_clean_files] quita la consulta de la URL y busca la ubicación de la caché solo por la ruta. Si la ruta que queda es [/en/], eso equivale a toda la carpeta de caché de ese idioma, y si el destino es una carpeta, la borra de forma recursiva, subcarpetas incluidas.
// wp-rocket/inc/functions/files.php (3.23.5.1) — dentro de rocket_clean_files()
$parsed_url = get_rocket_parse_url( $url ); // separa la ruta y la consulta
// …
$entry = $dir . $parsed_url['path']; // …/example.com/en/
// …
if ( $filesystem->is_dir( $entry ) ) {
rocket_rrmdir( $entry, [], $filesystem ); // borra toda la carpeta de forma recursiva
} else {
$filesystem->delete( $entry );
}La página de inicio pasa por la misma ruta. Su URL [/] se convierte en [/en/], así que incluso guardar la página de inicio publicada borra toda la carpeta del idioma. Con solo cambiar el título de un borrador y volver a guardarlo se vaciaron las carpetas de caché de los cuatro idiomas, y con las horas de guardado y los registros de borrado de caché comprobamos que el mismo borrado se repitió más de 30 veces en una noche con muchos guardados de borradores.
Según el código, el autoguardado del editor sigue la misma ruta. Las revisiones que se guardan mientras editas una entrada publicada también usan una URL con la forma [?p=].
En un sitio de pruebas con Nginx + Apache editamos una entrada publicada en el editor mientras contábamos los archivos de las carpetas de idioma. Tras el primer autoguardado, las carpetas de inglés y japonés seguían con 20 archivos cada una, y con el segundo autoguardado, un minuto después, ambas quedaron en 0.
El primer autoguardado crea una revisión nueva, y a partir del segundo se actualiza y guarda esa misma revisión, así que se ejecuta [post_updated]. Si sigues editando tras el primer autoguardado, la caché de las versiones traducidas se borra con toda la carpeta del idioma aunque no pulses el botón de guardar.
El mismo síntoma figura en el repositorio oficial de WP Rocket como issue #6130, abierta desde el 31 de agosto de 2023. La pull request #7616 que lo corrige se envió en septiembre de 2025 pero no se ha fusionado, y el registro de cambios de la 3.23.5.1, publicada el 2 de octubre de 2026, tampoco incluye ninguna corrección.
3️⃣ Código de solución: borrar la caché de las versiones traducidas solo en entradas publicadas
Hasta que llegue una corrección oficial, se quita la función de la integración y se sustituye por otra que borra las versiones traducidas solo cuando la URL es segura. La solución provisional publicada en los comentarios de la issue va en la misma dirección: sale de inmediato de la función si la entrada no está publicada.
Aun así, una condición que solo comprueba el estado de la entrada deja dos casos. La página de inicio borra toda la carpeta del idioma al guardarse aunque esté publicada, y si devuelves una entrada publicada a borrador, su caché traducida no se borra y la entrada retirada sigue abriéndose en sus URL traducidas.
<?php
/**
* Plugin Name: Rocket TranslatePress Draft Fix
* Description: Limita el borrado de la caché de las versiones traducidas de la integración de WP Rocket con TranslatePress a los casos en que la URL es segura
*/
// 1. Quitar la función de integración de WP Rocket de post_updated y guardarla
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. Función sustituta
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'] ] );
// Página de inicio: solo los archivos de caché de la página de inicio del idioma, no la carpeta del idioma
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 ); // avisar a la precarga (5️⃣)
return;
}
// Guardar una entrada publicada: la función original de WP Rocket tal cual
if ( 'publish' === $after->post_status ) {
call_user_func( $GLOBALS['rtdf_original'], $post_id );
return;
}
// Publicada → borrador·privada·papelera: solo las versiones traducidas de la URL anterior a la retirada
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 );
}
// Lo demás (borradores·revisiones·autoguardado) no tiene URL traducida, así que no se borra nada
}, 10, 3 );La primera parte localiza la función de integración que registró WP Rocket, la quita de [post_updated] y guarda la función original. La función sustituta borra solo los archivos de caché de las páginas de inicio de idioma si se trata de la página de inicio, ejecuta tal cual la función original guardada si es una entrada publicada y, si se retira una entrada publicada, busca y borra las versiones traducidas con la URL de antes de retirarla.
Si se guarda como archivo PHP en la carpeta [wp-content/mu-plugins/], se aplica al instante sin activarlo, y al borrar el archivo WP Rocket vuelve a su comportamiento original. Al probar un código con el mismo comportamiento, volver a guardar un borrador dejó igual el número de archivos de las carpetas de idioma, y volver a guardar una entrada publicada solo borró las carpetas de esa entrada, la original y la traducida.
Antes y después de añadir el código de arriba comparamos, en el mismo entorno, el número de archivos de las carpetas de idioma en cuatro casos. Las carpetas de inglés y japonés tenían cada una 20 archivos de caché de PC y móvil de la página de inicio del idioma y cuatro entradas.
Antes de añadir el código, guardar un borrador, guardar la página de inicio y despublicar dejaron ambas carpetas en 0, y solo guardar una entrada publicada borró únicamente la caché traducida de esa entrada.
Después de añadir el código, al guardar un borrador y con el autoguardado del editor se mantuvieron los 20 archivos. Guardar la página de inicio borró los 4 archivos de caché de las páginas de inicio de idioma, y guardar una entrada publicada o despublicarla solo borró los 4 archivos traducidos de esa entrada y quedaron 16; la URL traducida al inglés de la entrada retirada respondió 404.
| Caso | Antes de la corrección | Después de añadir el código | Caché borrada después |
|---|---|---|---|
| Guardar un borrador | 20 → 0 | 20 → 20 | Ninguno |
| Guardar una entrada publicada | Solo se borran las versiones traducidas de esa entrada | 20 → 16 | 4 archivos traducidos de esa entrada |
| Guardar la página de inicio | 20 → 0 | 20 → 16 | 4 archivos de caché de las páginas de inicio de idioma |
| Despublicar | 20 → 0 | 20 → 16 | 4 archivos traducidos de esa entrada · la URL traducida da 404 |
4️⃣ La precarga no regenera: estado completado que queda en la cola
Aunque se bloquee el guardado de borradores, la precarga no vuelve a llenar los archivos de caché borrados sin la señal de borrado de una función de WP Rocket. La precarga de WP Rocket usa una tabla de cola que registra el estado de cada URL: las que hay que solicitar quedan pendientes, las solicitadas pasan a en curso, las que ya tienen caché pasan a completadas y las que no terminan en 3 minutos pasan a fallidas.
Una URL completada vuelve a pendiente en tres casos: archivos borrados al terminar la vida útil de la caché, URL borradas por WP Rocket enviando la señal de borrado y URL que fallaron hace más de 12 horas. Si pasas false como tercer argumento de [rocket_clean_files] o borras los archivos directamente, esa señal no se envía y solo desaparecen los archivos de caché, mientras en la cola siguen como completados.
El tercer argumento se pasa como false en el código que recibe la señal de borrado y sigue borrando otras cachés, para evitar llamadas repetidas. Al cotejar las cachés traducidas, 3 de las 65 versiones en inglés y 7 de las 65 en japonés seguían como completadas en la cola, pero sin archivos de caché.
Un colaborador del equipo de soporte de WP Rocket también reconoció en los comentarios de la issue #6130 que, tras borrar la caché, las URL de la tabla quedan como completadas y el estado se desincroniza. La propuesta de sincronizar periódicamente la tabla con los archivos de caché (#2939) se cerró en 2020 sin implementarse.
5️⃣ Volver a registrar en la precarga: avisar a la cola de las URL borradas a mano
Para las URL que borras a mano basta con una línea que avise a la precarga justo después de borrarlas. Cuando la precarga recibe la señal [rocket_after_clean_terms], devuelve a pendiente las URL recibidas y añade las que no estén en la tabla.
// Tras borrar sin la señal de borrado: volver a registrar el array de URL borradas en la cola de precarga
rocket_clean_files( $urls, null, false ); // tercer argumento false = sin señal de borrado
do_action( 'rocket_after_clean_terms', $urls ); // la precarga devuelve estas URL a espera (pending)Dentro de WP Rocket, esta señal solo la reciben la función de la cola de precarga y la integración con el hosting SpinUpWP, y la función de precarga solo actualiza filas de la cola sin borrar archivos de caché de WP Rocket ni volver a enviar la señal de borrado, así que no hay llamadas repetidas. Los sitios que borran la caché solo con funciones de WP Rocket y dejan el tercer argumento con su valor por defecto ya envían la señal y no necesitan esta línea.
Tras añadir esta línea, al borrar la caché de una entrada con versiones traducidas en cuatro idiomas, sus cuatro filas de la cola pasaron a pendiente en menos de 2 segundos. En dos pruebas en un servidor que ejecuta el cron cada minuto, los 8 archivos de caché de PC y móvil de las versiones traducidas se regeneraron a los 101 y a los 153 segundos. Se comprueba con el estado de la tabla de la cola y los archivos de la carpeta de caché.
# Estado de esa URL en la tabla de la cola (el wp_ delante del nombre de la tabla es el prefijo del sitio)
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# Si los archivos de caché vuelven a aparecer al cabo de un minuto
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_gzipJusto después del borrado el estado cambia a [pending], y cuando la precarga envía la solicitud y se crea el archivo de caché, pasa a [completed]. Si el estado es [completed] pero no hay archivo de caché, esa URL se borró sin la señal.
Al guardar la página de inicio, el código de arriba borró los archivos de caché de las páginas de inicio de idioma y envió la señal, y las URL de inicio en inglés y japonés volvieron a la cola. La caché de PC y móvil de las páginas de inicio de idioma se regeneró, como tarde, en la segunda ejecución del cron.
En dos pruebas, desde el guardado hasta el último archivo de caché pasaron 47 y 91 segundos.
🔢 FAQ & contenido recomendado
















ℹ️ Aviso de afiliados
El contenido de este sitio incluye enlaces de afiliado. Cuando un visitante compra un producto o servicio a través de uno de ellos, el sitio recibe una comisión del vendedor. El importe que paga el comprador(baja durante las promociones ↓)no aumenta. Los precios, descuentos y existencias publicados corresponden al momento de redacción y pueden variar, así que confírmalos con el vendedor antes de comprar. Los productos se eligen y evalúan con criterios propios, y las comisiones no influyen en el orden ni en el contenido de las reseñas.