Guide 01 · Developer docs

Choosing how to build

Decide where the pages of a Core dna site are composed before writing code: on the platform, in your own application, or on the platform with a few pieces filled in by the browser. The decision tree, each shape in depth, multi-brand and languages, and a table and case studies to make the call.

L2
Unit 04 · Hybrid, the common case

The three things that always need a fragment

Sign-in state, the cart count and personalised blocks: why each one breaks a cached page in its own way, and the cart count as a fragment from end to end. Put these three in fragments in the first sprint and the rest of the site can stay cached.

Who this is for. The theme developer planning a site's header and home page. Knowing this list in the first week saves the week spent finding it later. After this page you can recognise each of the three in a design and build the fragment for it, using the mechanism on Dynamic fragments.

The three, and why each one fails

ElementWhat goes wrong in a cached page
Sign-in state: the header's Sign in or My account and Sign out, a member's nameThe stored copy was rendered for someone not signed in, and it is sent before the platform knows who is asking, so a member sees Sign in on every cached page
The cart countVisitors who are not signed in have carts too, kept by a cookie. The page rendered for the first of them is stored with their count, and every later visitor sees it
Personalised blocks: recommendations, welcome back, member-only offers, anything built from what the site knows about the visitorEither the first visitor's version is stored and shown to everyone, or the block is built in the browser from data the cached page must not contain

The first two are in the header of almost every page, which is why they matter so much: one personal element in a shared header makes every page on the site either wrong or uncacheable.

The cart count, end to end

A page on the Fragment layout with the slug cart-count, a placeholder in the header, and this template. _cart is available in every template; its getCart() returns the visitor's cart:

Template code templates/fragments/cart-count.html
{$_response->preventCaching()}
{$count = 0}
{foreach $_cart->getCart()->getItems() as $item}
  {$count = $count + $item->getQuantity()}
{/foreach}
<span class="cart-count" data-count="{$count}">{if $count > 0}{$count}{/if}</span>
{% do _response.preventCaching() %}
{% set count = 0 %}
{% for item in _cart.getCart().getItems() %}
  {% set count = count + item.getQuantity() %}
{% endfor %}
<span class="cart-count" data-count="{{ count }}">{% if count > 0 %}{{ count }}{% endif %}</span>
Template code In the header include
<a href="/cart" class="cart-link">
  Cart <span data-fragment="/fragments/cart-count"><span class="cart-count"></span></span>
</a>
<a href="/cart" class="cart-link">
  Cart <span data-fragment="/fragments/cart-count"><span class="cart-count"></span></span>
</a>

The script on Dynamic fragments fills it in. When the cart changes on the page, the cart's own API answer has the new contents, so the script updates the count from that answer rather than fetching the fragment again.

  • One request for the header. Sign-in state and the cart count can share a fragment. A course provider's site renders both in one header fragment, so a page view costs one extra request, not two.
  • getCart() creates a cart. For a visitor who has none, reading the cart creates and saves an empty one. Fetch the cart-count fragment only on pages that show the count.
  • Personalised blocks are fragments too, often with parameters that come from the browser: A personalisation bundle that loads only when it is on follows one through.
Go deeper

Was this page helpful?

Your answer goes to the docs team.