RG Digital Logo
RG DIGITAL · INSIGHTS · ARQUITECTURA DIGITAL

Colisión de Caché NGINX en WordPress Multilingüe

Cómo RG Digital desarrolló su propia arquitectura multilingüe para WordPress y rastreó un comportamiento inesperado en producción hasta la interacción entre el estado de la aplicación y la caché del servidor.

Una aplicación técnicamente correcta puede fallar incluso antes de que WordPress ejecute una sola línea de su lógica.

Eso fue exactamente lo que descubrimos mientras validábamos la arquitectura bilingüe de RG Digital.

En lugar de adoptar un plugin multilingüe de propósito general, diseñamos nuestra propia arquitectura de idioma y desarrollamos RG Language Bridge, un plugin personalizado para WordPress responsable de la asignación de idioma, relaciones editoriales, generación de hreflang, idioma de schema, routing y comportamiento determinístico del selector de idioma.

La aplicación se comportaba correctamente. El plugin leía correctamente las preferencias de idioma. Las páginas de destino se resolvían como esperábamos. Los códigos de estado HTTP generados eran los correctos.

Aun así, un visitante que había seleccionado explícitamente Español podía terminar siendo redirigido a la versión en Inglés del sitio.

El problema no estaba en la arquitectura de idioma.
El problema existía una capa antes.

01 · LA DECISIÓN ARQUITECTÓNICA

Por Qué Desarrollamos Nuestra Propia Capa Multilingüe

WordPress ya cuenta con soluciones multilingües maduras como WPML y Polylang. Son plataformas capaces de resolver necesidades amplias de traducción y publicación multilingüe para miles de escenarios diferentes.

Nuestro requerimiento era más específico y, sobre todo, más arquitectónico.

No necesitábamos una plataforma de gestión de traducciones que definiera cómo debía comportarse el sitio. Necesitábamos una capa de aplicación pequeña que implementara un contrato que pudiéramos definir, inspeccionar, probar y controlar directamente.

La arquitectura requería URLs independientes por idioma, relaciones editoriales explícitas entre páginas equivalentes, salida hreflang predecible, routing controlado y un sistema determinístico de fallback.

CONTROL

Arquitectura Explícita

El comportamiento del idioma sigue un contrato de aplicación diseñado específicamente para el sitio, en lugar de depender del modelo interno de una plataforma multilingüe de propósito general.

ALCANCE

Solo lo que Necesitamos

El sistema administra idioma, pairing editorial, hreflang, schema language, switching y routing sin introducir una capa adicional de gestión de traducciones.

CONTROL DEL SISTEMA

Comportamiento Predecible

Cada redirect, fallback y relación existe dentro de nuestro propio código y puede auditarse contra un contrato arquitectónico claramente definido.

No necesitábamos otra capa de traducción. Necesitábamos una arquitectura de idioma.

Esa decisión nos llevó al desarrollo de RG Language Bridge.

02 · DENTRO DE RG LANGUAGE BRIDGE

Un Plugin Pequeño con un Contrato Explícito

RG Language Bridge no traduce páginas automáticamente.

Inglés y Español permanecen como experiencias editoriales independientes. El plugin crea y hace cumplir las relaciones necesarias para que ambas funcionen como un solo sistema multilingüe coherente.

RG LANGUAGE BRIDGE Taxonomía rg_language → identifica el idioma de cada página paired_page_id → conecta equivalentes editoriales reales hreflang → en-us ↔ es-mx → x-default = miembro EN del mismo par editorial Schema language → en → en-US → es → es-MX Selector de idioma → par directo → ancestro emparejado → Home del idioma Root router → sin preferencia: 301 → /en/ → preferencia EN: 302 → /en/ → preferencia ES: 302 → /es/

Cada responsabilidad se mantiene deliberadamente pequeña.

Rank Math permanece a cargo de canonical URLs, sitemap y de la capa SEO general. RG Language Bridge únicamente controla las responsabilidades multilingües que pertenecen a su alcance arquitectónico.

03 · RELACIONES EDITORIALES

Simetría Estructural No Significa Equivalencia Editorial

Una de las reglas más importantes dentro de RG Language Bridge es que dos páginas no se emparejan únicamente porque ocupen una posición similar dentro de las estructuras en Inglés y Español.

Un pairing existe solamente cuando dos páginas representan el mismo contenido editorial para audiencias en idiomas diferentes.

PAR EDITORIAL VÁLIDO /en/services/ ↔ /es/servicios/ NO ES AUTOMÁTICAMENTE UN PAR VÁLIDO /en/case-studies/ Proyecto destacado para el mercado de Estados Unidos /es/casos-de-estudio/ Proyecto destacado para el mercado mexicano

El segundo ejemplo puede ser estructuralmente simétrico, pero el contenido no es equivalente.

En ese caso, las páginas permanecen intencionalmente sin pairing y RG Language Bridge no genera una relación hreflang artificial entre ellas.

Una arquitectura multilingüe debe representar relaciones de contenido que realmente existen, no relaciones que simplemente resultan convenientes dentro de un árbol de URLs.

04 · RESOLUCIÓN DE IDIOMA

El Selector Resuelve la Intención en Lugar de Adivinar URLs

El selector de idioma no sustituye mecánicamente /en/ por /es/, ni asume que necesariamente debe existir una URL equivalente.

Sigue una secuencia de resolución determinística.

RESOLUCIÓN DEL SELECTOR DE IDIOMA 01 · PAR DIRECTO Existe una página editorial equivalente → utilizar esa página 02 · ANCESTRO EMPAREJADO No existe un par directo → buscar el ancestro emparejado más cercano 03 · HOME DEL IDIOMA No existe un ancestro emparejado significativo → utilizar el Home del idioma de destino

Esto permite preservar la intención del visitante sin fabricar relaciones entre contenidos que no son realmente equivalentes.

Por ejemplo, una página de Casos de Estudio sin pairing puede resolver su destino mediante su Home emparejado y llevar al visitante al punto de entrada correcto del otro idioma.

05 · EL ROOT ROUTER

Una URL con Múltiples Estados Válidos de Aplicación

Las experiencias en Inglés y Español viven en rutas independientes:

/en/ → Inglés /es/ → Español

La URL raíz tiene una responsabilidad diferente.

No representa una página de contenido. Funciona como punto de entrada y router de la arquitectura multilingüe.

SIN PREFERENCIA

Ruta Predeterminada

Un visitante sin una preferencia almacenada recibe el Home en Inglés como destino predeterminado.

PREFERENCIA EN

Inglés Explícito

Un visitante que seleccionó Inglés mantiene esa preferencia mediante un redirect temporal.

PREFERENCIA ES

Español Explícito

Un visitante que seleccionó Español es dirigido directamente a la experiencia en Español.

Sin preferencia de idioma / → 301 → /en/ rg_lang_pref=en / → 302 → /en/ rg_lang_pref=es / → 302 → /es/

Durante las pruebas de aplicación, ese contrato se comportó exactamente como había sido diseñado.

Entonces producción se comportó de manera diferente.

06 · VALIDACIÓN EN PRODUCCIÓN

El Primer Sospechoso Fue Nuestro Propio Código

Durante la validación en producción, un visitante con una preferencia explícita por Español podía recibir el redirect permanente hacia Inglés desde la URL raíz.

Cookie: rg_lang_pref=es Esperado: 302 → /es/ Observado: 301 → /en/

Debido a que el componente de routing había sido desarrollado por nosotros, la primera pregunta era evidente:

¿Existía un defecto dentro de RG Language Bridge?

Antes de responsabilizar al entorno de hosting o introducir cambios adicionales en infraestructura, auditamos nuestra propia capa de aplicación.

Revisamos la lógica de redirects, manejo de cookies, validación de idioma y comportamiento del router contra el contrato arquitectónico.

Después pasamos de la revisión estática del código al aislamiento del comportamiento en runtime.

07 · AISLANDO LA APLICACIÓN

Una Solicitud Única Cambió la Investigación

Repetimos la solicitud utilizando un query string único que no podía existir previamente como la misma solicitud dentro de la caché del servidor.

/?rg_probe=es-001 Cookie: rg_lang_pref=es

Esta vez, la respuesta coincidió exactamente con lo que exigía el contrato de la aplicación.

HTTP/1.1 302 Found Location: /es/ Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private

La misma prueba con una preferencia explícita por Inglés también se comportó correctamente.

rg_lang_pref=en → 302 → /en/

RG Language Bridge estaba leyendo correctamente la cookie y produciendo la decisión de routing esperada.

Algo más estaba devolviendo la respuesta incorrecta antes de que esa lógica de aplicación tuviera oportunidad de ejecutarse.

08 · LA COLISIÓN DE CACHÉ

Cuando la Caché Consideró Equivalentes Dos Solicitudes Diferentes

Identificamos la caché de servidor NGINX como la siguiente variable y reproducimos el comportamiento mediante una secuencia controlada.

Primero limpiamos completamente la caché.

