Guide 00 · Developer docs

Core dna for site builders

Read this guide first. Core dna is hosted, so there is nothing to install; your repository holds only templates and front-end assets; and a new kind of page starts in the admin, with a layout. In half a day, from what the platform is to a page you built, deployed and rendered in Smarty or Twig.

L0
Unit 05 · Choosing what to read next

Conventions every theme follows

The house rules for every Core dna theme, stated once so no later page repeats them: BEM class names in SCSS, a bundle per page type, a nonce on every script tag, a cache-buster on every asset URL, no secrets in tracked files, escaped output, and links built from route names.

Who this is for. Everyone who writes or reviews a theme. Later guides assume these rules without restating them. Some are the platform's own requirements, marked as such; the rest are the house style that keeps one theme readable to the next developer.

The rules

RuleWhyIn depth
SCSS with BEM class names: .card, .card__title, .card__title--largeClass names that say what they belong to and cannot collide between componentsStyling
A bundle per page type: shared code in the main bundle, code one kind of page needs in its own entryEach page loads only what it usesBuilds, bundles and script tags
A nonce on every script tag: nonce="{$_inlineScriptNonce}". A platform requirementThe site's Content Security Policy refuses an inline script without itAssets, CSP and the build pipeline
A cache-buster on every asset URL, usually the deployed commitBrowsers keep built files for a yearThe build output is committed and served
The production build, committed with its source. A platform requirementThe server builds nothing; it serves what is committedThe build output is committed and served
No secrets in tracked filesThe repository is copied to every developer and every environment that follows itConfiguration and secrets per environment
Escape what you print: |escape in Smarty, |e in TwigNeither engine escapes output for you on Core dnaSmarty and Twig side by side
Links built from route names with _url, not typed pathsA site can change a module's prefix; a built link follows itGlobal template variables

The nonce, in both engines

The policy is the site setting CSP policy (Globals.security.cspPolicy); by default it allows scripts from the site itself, from cdnjs.cloudflare.com, and inline scripts that carry the request's nonce. The nonce changes on every request, so it is printed from _inlineScriptNonce, never copied:

Template code
<script nonce="{$_inlineScriptNonce}">
  document.documentElement.classList.add('js');
</script>
<script src="/dist/app.js?v={$_currentSite->getLastVcsHash()}" nonce="{$_inlineScriptNonce}" defer></script>
<script nonce="{{ _inlineScriptNonce }}">
  document.documentElement.classList.add('js');
</script>
<script src="/dist/app.js?v={{ _currentSite.getLastVcsHash() }}" nonce="{{ _inlineScriptNonce }}" defer></script>

An external script from the site's own origin is allowed by the default policy without a nonce, but a site may tighten its policy. Giving every script tag the nonce keeps a theme working whichever policy the site sets. A refused script shows only as an error in the browser's console, never on the page.

Go deeper

Was this page helpful?

Your answer goes to the docs team.