Only add the preview_link_route cache on preview link routes, only add the...

I can confirm this issue with page_cache disabled and dynamic_page_cache enabled. With http.response.debug_cacheability_headers: true you can see X-Drupal-Cache-Contexts includes session on canonical pages for any entity that has a preview link configured, even for fully anonymous requests with no token.

Root cause 1 — PreviewLinkCanonicalRerouteAccessCheck

PreviewLinkRoutes attaches _access_preview_link_canonical_rerouter to every canonical entity route. When that access check runs, it unconditionally calls $this->privateTempStoreFactory->get('preview_link') on any entity that has preview links. Calling PrivateTempStore::get() starts a PHP session for the anonymous user, assigning them a unique session ID. The session cache context then resolves to that ID, so every new anonymous visitor gets their own dynamic page cache entry and the shared cache is never hit.

Even without the session being started, the session cache context was being declared before checking isStarted(), meaning the response was already marked as session-varying before the early return.

Root cause 2 — PreviewLinkEntityHooks::entityAccess()

$neutral (carrying the preview_link_route cache context and its routes cache tag) was constructed at the top of the function and returned from every early-exit path — including the path where $entityParameterName === NULL, i.e. when not on a preview link route at all. This added unnecessary cache metadata to every entity access check on every regular page.

Fix

Two changes:

  1. In PreviewLinkCanonicalRerouteAccessCheck::access(), move the session context declaration and the PrivateTempStore access to after an isStarted() check. A session is only ever started by claimToken() when a user visits an actual preview URL, so isStarted() === false means no tokens have been claimed and the canonical page is safe to cache without session variation.
  2. In PreviewLinkEntityHooks::entityAccess(), move $neutral construction to after all early-exit checks so the preview_link_route context is only added when we are actually on a preview link route and need it.

I used claude to tackle this. Someone smarter than me for sure should vet. It does seems to work correctly tho.

Merge request reports

Loading