How-to library · Developer docs

How-to library

Task-shaped pages: a title that starts with a verb, the situation in a few lines, the steps, the working code in both engines, and why this way rather than another. Found from a search, done, and left.

Build a global header and footer an author can edit

A global component is stored once, versioned, and edited by authors without a deploy. Give it a component layout, an identifier, and fetch it in the base template with _globalComponents.get(). Its template reads areas as any component does.

Context

Context. The header's logo, tagline and footer columns change more often than any template. Make each a global component: one record, stored at site level (or account-wide), with its own layout, its own areas and its own versions, that an author edits in the admin. The base template fetches it by identifier. The current site's component is found first, then an account-wide one with the same identifier, so a multi-site account can share a footer and override it per site.

Steps

  1. Create templates/components/site-header.html and site-footer.html, and deploy. Register both as layouts.
  2. In the admin, add a global component Site header with identifier site-header and that layout; fill its layout areas (logo image, tagline, a call-to-action label and URL). Repeat for the footer.
  3. In the base template, fetch each by identifier and render it, guarding for nothing.
  4. For anything that must switch on and off (an announcement bar), add a switch area and read it: a global component has no publish switch of its own.

Template code

Template code
{* base template *}
{$header = $_globalComponents->get('site-header')}
{if $header}{$header->getHtml()}{/if}
…
{$footer = $_globalComponents->get('site-footer')}
{if $footer}{$footer->getHtml()}{/if}

{* templates/components/site-header.html *}
<header class="site-header">
  {$logo = $component->getAreaImage('logo')}
  <a href="/">{if !$logo->isBlank()}{$logo->getResized(null, 48)->getHtml(['alt' => $_currentSite->getName()|escape])}{else}{$_currentSite->getName()|escape}{/if}</a>
  {if $component->showAnnouncement}<div class="announce">{$component->announcement}</div>{/if}
  {include 'includes/frontend/nav.html'}
</header>
{# base template #}
{% set header = _globalComponents.get('site-header') %}
{% if header %}{{ header.getHtml() }}{% endif %}
…
{% set footer = _globalComponents.get('site-footer') %}
{% if footer %}{{ footer.getHtml() }}{% endif %}

{# templates/components/site-header.html #}
<header class="site-header">
  {% set logo = component.getAreaImage('logo') %}
  <a href="/">{% if not logo.isBlank() %}{{ logo.getResized(null, 48).getHtml({'alt': _currentSite.getName()|e}) }}{% else %}{{ _currentSite.getName()|e }}{% endif %}</a>
  {% if component.showAnnouncement %}<div class="announce">{{ component.announcement }}</div>{% endif %}
  {{ include('includes/frontend/nav.html') }}
</header>

Why this and not that

Not areas on every page layout for the header: the same content on every page is one record, not a copy per page. Not a global component without an identifier: one without it can only be placed by an author, never fetched by a template. Not getHtml() on the result unguarded: get() returns nothing when the identifier does not exist, and in Smarty that fails the page. A global component whose layout has no template still works as a settings store read with getAreaText(), for brand colours or contact details.

Go deeper

Was this page helpful?

Your answer goes to the docs team.