Cache multilíngue do WP Rocket: por que o cache das versões traduzidas some ao salvar um rascunho e a solução

O cache multilíngue do WP Rocket é um cache de página guardado separadamente numa pasta de idioma para cada URL traduzida do TranslatePress. Num servidor WordPress com Nginx + Apache, rastreamos no código do WP Rocket por que o cache das páginas traduzidas sumia junto com a pasta inteira do idioma toda vez que um rascunho era salvo, e resolvemos com um código que deixa posts não publicados fora da limpeza do cache das páginas traduzidas e avisa de novo o preload sobre as URLs que nós mesmos apagamos.
O tempo até o primeiro byte, medido dentro do mesmo servidor, foi de 0,015 segundo com o cache da página traduzida e 2,492 segundos sem ele. Quando uma pasta de idioma fica vazia, os visitantes das páginas traduzidas recebem essa resposta lenta até alguém abrir a URL de novo e o cache ser recriado.
1️⃣ Como o cache multilíngue do WP Rocket se organiza: pastas por idioma e limpeza das páginas traduzidas
Uma página traduzida mostra o post original traduzido, então é fácil achar que o cache dela fica junto com o original, mas o WP Rocket faz cache das URLs traduzidas como páginas separadas. Sob a pasta de cache, pastas de idioma como [en] e [ja] aparecem ao lado das pastas dos posts originais, e os posts traduzidos ficam dentro delas com os slugs traduzidos.
Ao editar um post, a integração do WP Rocket com o TranslatePress também apaga o cache das páginas traduzidas desse post. A documentação oficial também diz que uma edição comum limpa todas as versões traduzidas, enquanto uma edição feita no editor de tradução do TranslatePress limpa só o idioma que mudou.
// wp-rocket/inc/ThirdParty/Plugins/I18n/TranslatePress.php (3.23.5.1)
'post_updated' => 'clear_post_languages', // roda toda vez que um post é salvo
public function clear_post_languages( $post_id ) {
// …
$default_permalink = get_permalink( $post_id ); // o status do post não é verificado
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 );
}A função de integração converte a URL do post na URL traduzida de cada idioma e depois as passa para a função de limpeza de cache [rocket_clean_files]. Nada nesse processo verifica o status do post, então as URLs traduzidas são montadas e apagadas da mesma forma, seja o post publicado ou rascunho.
2️⃣ Salvar um rascunho: a pasta inteira do idioma é apagada
Salvar um rascunho tem a ver com o cache das páginas traduzidas. Antes de o post ser publicado, o link permanente não é um slug, e sim a forma [?p=ID do post], e o TranslatePress converte essa URL numa com caminho de idioma, como [/en/?p=ID do post].
O [rocket_clean_files] tira a query da URL e encontra o local do cache só pelo caminho. Se o caminho que sobra é [/en/], isso significa a pasta inteira de cache daquele idioma, e se o alvo é uma pasta, ela é apagada recursivamente, com subpastas.
// wp-rocket/inc/functions/files.php (3.23.5.1) — dentro de rocket_clean_files()
$parsed_url = get_rocket_parse_url( $url ); // separa o caminho e a query
// …
$entry = $dir . $parsed_url['path']; // …/example.com/en/
// …
if ( $filesystem->is_dir( $entry ) ) {
rocket_rrmdir( $entry, [], $filesystem ); // apaga a pasta inteira recursivamente
} else {
$filesystem->delete( $entry );
}A página inicial passa pelo mesmo caminho. A URL [/] é convertida em [/en/], então até salvar a página inicial publicada apaga a pasta inteira do idioma. Só mudar o título de um rascunho e salvar de novo esvaziou as pastas de cache dos quatro idiomas, e pelos horários de salvamento e registros de exclusão de cache confirmamos a mesma exclusão repetida mais de 30 vezes numa noite em que os salvamentos de rascunho se acumularam.
No código, o salvamento automático do editor segue o mesmo caminho. As revisões salvas enquanto você edita um post publicado também usam uma URL da forma [?p=].
Num site de teste com Nginx + Apache, editamos um post publicado no editor contando os arquivos das pastas de idioma. Depois do primeiro salvamento automático, as pastas de inglês e japonês ainda tinham 20 arquivos cada, e depois do segundo, um minuto mais tarde, as duas estavam em 0.
O primeiro salvamento automático cria uma revisão nova, e a partir do segundo a mesma revisão é atualizada e salva, então o [post_updated] é disparado. Se você continuar editando depois do primeiro, o cache das páginas traduzidas é apagado junto com a pasta do idioma, mesmo sem apertar o botão de salvar.
O mesmo sintoma está aberto no repositório oficial do WP Rocket como issue #6130 desde 31 de agosto de 2023. O pull request #7616 para corrigi-lo foi enviado em setembro de 2025, mas não foi incorporado, e o changelog da 3.23.5.1, lançada em 2 de outubro de 2026, também não traz correção.
3️⃣ A correção: limpar o cache das páginas traduzidas só para posts publicados
Até sair uma correção oficial, você desconecta a função de integração e a troca por uma que limpa as páginas traduzidas só quando a URL é certa. A solução alternativa publicada nos comentários da issue vai na mesma direção, saindo logo da função de integração quando o post não está publicado.
Mas uma condição que só verifica o status do post deixa dois casos. A página inicial limpa a pasta inteira do idioma ao ser salva, mesmo publicada, e quando você volta um post publicado para rascunho, o cache das páginas traduzidas não é apagado, então o post despublicado continua abrindo nas URLs traduzidas.
<?php
/**
* Plugin Name: Rocket TranslatePress Draft Fix
* Description: Limita a exclusão do cache das páginas traduzidas pela integração WP Rocket–TranslatePress aos casos em que a URL é certa
*/
// 1. Desconecta a função de integração do WP Rocket do post_updated e a guarda
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. Função substituta
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 inicial — só os arquivos de cache da página inicial do idioma, não a pasta
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 o preload (5️⃣)
return;
}
// Salvar um post publicado — a função original do WP Rocket como está
if ( 'publish' === $after->post_status ) {
call_user_func( $GLOBALS['rtdf_original'], $post_id );
return;
}
// Publicado → rascunho·privado·lixeira — só as páginas traduzidas da URL de antes de despublicar
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 );
}
// O resto (rascunhos·revisões·salvamento automático) não tem URL traduzida, então nada é apagado
}, 10, 3 );A primeira parte encontra a função de integração registrada pelo WP Rocket, desconecta-a do [post_updated] e guarda a função original. A função substituta limpa só os arquivos de cache da página inicial do idioma quando é a página inicial, roda a função original guardada como está para posts publicados e, quando um post publicado é retirado, encontra e apaga as páginas traduzidas usando a URL de antes.
Salvo como arquivo PHP na pasta [wp-content/mu-plugins/], ele vale na hora sem ativação, e apagar o arquivo devolve o WP Rocket ao comportamento original. Num teste com código de mesmo comportamento, salvar de novo um rascunho manteve o número de arquivos das pastas de idioma, e salvar de novo um post publicado limpou só as pastas do original e das páginas traduzidas desse post.
Antes e depois de adicionar o código acima, comparamos o número de arquivos das pastas de idioma em quatro casos no mesmo ambiente. As pastas de inglês e japonês tinham cada uma 20 arquivos de cache para PC e celular da página inicial do idioma e de quatro posts.
Antes do código, salvar um rascunho, salvar a página inicial e despublicar levaram as duas pastas a 0, e só salvar um post publicado apagou apenas o cache das páginas traduzidas desse post.
Depois do código, os 20 arquivos ficaram ao salvar um rascunho e no salvamento automático do editor. Salvar a página inicial apagou os 4 arquivos de cache da página inicial do idioma, e salvar ou despublicar um post publicado apagou só as 4 páginas traduzidas desse post, sobrando 16; a URL traduzida em inglês do post despublicado retornou 404.
| Caso | Antes da correção | Depois de adicionar o código | Cache apagado depois da correção |
|---|---|---|---|
| Salvar um rascunho | 20 → 0 | 20 → 20 | Nenhum |
| Salvar um post publicado | Só as páginas traduzidas desse post apagadas | 20 → 16 | 4 páginas traduzidas desse post |
| Salvar a página inicial | 20 → 0 | 20 → 16 | 4 arquivos de cache da página inicial do idioma |
| Despublicar | 20 → 0 | 20 → 16 | 4 páginas traduzidas desse post · URL traduzida retorna 404 |
4️⃣ Recriação do preload perdida: status concluído preso na fila
Mesmo com os salvamentos de rascunho bloqueados, o preload não repõe arquivos de cache apagados sem o sinal de exclusão de uma função do WP Rocket. O preload do WP Rocket usa uma tabela de fila que registra um status por URL: URLs aguardando requisição ficam pendentes, as requisitadas ficam em andamento, as que têm cache viram concluídas, e as que não terminam em 3 minutos viram falhas.
Uma URL concluída volta a pendente em três casos: quando o arquivo foi removido ao fim da vida útil do cache, quando o WP Rocket enviou um sinal de exclusão ao limpá-lo, ou quando falhou há mais de 12 horas. Se você passar false como terceiro argumento do [rocket_clean_files] ou apagar os arquivos diretamente, esse sinal não é enviado, então só os arquivos de cache somem enquanto a fila ainda os mostra como concluídos.
O código que recebe o sinal de exclusão e segue limpando outros caches passa false no terceiro argumento para evitar chamadas repetidas. Quando conferimos os caches das páginas traduzidas, 3 das 65 páginas em inglês e 7 das 65 em japonês ainda estavam como concluídas na fila sem os arquivos de cache.
Um colaborador do suporte do WP Rocket também reconheceu nos comentários da issue #6130 que, depois de limpar o cache, as URLs na tabela continuam como concluídas e o estado fica dessincronizado. Uma proposta de reconciliar periodicamente a tabela com os arquivos de cache (#2939) foi fechada em 2020 sem ser implementada.
5️⃣ Registrar de novo no preload: avisar a fila sobre as URLs que você mesmo limpou
Para URLs que você mesmo apaga, uma linha que avisa o preload logo depois de apagar resolve. Quando o preload recebe o sinal [rocket_after_clean_terms], ele volta as URLs recebidas para pendentes e adiciona as que faltam na tabela.
// Depois de apagar sem o sinal de exclusão — registra de novo o array de URLs apagadas na fila do preload
rocket_clean_files( $urls, null, false ); // terceiro argumento false = sem sinal de exclusão
do_action( 'rocket_after_clean_terms', $urls ); // o preload volta essas URLs para espera (pending)Dentro do WP Rocket, só a função de fila do preload e a integração de hospedagem SpinUpWP recebem esse sinal, e a função do preload só atualiza linhas da fila, sem apagar arquivos de cache do WP Rocket nem reenviar o sinal, então não há chamadas repetidas. Sites que limpam o cache só por funções do WP Rocket e deixam o terceiro argumento no padrão já enviam o sinal e não precisam dessa linha.
Depois de adicionar essa linha, limpamos o cache de um post com páginas traduzidas em quatro idiomas, e em 2 segundos as quatro linhas da fila passaram para pendente. Em dois testes num servidor que roda cron a cada minuto, os 8 arquivos de cache de PC e celular das páginas traduzidas foram recriados após 101 e 153 segundos. Você confere pelo status da tabela da fila e pelos arquivos da pasta de cache.
# Status dessa URL na tabela da fila (o wp_ antes do nome da tabela é o prefixo do 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# Se os arquivos de cache voltaram cerca de um minuto depois
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_gzipLogo depois de apagar, o status muda para [pending], e quando o preload envia a requisição e o arquivo de cache é criado, passa a [completed]. Se o status é [completed] mas não há arquivo de cache, essa URL foi apagada sem o sinal.
Quando salvamos a página inicial e o código acima apagou os arquivos de cache da página inicial dos idiomas e enviou o sinal, as URLs da home em inglês e japonês voltaram para a fila. Os caches de PC e celular das páginas iniciais dos idiomas foram recriados no máximo na segunda execução do cron.
Em dois testes, levou 47 e 91 segundos do salvamento até o último arquivo de cache.
🔢 FAQ & conteúdo recomendado














ℹ️ Aviso de afiliados
O conteúdo deste site contém links de afiliados. Quando um visitante compra um produto ou serviço por meio de um desses links, o site recebe uma comissão do vendedor. O valor que o comprador paga (em promoções, ele diminui ↓) não aumenta por causa disso. Preços, descontos e informações de estoque valem para o momento em que o texto foi escrito e podem ter mudado, por isso confirme com o vendedor antes de comprar. Os produtos são escolhidos e avaliados por critérios próprios, e o recebimento de comissão não influencia a ordem de apresentação nem o conteúdo das avaliações.

