Skip to content

Prevent full-page cache from storing live checkout shortcode/block state #1330

@superdav42

Description

@superdav42

Problem

Pages that embed the Ultimate Multisite checkout shortcode/block can be cached as anonymous marketing pages even though the rendered checkout markup contains per-request state.

Observed on https://sdaiagent.com/get-your-free-demo-site/:

  • A normal production request returned x-sidekick-cache: HIT and public cache headers.
  • The cached HTML reused hidden checkout values such as generated usernames/nonces/captcha context across different visitors.
  • New visitors then hit validation failures such as duplicate customer/username or captcha verification failure before signup could proceed.
  • A cache-busted request returned x-sidekick-cache: MISS, no-store/no-cache headers, fresh hidden checkout values, and the flow worked in local/dev testing.

A path-level production workaround can protect known URLs, but the correct fix belongs in Ultimate Multisite so any page embedding checkout is safe regardless of permalink.

Goal

Allow cacheable marketing content for anonymous first visitors and bots where possible, while ensuring live checkout state is always generated fresh once a visitor starts checkout.

Recommended design

Phase 1: protect live checkout output

In the shared checkout shortcode/block render path, send explicit no-cache signals whenever the live checkout form is rendered.

Primary file/pattern:

  • inc/ui/class-checkout-element.php
  • Checkout_Element::output() is shared by shortcode and block rendering.

Suggested behavior:

  • Call nocache_headers() before outputting live checkout markup.
  • Define DONOTCACHEPAGE if not already defined.
  • Optionally add a UM-specific action/filter so cache adapters can react, e.g. do_action( 'wu_checkout_nocache_required', $atts, $this ).

This ensures [wu_checkout] and the checkout block cannot be cached with stale nonce/order/captcha/autogenerated-field state.

Phase 2: preserve first-visit marketing-page cache with deferred checkout

Add an optional deferred/lazy checkout mode for marketing pages:

  1. Initial shortcode/block render can output a cache-safe placeholder/shell.
  2. On explicit user intent, JS fetches the live checkout form via an AJAX/REST endpoint.
    • examples of intent: CTA click, form focus, checkout placeholder enters viewport.
  3. The AJAX/REST endpoint sends no-cache headers and returns fresh checkout markup/state.
  4. The endpoint can set/commit a checkout-intent/session cookie so subsequent requests bypass page cache.

This lets bots and passive anonymous visitors receive cached marketing HTML, while real checkout users receive fresh dynamic checkout state.

Cookie/cache notes

Ultimate Multisite already has a signup session cookie:

  • wu_session_signup
  • implemented by Session_Cookie
  • created through wu_get_session( 'signup' )

Relevant files/patterns:

  • inc/functions/session.php
  • inc/class-session-cookie.php
  • inc/checkout/class-checkout.php

That cookie is useful as a cache-bypass signal after checkout has started, but it is not sufficient for the first live checkout render because the first anonymous GET does not have the cookie yet.

Recommended cache-bypass signals:

  • no-cache headers when live checkout markup is rendered
  • DONOTCACHEPAGE for WordPress cache-plugin compatibility
  • wu_session_signup cookie as a subsequent-request bypass signal
  • optional lightweight wu_checkout_intent=1 cookie for deferred checkout mode

Acceptance criteria

  • A page containing [wu_checkout] or the UM checkout block does not produce publicly cacheable live checkout HTML.
  • The response with live checkout markup includes no-cache/no-store headers.
  • The fix works for arbitrary permalinks, not only /checkout or /get-your-free-demo-site/.
  • Optional deferred mode allows the surrounding marketing page to be cached until the visitor expresses checkout intent.
  • Tests cover shortcode/block detection or render behavior so future checkout render changes do not regress cache safety.

Verification

  • Create a page with [wu_checkout slug="..."] on a non-checkout marketing URL.
  • Request it twice as an anonymous visitor.
  • Confirm live checkout HTML is not served from full-page cache with reused hidden usernames/nonces/captcha context.
  • Confirm a deferred-mode page remains cacheable before intent, then fetches fresh checkout markup after intent.

aidevops.sh v3.20.6 plugin for OpenCode v1.15.13 with gpt-5.5 spent 3d 21h and 111,419 tokens on this with the user in an interactive session.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingorigin:interactiveCreated by interactive user sessionpriority:highHigh severity — significant quality issuesolved:interactiveTask was solved by an interactive session

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions