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 05 · Multi-brand and multi-language
Keeping components shared across brands
Multi-brand and multi-languagePage 24 of 29Updated
A layout or component shared by several brands may differ between them only through tokens and attributes. Why brand checks inside shared templates cost more with every brand, how to compute brand values once, and the question to ask in review.
Who this is for. Developers and reviewers working on a codebase that serves several brands. After this page you can keep layouts and components shared as brands are added, and you have one question that settles a proposed brand condition in review.
The rule
A shared layout or component holds no brand-specific markup. It differs between brands in two ways only: the values of design tokens, which the brand attribute selects (Per-brand design tokens), and variables or attributes handed to it from outside. The logic that decides the brand lives in one place, above every shared template.
What a check at every call site costs
One real two-brand site tells its brands apart by environment, and tests $_currentSite->getEnvironmentId() === 4 directly inside more than fifteen component, form and page templates. Each test is small, but together they are the site's brand logic, spread through templates that were meant to be shared:
adding a third brand means finding and editing every one of them;
a reviewer cannot see in one file what differs between the brands;
a component copied to another project carries a test of an id that means nothing there.
Compute brand values once
The same site also has the better pattern: one include works out every brand-derived value a single time and hands it to the template that included it, so templates read a plain variable instead of repeating the test. In Smarty that is {assign} with scope="parent", in an include placed at the top of the base template. In Twig, set the values at the top of the base layout, before any include: an include receives the current variables, so every template below reads them.
Template code
{* includes/frontend/assign/brand.html, included once at the top of the base template *}
{$brands = [
'www.brand-one.example' => 'brand-one',
'staging.brand-one.example' => 'brand-one',
'www.brand-two.example' => 'brand-two'
]}
{$host = $_currentSite->getHostname()}
{$brandKey = 'default'}
{if isset($brands[$host])}{$brandKey = $brands[$host]}{/if}
{$brandHasShop = $brandKey == 'brand-one'}
{assign var="brandKey" value=$brandKey scope="parent"}
{assign var="brandHasShop" value=$brandHasShop scope="parent"}
{# at the top of the base layout, before any include #}
{% set brands = {
'www.brand-one.example': 'brand-one',
'staging.brand-one.example': 'brand-one',
'www.brand-two.example': 'brand-two'
} %}
{% set brandKey = brands[_currentSite.getHostname()]|default('default') %}
{% set brandHasShop = brandKey == 'brand-one' %}
Shared templates then read $brandKey and $brandHasShop (Twig brandKey, brandHasShop) and never test a hostname or an id themselves. A new brand is a line in this one file, and a value such as $brandHasShop is named for the feature it switches, not for the brand that has it.
The review question
Ask in review
When someone proposes {if $brandKey == 'brand-two'} inside a shared component, ask: is this a different component, or the same one styled differently?
The answer decides where the difference goes:
Styled differently: it is a token. Add or override a custom property under the brand's attribute, as in Per-brand design tokens.
Different in structure: it is a second component, or a brand override file with a fallback, as in Per-brand template folders. It is never a branch inside the shared one.
Different in what it offers: it is a value from the compute-once file, named for the feature, such as $brandHasShop.
Either way the shared component stays one file that every brand uses, and the brand list stays in one place.