NGINX Cache Collision in Multilingual WordPress
How a custom WordPress language architecture exposed a cache-layer collision in production — and why solving it required looking beyond the application itself.
A technically correct application can still fail before WordPress executes a single line of its logic.
We discovered exactly that while validating the bilingual architecture of RG Digital.
Instead of adopting a general-purpose multilingual plugin, we designed the language architecture ourselves and developed RG Language Bridge, a custom WordPress plugin responsible for language ownership, editorial relationships, hreflang generation, schema language, routing and deterministic language-switching behavior.
The application was behaving correctly. The plugin was reading language preferences correctly. Destination pages were resolving correctly. The expected HTTP status codes were being generated.
Yet a visitor who had explicitly selected Spanish could still be redirected to the English version of the site.
The problem was not the language architecture.
The problem existed one layer before it.
Why We Built Our Own Multilingual Layer
WordPress already has mature multilingual solutions such as WPML and Polylang. They solve broad translation and multilingual publishing requirements for thousands of different use cases.
Our requirement was narrower and more architectural.
We did not need a translation management platform to determine how the site should behave. We needed a small application layer that implemented a contract we could define, inspect, test and control ourselves.
The architecture required independent language URLs, explicit editorial relationships between equivalent pages, predictable hreflang output, controlled language routing and deterministic fallback behavior.
Explicit Architecture
Language behavior follows an application contract designed specifically for the site instead of being determined by the internal model of a general-purpose multilingual platform.
Only What We Need
The system handles language ownership, editorial pairing, hreflang, schema language, switching and routing without introducing a larger translation-management layer.
Predictable Behavior
Every redirect, fallback and relationship exists in our own codebase and can be audited against a clearly defined architectural contract.
We did not need another translation layer. We needed a language architecture.
That decision led to the development of RG Language Bridge.
A Small Plugin With an Explicit Contract
RG Language Bridge does not automatically translate pages.
English and Spanish remain independently authored experiences. The plugin creates and enforces the relationships required for those experiences to behave as one coherent multilingual system.
Each responsibility is intentionally small.
Rank Math remains responsible for canonical URLs, sitemap generation and the broader SEO layer. RG Language Bridge only owns the multilingual responsibilities that belong to its architectural scope.
Structural Symmetry Is Not Editorial Equivalence
One of the most important rules inside RG Language Bridge is that pages are not paired merely because they occupy similar positions in the English and Spanish site structures.
A pairing exists only when two pages represent the same editorial content for different language audiences.
The second example may be structurally symmetrical, but the content is not equivalent.
In that situation, the pages remain intentionally unpaired and RG Language Bridge does not generate an artificial hreflang relationship between them.
Multilingual architecture should represent content relationships that actually exist, not relationships that merely look convenient in a URL tree.
The Switcher Resolves Intent Instead of Guessing URLs
The language switcher does not mechanically replace /en/ with /es/ or assume that an equivalent URL must exist.
It follows a deterministic resolution sequence.
This allows the system to preserve visitor intent without fabricating relationships between content that is not genuinely equivalent.
For example, an unpaired Case Studies page can resolve through its paired Home ancestor and send the visitor to the appropriate language entry point.
One URL With Multiple Valid Application States
The English and Spanish experiences live under independent language paths:
The root URL has a different responsibility.
It is not a content page. It acts as the entry router for the multilingual architecture.
Default Route
A visitor without a stored language preference receives the English Home as the default destination.
Explicit English
A visitor who explicitly selected English keeps that preference through a temporary redirect.
Explicit Spanish
A visitor who selected Spanish is routed directly into the Spanish experience.
During application testing, that contract behaved exactly as designed.
Then production behaved differently.
The First Suspect Was Our Own Code
During production validation, a visitor with an explicit Spanish preference could still receive the permanent English redirect from the root URL.
Because the routing component was software we had developed, the first question was obvious:
Was there a defect in RG Language Bridge?
Before blaming the hosting environment or introducing additional infrastructure changes, we audited our own application layer.
Redirect logic, cookie handling, language validation and routing behavior were reviewed against the architecture contract.
Then we moved from static code review to runtime isolation.
A Unique Request Changed the Investigation
We repeated the request using a unique query string that could not already exist as the same cached request.
This time the response was exactly what the application contract required.
The same test with an explicit English preference also behaved correctly.
RG Language Bridge was reading the cookie correctly and producing the correct routing decision.
Something else was returning the incorrect response before that application logic had an opportunity to execute.
When the Cache Considered Different Requests Equivalent
We identified NGINX server caching as the next variable and reproduced the failure in a controlled sequence.
First, the cache was cleared.
The second request generated the legitimate default 301 → /en/ response.
NGINX cached that response.
When the next request arrived with an explicit Spanish preference, the cache returned the previously stored redirect without considering the application state represented by the language cookie.
WordPress never had an opportunity to evaluate the preference.
More PHP Could Not Fix a Request That Never Reached PHP
The explicit language branches were already returning restrictive cache headers.
Those headers were correct.
But they only existed after WordPress executed the routing logic.
Once NGINX already had a cached representation of the root URL, it could answer the next request before PHP, WordPress or RG Language Bridge executed.
In the failing request, execution effectively stopped at the second node.
Even sending explicit client headers such as:
did not change the cached response.
Application code cannot correct a decision made before the application executes.
Remove One Variable and Repeat the Same Test
To confirm the diagnosis, we disabled NGINX caching and repeated exactly the same sequence.
Nothing else changed.
Same WordPress installation.
Same RG Language Bridge release.
Same routing contract.
Same cookies.
Same URLs.
The only variable removed was NGINX caching.
That isolated the failure to the infrastructure layer.
Every Component Was Correct in Isolation
This is where debugging stops being a component problem and becomes an architecture problem.
RG Language Bridge correctly evaluated the language preference.
WordPress correctly executed the application logic.
NGINX correctly cached repeated responses.
The failure appeared because the cache treated two requests as equivalent even though the application intentionally treated them as different states.
A cache cannot safely reuse a response when the application response depends on state the cache does not understand.
Apply Cache According to the Responsibility of Each Route
From an architectural perspective, the ideal solution was not to remove caching broadly across the site.
The language router and the content URLs have different responsibilities and, in an environment with sufficient configuration granularity, can use different cache policies.
Bypass Cache When the Language Cookie Exists
When the root URL receives a request containing rg_lang_pref, NGINX cache can be bypassed so RG Language Bridge can evaluate the visitor's explicit language preference.
Do Not Cache the Root Language Router
If cookie-aware bypass rules are unavailable, another option is to exclude only the root URL from server cache while keeping the English and Spanish content URLs cacheable.
This was the preferred architecture: allow content to continue benefiting from server caching while preserving access to the state required by the router to make the correct decision.
The final implementation, however, had to adapt to the actual capabilities of the hosting environment.
Adapting the Solution to the Constraints of the Environment
Our preferred solution was to bypass NGINX cache only when the root router needed to evaluate a request containing the rg_lang_pref cookie.
The hosting environment did not allow that level of granularity directly within the shared NGINX configuration for rgdigital.mx without affecting the broader hosting environment.
The available production solution was therefore broader.
Through the .htaccess configuration specific to RG Digital, HTTP headers were added instructing the server cache not to store or reuse responses generated by the site.
This kept the change scoped to rgdigital.mx without altering the global configuration of the hosting environment.
The tradeoff is explicit: RG Digital's HTML pages stopped benefiting from NGINX server-side caching.
Under the current hosting constraints, we prioritized correct routing and a consistent multilingual experience over preserving a cache optimization that could not safely distinguish between the different application states.
The application logic did not need to change. The cache policy around the application did.
Verifying the Resolution
After the infrastructure change, we repeated the exact same request sequence that had previously reproduced the collision.
We also verified the responses returned by the main English and Spanish content routes.
This confirmed both the resolution of the cache collision and the actual scope of the tradeoff: the site's HTML no longer uses NGINX server-side caching under the current configuration.
The previously reproducible failure disappeared without modifying RG Language Bridge, its routing contract or the multilingual content architecture.
If the hosting environment later supports more granular rules, the architecture can evolve toward a selective bypass for the router while keeping content pages cacheable.
The final test closed the investigation: the application was correct, and the production solution belonged at the boundary between application state and infrastructure caching.
A Digital System Does Not End at the CMS
The original symptom looked like a WordPress problem.
Then it looked like a redirect problem.
Then it looked like a cookie problem.
Our own application layer was audited before responsibility was assigned elsewhere.
The actual failure existed in the interaction between the application and the infrastructure serving it.
Software Engineering gave us control over the application.
Technical QA allowed us to validate that application against its contract.
Infrastructure analysis revealed why a correct application was producing an incorrect experience in production.
Digital Architecture means understanding not only how each component works, but how those components behave when they interact.
Is the problem really where you think it is?
Caching conflicts, redirects, analytics discrepancies, disconnected applications and infrastructure issues often appear to be isolated technical problems. Frequently, they are symptoms of how the underlying digital architecture has been designed.
Request a Digital Architecture Audit →
