Cache problem – Request for clarification / improvement
-
Hello LiteSpeed Support Team,
I am reporting a rather unusual LSCache for WordPress caching behavior and would appreciate a detailed explanation from the LiteSpeed team, as well as guidance on whether there is a supported way to achieve the desired behavior without custom workarounds.
The use case is very simple:
I have a WooCommerce/WordPress site where all publicly accessible content is identical for guests and logged-in non-admin users.
There is no user-specific content on the public-facing pages.
There is no cart counter, username, personalized greeting, account information, customer-specific pricing, or any other user-specific fragment in the public header or public page content.
The genuinely private areas are already excluded from caching, including:
- Cart
- Checkout
- My Account
- Authentication pages
- Wishlist
The goal is therefore:
Guest → Public Cache
Logged-in non-admin → the exact same Public Cache
Administrator → optionally a separate variation
Cart / Checkout / My Account / Auth / Wishlist → remain completely uncachedI am intentionally NOT looking for Private Cache and I do NOT want ESI for this use case.
The desired architecture is simply:
Guest + Logged-in Non-Admin
↓
Same Public Cache Objectwhile genuinely private pages remain uncached.Environment / configuration
The site is using:
- WordPress
- WooCommerce
- Woodmart theme
- LiteSpeed Web Server Enterprise
- LiteSpeed Cache for WordPress
- ESI currently OFF
- “Cache Logged-in Users” currently OFF
The site already has working public caching for guests.
Guest caching is not the problem.
The problem is specifically how LSCache handles logged-in users when they should logically be identical to guests.The original behavior
With:
Cache Logged-in Users = ON
logged-in users receive Private Cache behavior.
That is not what I want.
Private Cache is unnecessary for this site because the public pages are not personalized.
So I disabled:
Cache Logged-in Users = OFF
After doing that, the Private Cache behavior disappeared, which is expected.
However, the logged-in requests then became uncached:
Guest:
Public Cache → working normallyLogged-in:
No CacheThis is also consistent with the current LSCache behavior.
From the current LSCache source, I understand that when a user is logged in, ESI is disabled, and private logged-in caching is disabled, LSCache explicitly marks the request as non-cacheable with the reason “logged in user”.
The relevant current source behavior is essentially:
- logged-in + ESI OFF + Cache Logged-in ON → private cache
- logged-in + ESI OFF + Cache Logged-in OFF → no cache
This appears to be intentional behavior rather than a WooCommerce or Woodmart bug.
This is precisely where my use case differs from the normal assumption:
I am deliberately asking LSCache to treat a logged-in non-admin exactly like a guest for public pages because the generated public content is the same.Important discovery:
_lscache_varyDuring investigation I found that logged-in requests receive a cookie similar to:
_lscache_vary=admin_bar:1;logged-in:1while a normal guest request does not have this logged-in vary state.
This is understandable given the current LSCache implementation.
The current source explicitly adds:
logged-in:1for logged-in users.
It can also add:
admin_bar:1depending on the
show_admin_bar_frontuser option.The current source then applies the
litespeed_varyfilter before hashing the vary data.This led to the discovery that there are really two separate problems:
- Logged-in users are classified as non-cacheable when ESI and Private Logged-in Cache are both disabled.
- Logged-in users also receive a different
_lscache_varystate, which causes them to use a different cache variation from guests.
These two behaviors are extremely important for this use case.Testing with Force Public Cache
I then tested the built-in:
“Force Public Cache URIs”
functionality.
For example, I tested public pages such as:
/privacy-terms/The result was very interesting.
For a logged-in user, the response showed:
X-LiteSpeed-Cache-Control: public,max-age=1209600so the Force Public mechanism clearly worked and the response was allowed to become publicly cacheable.
However, the logged-in request still behaved as a separate cache variation.
For example:
Guest:
X-LiteSpeed-Cache: missthen subsequent guest request:
X-LiteSpeed-Cache: hitLogged-in:
X-LiteSpeed-Cache: missthen subsequent logged-in request:
X-LiteSpeed-Cache: hitThis strongly indicated that both requests were publicly cached but were not sharing the same cache object.
In other words:
Guest → Public Object A
Logged-in → Public Object Binstead of:
Guest + Logged-in → Public Object A
This distinction is critical.
Force Public solved the “can this logged-in request be cached?” problem, but did not by itself solve the “can it use the exact same cache variation as the guest?” problem.
This also appears consistent with LiteSpeed’s cache-vary architecture, where cache varies are part of the cache key and multiple publicly cached versions can exist for the same URI.Admin Bar investigation
Another discovery was that logged-in users could receive:
_lscache_vary=admin_bar:1;logged-in:1even when the Admin Bar was not visibly displayed to normal users.
The current LSCache source checks the WordPress user option:
show_admin_bar_frontand considers the admin bar active when that option is false/unset or explicitly true.
I therefore also disabled the frontend Admin Bar for non-admin users while preserving the administrator’s behavior.
This removed the unnecessary Admin Bar variation for regular users, but the core
logged-in:1distinction still remained.So the Admin Bar was not the fundamental issue.A key experiment:
litespeed_vary_noI then investigated the official LSCache API and tested:
litespeed_vary_noThe idea was to tell LSCache not to create/use a vary for the current page.
The response showed:
X-LiteSpeed-Cache-Control: public,no-vary,max-age=1209600which proves the API was being executed.
However, the behavior was not suitable when used in the first implementation.
In one test, the logged-in request continued to MISS repeatedly rather than converging cleanly onto the guest object.
More importantly, I observed that indiscriminately disabling the entire vary state can interfere with legitimate variations such as the administrator variation.
This made it clear that simply disabling all varies is too blunt for this use case.
I do not want to remove all Vary functionality.
I specifically want:
Guest
and
logged-in non-adminto share the same public cache variation,
while retaining the ability for an Administrator variation to remain separate if desired.
That distinction is very important.The cache lookup timing is also important
One of the hardest parts of this investigation was understanding when
_lscache_varymatters.My understanding is that the web server performs the initial cache lookup before WordPress/PHP executes.
Therefore, if the browser arrives with:
_lscache_vary=admin_bar:1;logged-in:1the server can perform the cache lookup using that variation before PHP has an opportunity to change anything.
This explains a particularly confusing behavior:
If the guest cache is already warm and a logged-in user still has the old vary cookie, the logged-in request can MISS even though the guest object already exists.
PHP then runs.
If the code causes the vary cookie to disappear from the response, subsequent requests can converge toward the guest cache variation, but that first request was already looked up under the logged-in vary state.
Likewise, if the destination page is cold, the logged-in request can MISS first, PHP runs, and the page may then become cacheable if Force Public applies.
This behavior makes the distinction between:
- cache lookup key
- response cacheability
- response Set-Cookie
- subsequent browser requests
extremely important.Current successful workaround
After several experiments, I found one workaround that finally produces the behavior I actually want.
The workaround does NOT modify the WordPress authentication cookie.
It only removes the LiteSpeed-specific:
_lscache_varycookie from the response for logged-in non-admin users.
The actual WordPress authentication cookie:
wordpress_logged_in_*remains untouched.
This does not log the user out because
_lscache_varyis not the authentication cookie.The result is that once the LiteSpeed vary cookie is no longer sent by the browser, the logged-in non-admin request can be treated like the guest request from the cache-key perspective.
The effective model becomes:
Guest:
no logged-in vary cookie
→ guest/public cache variationLogged-in non-admin:
no_lscache_vary
→ same public cache variationAdministrator:
still allowed to retain the administrator variationThis workaround finally gives us the behavior we wanted.Another important observation: logged-in users need Force Public for first-time cache warming
There is another subtle but important part of this use case.
With:
Cache Logged-in Users = OFF
ESI = OFFa logged-in request is normally marked non-cacheable.
Therefore, if a logged-in user is the first person to request a cold public page, that request does not normally warm the cache.
To allow logged-in users to warm public pages as well, I have to use:
“Force Public Cache URIs”
for the public URLs I actually want cached.
This is expected from the current design: Force Public is what overrides the normal non-cacheable condition for the logged-in request.
So the desired final configuration becomes approximately:
Cache Logged-in Users = OFF
ESI = OFFPublic pages:
Force Public CachePrivate pages:
Do Not CacheLogged-in non-admin:
LiteSpeed vary cookie suppressedAdministrator:
optional separate variation retainedOur current “Do Not Cache” rulesThe following private URL prefixes are explicitly excluded from caching:
^/checkout^/cart^/my-account^/auth^/wishlistThe intention is that these pages remain non-cacheable for both guests and logged-in users.
The custom workaround does not call any Force Cache or Set Cacheable function on these pages.
It only changes the LiteSpeed vary cookie behavior.
This distinction is important because I do NOT want this workaround to accidentally override the site’s genuine no-cache rules.What I believe would be the ideal native LiteSpeed solution
I would strongly prefer not to maintain a custom cookie-manipulation workaround indefinitely.
What I really want LiteSpeed Cache for WordPress to support natively is something conceptually like:
“Treat logged-in users as the default public cache group when their public-facing output is identical to the guest view.”
For example:
Cache Mode:
Guest + Logged-in Non-Admin
→ same public cache variationAdministrator
→ optional separate public variationPrivate URLs
→ still completely uncachedThis would be much cleaner than forcing customers to discover and work around:
- Private Cache
- ESI
logged-in:1admin_bar:1_lscache_vary- Force Public
- cache-key behavior before PHP
- and custom
Set-Cookiemanipulation
just to achieve “logged-in user receives the same public page as an anonymous visitor.”Why I am reporting this as a potential product/design issue
I understand why LSCache is conservative.
For most WordPress sites, logged-in users genuinely have different content.
Private Cache and ESI are therefore sensible and valuable features.
But there is an important class of sites where logged-in users have no personalized public-page content whatsoever.
For those sites, the current behavior creates a rather surprising situation:
The page is publicly cacheable for guests.
The page is visually and functionally identical for logged-in non-admin users.
Yet:
- Private Cache is unnecessary.
- ESI is unnecessary.
- Logged-in Cache OFF causes No Cache.
- Force Public is required to override the logged-in no-cache rule.
_lscache_varycreates a separate variation.- And the administrator/user-state variation has to be carefully preserved.
This is a considerable amount of complexity for what should logically be a very simple caching scenario.
Even more importantly, a user who does not deeply understand the LSCache vary architecture could easily create an unsafe configuration while trying to solve it.
For example, blindly removing all Vary information can potentially cause an administrator-specific public response to become shared with normal visitors.
That is exactly the kind of thing I would like LiteSpeed to make impossible or at least much harder to do incorrectly.My request to LiteSpeed
Could you please review this use case and confirm the intended/correct supported mechanism?
Specifically, I would like to know:
- Is there an officially supported way to make a logged-in non-admin user use the exact same public cache variation as a guest, while retaining a separate variation for administrators if required?
- Is removing
_lscache_varyfor logged-in non-admin users a safe and supported approach, or is there a better server/plugin-level mechanism intended for this? - Is there a supported way to configure LSCache so that:
- logged-in non-admin = default public cache group
- administrator = optional separate public variation
- private WooCommerce pages = still uncached
- Does LiteSpeed consider it correct that:
Cache Logged-in Users = OFFESI = OFF- logged-in user
results in explicitNO CACHEeven when the page is otherwise completely public?
- Would you consider adding a dedicated setting such as:
“Share Public Cache with Logged-in Users”
or an equivalent safe mechanism?
Ideally such a setting would allow the plugin/server itself to handle the cache lookup correctly rather than requiring users to manipulate
_lscache_varyfrom PHP.Why a native solution would be valuableThis is not just a request for one site.
The underlying use case is quite common:
- informational sites with optional accounts
- WooCommerce shops with no user-specific public pricing
- stores where the cart/account/checkout are private but product/catalog pages are completely public
- membership systems where public pages remain identical for everyone
- sites that authenticate users but do not personalize the public frontend
In those environments, it would be extremely useful if LiteSpeed could natively express:
“This user is logged in, but for this public page they should be treated as an anonymous/public-cache visitor.”
That would avoid custom PHP, cookie manipulation, fragile interactions with Vary, and the possibility of users accidentally exposing administrator-specific content.
I would sincerely encourage the LiteSpeed team to consider improving this behavior or documentation so that other users do not have to spend hours reverse-engineering the interaction between logged-in detection, Private Cache, ESI, Vary Groups,
_lscache_vary, and Force Public Cache.Summary of the investigationThe final behavior we are trying to achieve is:
Guest:
→ Public CacheLogged-in non-admin:
→ exactly the same Public CacheAdministrator:
→ optional separate public variationCart:
→ No CacheCheckout:
→ No CacheMy Account:
→ No CacheAuth:
→ No CacheWishlist:
→ No CacheESI:
→ OFFPrivate Logged-in Cache:
→ OFFThe current LSCache implementation appears to support the individual pieces of this architecture, but not in one clean configuration.
The current source confirms that logged-in detection adds
logged-in:1to the default vary and that, with ESI disabled and Private Logged-in Cache disabled, logged-in requests are explicitly marked non-cacheable.The current Vary architecture also allows multiple public cache versions, which explains why simply making the logged-in request public does not necessarily make it share the exact same public object as the guest.
I would greatly appreciate any clarification from the LiteSpeed team on the officially supported solution, and especially any recommendation that avoids custom manipulation of
_lscache_vary.Thank you for taking the time to look into this.
Best regards
You must be logged in to reply to this topic.