CACHÉ NGINX ACTIVA
Cookie ES
302 → /es/ ✓
Sin cookie
301 → /en/ ✓
Cookie ES nuevamente
301 → /en/ ✕
CONTRATO DE APLICACIÓN ESPERADO
Cookie ES
302 → /es/
Sin cookie
301 → /en/
Cookie ES nuevamente
302 → /es/

La segunda solicitud generó legítimamente la respuesta predeterminada 301 → /en/.

NGINX almacenó esa respuesta en caché.

Cuando llegó una nueva solicitud con una preferencia explícita por Español, la caché devolvió el redirect previamente almacenado sin considerar el estado de aplicación representado por la cookie de idioma.

WordPress nunca tuvo oportunidad de evaluar esa preferencia.

09 · APLICACIÓN VS. CACHÉ

Más PHP No Podía Corregir una Solicitud que Nunca Llegaba a PHP

Las ramas correspondientes a preferencias explícitas ya estaban enviando headers restrictivos de caché.

Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private

Esos headers eran correctos.

Pero solamente existían después de que WordPress ejecutaba la lógica del router.

Una vez que NGINX ya tenía almacenada una representación de la URL raíz, podía responder a la siguiente solicitud antes de que PHP, WordPress o RG Language Bridge se ejecutaran.

Visitante
Caché NGINX
PHP
WordPress
RG Language Bridge

En la solicitud que fallaba, la ejecución efectivamente se detenía en el segundo nodo.

Visitante ↓ CACHÉ NGINX ↓ 301 almacenado → /en/ ↓ STOP PHP → no ejecutado WordPress → no ejecutado RG Language Bridge → no ejecutado

Incluso enviar explícitamente desde el cliente headers como:

Cache-Control: no-cache Pragma: no-cache

no modificó la respuesta almacenada.

El código de aplicación no puede corregir una decisión tomada antes de que la aplicación se ejecute.

10 · COMPROBANDO LA CAUSA RAÍZ

Eliminar una Variable y Repetir Exactamente la Misma Prueba

Para confirmar el diagnóstico, desactivamos la caché NGINX y repetimos exactamente la misma secuencia.

CACHÉ NGINX DESACTIVADA
Cookie ES
302 → /es/ ✓
Sin cookie
301 → /en/ ✓
Cookie ES nuevamente
302 → /es/ ✓

Nada más cambió.

La misma instalación de WordPress.

La misma versión de RG Language Bridge.

El mismo contrato de routing.

Las mismas cookies.

Las mismas URLs.

La única variable eliminada fue la caché NGINX.

Eso aisló la falla en la capa de infraestructura.

11 · INTERACCIÓN ENTRE SISTEMAS

Cada Componente Era Correcto de Forma Aislada

Aquí es donde el debugging deja de ser un problema de componentes y se convierte en un problema de arquitectura.

RG Language Bridge evaluaba correctamente la preferencia de idioma.

WordPress ejecutaba correctamente la lógica de aplicación.

NGINX almacenaba correctamente respuestas repetidas según su política de caché.

La falla apareció porque la caché consideraba equivalentes dos solicitudes que la aplicación, deliberadamente, trataba como estados diferentes.

SOLICITUD A GET / Sin preferencia de idioma SOLICITUD B GET / Cookie: rg_lang_pref=es VISIÓN DE LA CACHÉ → misma URL VISIÓN DE LA APLICACIÓN → estado diferente → respuesta diferente

Una caché no puede reutilizar de forma segura una respuesta cuando la aplicación depende de un estado que esa caché no está considerando.

12 · LA SOLUCIÓN CORRECTA DE INFRAESTRUCTURA

Aplicar Caché Según la Responsabilidad de Cada Ruta

Desde una perspectiva arquitectónica, la solución ideal no era eliminar la caché de forma general.

El router de idioma y las URLs de contenido tienen responsabilidades diferentes y, en un entorno con suficiente granularidad de configuración, pueden utilizar políticas de caché distintas.

PREFERIDA

Bypass de Caché Cuando Existe la Cookie de Idioma

Cuando la URL raíz recibe una solicitud que contiene rg_lang_pref, la caché NGINX puede omitirse para permitir que RG Language Bridge evalúe la preferencia explícita del visitante.

ALTERNATIVA

No Almacenar en Caché el Router Raíz

Si no están disponibles reglas de bypass basadas en cookies, una alternativa es excluir únicamente la URL raíz de la caché del servidor mientras las URLs de contenido en Inglés y Español permanecen cacheables.

