Step 2: Add a layout
In this step, you add the Acme layout. Every Acme page extends it, so the header, the footer and the stylesheets are in one file.
What you'll build
components/theme_layout.html, which extends Shop Base Theme'scomponents/base.html- A header with the store logo, a Shop link and a cart count
- A footer with the year and the store name
1. Create the layout file
Create acme_theme/themes/acme/components/theme_layout.html:
{% extends "components/base.html" %}
{% from "components/macros/branding.html" import brand_logo with context %}
{% block head %}
{# The shared toaster that base.html includes is styled with Tailwind utilities, so a plain-CSS theme still loads them. #}
<link rel="stylesheet" href="/assets/commera/css/tailwind.css">
<link rel="stylesheet" href="{{ shop_theme_asset_url('css/acme.css') }}">
{% endblock %}
{% block body_class %}theme-acme{% endblock %}
{% block chrome_top %}
{% block site_header %}
<header class="acme-header">
<a class="acme-brand" href="/{{ frappe.lang or 'en' }}">{{ brand_logo(css_class="acme-logo") }}</a>
<nav class="acme-nav">
<a href="/{{ frappe.lang or 'en' }}/products">{{ _("Shop") }}</a>
<a href="/{{ frappe.lang or 'en' }}/cart">
{{ _("Cart") }} (<span x-text="$store.cart.items.length">0</span>)
</a>
</nav>
</header>
{% endblock %}
{% endblock %}
{% block chrome_bottom %}
{% block site_footer %}
<footer class="acme-footer">
<p>© {{ frappe.utils.nowdate()[:4] }} {{ app_name }}</p>
</footer>
{% endblock %}
{% endblock %}
components/base.html is not in your theme. Commera finds it in the parent theme, Shop Base Theme. The same is true for components/macros/branding.html, which has the brand_logo() macro.
The cart count reads $store.cart. Shop Base Theme loads that Alpine store on every page, so your layout does not load it.
2. Fill the right blocks
components/base.html has these blocks. Fill the blocks that your theme needs, and leave the others alone.
| Block | Where it is | Fill it with |
|---|---|---|
seo |
In <head> |
Leave it. A page sets the seo context variable instead. |
json_ld |
In <head> |
Leave it. A page sets the json_ld context variable instead. |
analytics_head |
In <head> |
Leave it. It has the merchant's analytics tags. |
alpine_plugins |
In <head>, before Alpine starts |
<script> tags for extra Alpine plugins |
head |
End of <head> |
Your stylesheets, fonts and preload tags |
body_class |
The class of <body> |
A class for your theme, such as theme-acme |
body_attributes |
Inside the <body> tag |
Extra attributes. Start with a space: id="bg". |
chrome_top |
Before <main> |
The header |
body |
Inside <main> |
The page content. Each page fills this block. |
uncontained_body |
Inside <main>, after body |
Content that a page adds after its main content |
chrome_bottom |
After <main> |
The footer |
analytics_events |
End of <body> |
Leave it. It sends the storefront's analytics events. |
script |
After </body> |
Your scripts |
Name the header and footer blocks
Name the layout file components/theme_layout.html. Put the header in a block named site_header and the footer in a block named site_footer, as the Acme layout does. The names header and footer also work. The /commera dashboard renders this file to preview the header and the footer, and it empties the block that it does not show. With a different file name or different block names, the preview shows the wrong part of the page.
3. Import macros with context
{% from "components/macros/branding.html" import brand_logo with context %}
4. Load Tailwind for the toast
Shop Base Theme adds a toast, the "Item added to your bag" message, to every page. The toast uses Tailwind CSS classes. Acme is plain CSS, so the layout loads Commera's Tailwind file before its own CSS:
<link rel="stylesheet" href="/assets/commera/css/tailwind.css">
<link rel="stylesheet" href="{{ shop_theme_asset_url('css/acme.css') }}">
Without it, the toast shows as a large unstyled shape under the footer.
Tailwind resets the size and weight of headings. Set h1, h2 and the other headings in your own CSS. Shop Default Theme loads the same file. Load it in a Tailwind theme too, because your own Tailwind build contains only the classes that your templates use.
Next steps
- Step 3: Add pages
- Templates: every context variable and Jinja helper