Skip to content

Anonymous visitors receive a session cookie on every page view, disabling full-page caching #3210

Description

@lifterlms-maurice

Summary

LifterLMS sets a wp_llms_session_<COOKIEHASH> cookie on the first page view of every anonymous visitor, including on pages with nothing to do with LifterLMS (home page, blog posts, marketing pages, 404s). Full-page caches refuse to store any response carrying a Set-Cookie header (otherwise one visitor's session would be served to everyone), so the practical effect is that activating LifterLMS disables anonymous full-page caching site-wide.

Reproduction Steps

  1. Install LifterLMS on a site with a full-page cache (Surge, Cloudflare, Varnish, WP Super Cache, W3TC, host-level cache).
  2. As a logged-out visitor, request any front-end URL (home page, a blog post, a 404).
  3. Inspect the response headers.

Expected Behavior

An anonymous page view that never touches the LifterLMS session (no coupon applied, no notice queued) should not emit a Set-Cookie: wp_llms_session_... header and should stay cache-eligible.

Actual Behavior

Every anonymous front-end response carries Set-Cookie: wp_llms_session_<hash>=... plus a no-cache Cache-Control, so the page cache stores nothing for logged-out traffic. Captured on a live site:

set-cookie: wp_llms_session_<hash>=...; path=/; secure; HttpOnly
cache-control: private, max-age=0, no-cache

Root Cause

LLMS_Session::init_cookie() (includes/class.llms.session.php) eagerly mints a session and emits the cookie for any visitor without an existing one ($set_cookie = true), even though nothing has used the session. The cookie's only purposes are preserving an applied coupon during checkout and storing notice messages, both of which write via LLMS_Session::set().

Proposed Fix

Make the cookie lazy: defer emission until the first session write. Same philosophy already shipped for the llms-tracking cookie in #2330 / #2331. A grep of core + all first-party add-ons confirms every session writer goes through LLMS_Session::set() (core checkout + AJAX coupons, llms_add_notice(), Advanced Coupons coupon-from-URL, Gifts voucher count, Groups seat count) and none relies on eager creation, so this is safe default-on. The llms_session_should_init filter stays as the escape hatch.

This issue has been recreated:

  • Locally / from source
  • On a staging site
  • On a production website (header capture)
  • With only LifterLMS and a default theme

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions