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
Per-brand template folders
Multi-brand and multi-languagePage 22 of 29Updated
Keep one template set and put each brand's differences in a folder of its own, used only where the brand differs. The folder convention, the value that names the brand, and the fallback that keeps a brand without an override working.
Who this is for. The developer building one codebase for several brands. After this page you can lay out per-brand overrides, choose the value that identifies the brand, and give every override a fallback, in Smarty or Twig.
The folder convention
Shared templates stay where the platform expects them. Brand differences go in one folder per brand, holding only the files that brand changes, beside a default folder that holds every file any brand overrides. The multi-brand site in the case studies keeps them under includes/brands/, one file at a time in a generic/ folder:
A brand folder without a given file is the normal case: brand two above has its own logo and uses the default fonts. Overriding only what differs is what keeps the arrangement maintainable, and the fallback below is what makes it safe.
The brand on one site with several hostnames. It is the only one of the three that differs between the hostnames of one environment.
getPrimaryEnvironmentPrimaryHostname()
The primary hostname of the site's primary environment
The brand when each brand is a site of its own: the same on that site's development, staging and production environments, and different for each site. It does not read the request, so on one site it is the same for every hostname.
getPrimaryHostname()
The current environment's own primary hostname
An absolute link back to the same environment, not brand selection.
Every hostname is unique, so a brand's development and staging hostnames differ from its production one. On one site, map hostnames to a short brand key and name the folders by the key, so every environment of a brand finds the same folder:
{% 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') %}
With a site per brand, getPrimaryEnvironmentPrimaryHostname() is already the same in every environment of the brand, so it can name the folders directly or be mapped to a key the same way. Compute the key once, high in the page, and let every template read the variable: Keeping components shared across brands shows where.
The fallback when a brand has no override
Twig's include() takes a list of templates and renders the first one that exists, so the brand's file and the default are named together. This is the Twig engine's own behaviour. In Smarty, include only paths that exist: list which brands override which files, and test the list before including. Both versions render the brand's logo when the brand has one, and the default logo otherwise:
An include built from the brand key alone is safe only while every brand that reaches it has the file. Use the list form in Twig, or the override list in Smarty, for every brand include, and a new brand needs only the files in which it differs.
A theme that differs in structure
When brands differ in structure rather than in a file or two, give each group of brands a whole theme folder and let the module's default template choose between them. A blog post renders through blogs/posts/show.html; that file holds only the choice, and each theme folder holds a complete template. A post therefore picks its brand's template from the hostname it is served on:
{% if brandKey in ['brand-one', 'brand-two'] %}
{{ include('blogs/posts/themes/brand-group/show.html') }}
{% else %}
{{ include('blogs/posts/themes/default/show.html') }}
{% endif %}
Each theme is a full template set, so this form names the brands explicitly instead of falling back file by file. The included template receives the caller's variables, the post included.
Resolve it in one place
Put the resolution in one Smarty include or Twig macro that takes the file name, so templates call one name and the override list lives in one file. A new brand is then a key in the map and a folder holding only what differs.
Copy that differs by brand
Text that differs by brand, such as a legal line or a price, belongs in a global component per brand rather than in a template file, because an editor can change it without a deploy. Give the components identifiers that end in the brand key, and read the one for the current brand:
{% set brandCopy = _globalComponents.get('brandCopy_' ~ brandKey) %}
{% if brandCopy %}
<p class="legal">{{ brandCopy.legalLine }}</p>
{% endif %}
A global component can belong to one site or to every site of the client, so the same identifiers work with either arrangement: one shared set of brand components, or each site holding its own.