Who this is for. The theme developer and the lead, before the first template is written. After this page you know the two costs of server-side rendering, can predict which pages the platform will cache, and know why one personal element needs a fragment of its own.

Every interaction is a round trip

A server-rendered page changes by loading another page: a filter, a form step, a quantity in the cart. That is fine for most of a content site and wrong for a few interactions, which is where JavaScript earns its place, calling the API or a small page of the site instead of reloading the whole page. Keep the list of those interactions short and explicit; it is the island list of a hybrid site.

The page cache rules that decide what is personal

  • Only pages rendered for visitors who are not signed in are stored, and only a GET that answered 200 and did not ask for JSON. A page rendered for a signed-in visitor is never stored. Nothing is stored in a development environment.
  • The stored copy is sent before the platform checks who is asking. A signed-in member asking for a page that is in the cache gets the copy that was rendered for someone who was not signed in.
  • The copy is stored per hostname and path. A query parameter counts only if the template read it with $_request->getParameter(), which declares it, or declared it with addCacheVaryParameter(). Any other parameter is ignored, so /offers?region=nsw and /offers?region=vic share one copy when the region is read by a script, or through getQueryString().

What one personal element does

Put a personal element straight into a cacheable page, and one of two things happens, depending on who it is personal to:

ElementWhat visitors seeWhy
Something that differs between visitors who are not signed in, such as a cart countThe first visitor's value, shown to everyone until the copy expiresVisitors without an account have carts too; the page rendered for the first of them is the one stored
Something only a signed-in member has, such as their name or a sign-out linkMembers see the signed-out version on any page already in the cacheThe stored copy was rendered for someone not signed in, and it is sent before the platform knows who is asking

The blunt fix is to switch the cache off for the page with preventCaching(), and then every view of that page is a full render. On a page every visitor sees, such as the home page or a header shared by every page, that is the whole site's traffic rendered from scratch. The better fix is to take the personal element out of the page and fetch it separately, as a small fragment that is never cached, after the cached page has loaded. That pattern, and the three elements that always need it, are the subject of the next unit: Dynamic fragments.