ARQUITECTURA IDEAL URLS DE CONTENIDO /en/* /es/* → caché normal ROUTER DE IDIOMA / → evaluar independientemente

Esta era la arquitectura preferida: permitir que el contenido siguiera beneficiándose de la caché mientras el router conservaba acceso al estado necesario para tomar su decisión.

La implementación final, sin embargo, tenía que adaptarse a las capacidades reales del entorno de hosting.

13 · RESOLUCIÓN EN PRODUCCIÓN

Adaptar la Solución a las Restricciones del Entorno

Nuestra solución preferida consistía en omitir la caché NGINX únicamente cuando el router raíz necesitara evaluar una solicitud con la cookie rg_lang_pref.

El entorno de hosting no permitía aplicar ese nivel de granularidad directamente en la configuración compartida de NGINX para rgdigital.mx sin afectar la configuración utilizada por los demás dominios de la cuenta.

La solución disponible en producción fue, por lo tanto, más amplia.

Mediante la configuración .htaccess específica de RG Digital se añadieron encabezados HTTP que indican que las respuestas del sitio no deben almacenarse ni reutilizarse desde la caché del servidor.

Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0 Pragma: no-cache Expires: 0

De esta forma, el cambio quedó encapsulado dentro del dominio rgdigital.mx. NGINX continúa formando parte de la infraestructura y los demás dominios de la cuenta conservan su configuración de caché.

El tradeoff es explícito: las páginas HTML de RG Digital dejaron de beneficiarse de la caché de servidor NGINX.

Bajo las restricciones actuales del hosting, priorizamos la corrección del routing y una experiencia multilingüe consistente sobre conservar una optimización de caché que no podía distinguir de forma segura entre los diferentes estados de la aplicación.

La lógica de aplicación no necesitó cambiar. La política de caché alrededor de la aplicación sí.

Verificando la Resolución

Después del cambio de infraestructura, repetimos exactamente la misma secuencia de solicitudes que anteriormente reproducía la colisión.

01 · Sin preferencia de idioma / → 301 → /en/ ✓ Correcto 02 · Preferencia Español rg_lang_pref=es / → 302 → /es/ ✓ Correcto 03 · Sin preferencia nuevamente / → 301 → /en/ ✓ Correcto 04 · Preferencia Español nuevamente rg_lang_pref=es / → 302 → /es/ ✓ Correcto 05 · Preferencia Inglés rg_lang_pref=en / → 302 → /en/ ✓ Correcto

También verificamos directamente las respuestas de las rutas principales de contenido en Inglés y Español.

/en/ → 200 OK Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0 /es/ → 200 OK Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0

Esto confirmó tanto la resolución de la colisión como el alcance real del tradeoff: el HTML del sitio dejó de utilizar la caché NGINX bajo la configuración actual.

La falla previamente reproducible desapareció sin modificar RG Language Bridge, su contrato de routing ni la arquitectura multilingüe del contenido.

Si en el futuro la infraestructura permite reglas más granulares, esta arquitectura puede evolucionar hacia un bypass selectivo del router, manteniendo cacheables las páginas de contenido.

La prueba final cerró la investigación: la aplicación era correcta y la solución de producción pertenecía al límite entre el estado de la aplicación y la política de caché de la infraestructura.

14 · LA LECCIÓN ARQUITECTÓNICA

Un Sistema Digital No Termina en el CMS

El síntoma original parecía un problema de WordPress.

Después parecía un problema de redirects.

Después parecía un problema de cookies.

Auditamos nuestra propia capa de aplicación antes de asignar la responsabilidad a otro componente del sistema.

La falla real existía en la interacción entre la aplicación y la infraestructura encargada de servirla.

DNS / Edge
Reverse Proxy
Caché de Servidor
Aplicación
Experiencia de Usuario

Software Engineering nos dio control sobre la aplicación.

Technical QA nos permitió validar esa aplicación contra su contrato.

El análisis de infraestructura reveló por qué una aplicación correcta estaba produciendo una experiencia incorrecta en producción.

Arquitectura Digital significa comprender no solamente cómo funciona cada componente, sino cómo se comportan esos componentes cuando interactúan.

AUDITORÍA DE ARQUITECTURA DIGITAL

¿El problema realmente está donde usted cree?

Conflictos de caché, redirects, discrepancias en analytics, aplicaciones desconectadas y problemas de infraestructura suelen parecer incidentes técnicos aislados. Con frecuencia, son síntomas de cómo está diseñada la arquitectura digital que los conecta.

Solicite una Auditoría de Arquitectura Digital →