A Commera theme has three parts: a Shop Theme record, a theme folder with templates, and a public folder with assets. All three are in the Frappe app that owns the record's Module.
Folder layout
The folder name is the theme name in lowercase, with spaces and hyphens changed to _. For Acme Catalog, it is acme_catalog. Two themes cannot have the same folder name, so My-Theme and My Theme cannot both exist.
| Path in your app | What it holds | Served to the browser |
|---|---|---|
<app>/themes/<folder>/components/ |
The layout, includes, macros and sections that pages use | No |
<app>/themes/<folder>/pages/ |
One .html per page, each with an optional .py controller |
No |
<app>/themes/<folder>/styles/ |
CSS sources for a Tailwind build | No |
<app>/themes/<folder>/tailwind.input.css |
The Tailwind entry file, for a Tailwind theme only | No |
<app>/public/themes/<folder>/ |
CSS, scripts, images, fonts and a Tailwind output file | Yes, at /assets/<app>/themes/<folder>/ |
<app>/<module>/shop_theme/<folder>/<folder>.json |
The theme record | No. bench migrate imports it. |
The first save of a new record in developer mode makes these empty folders: components/includes, components/macros, pages and styles in the theme folder, and images and scripts in the public folder. Add other folders under components/ as you need them, for example sections/ and overlays/.
There is no manifest file. The Shop Theme record holds the theme's name, parent and settings.
The Shop Theme record
| Field | What it does |
|---|---|
| Theme Name | The record's name, and the source of the folder name. Letters, digits, spaces, - and _ only. |
| Module | The module whose app holds the theme's files and the record's JSON. Set it before the first save. |
| Is Standard | Ships the record with the app. Commera writes the record's JSON only when this is ticked, and never deletes a standard theme's folders. |
| Parent Theme | The theme that gives every file this theme does not have |
| Theme Settings | A Single DocType with the merchant's settings for this theme. Use Scaffold Theme Settings on a saved record to make one. |
| Config | Not used. Leave it empty. |
Commera does not allow a parent chain that loops back to the same theme.
The theme chain
The chain starts at the active theme and follows Parent Theme to the top. For Acme Catalog, the chain is:
- Acme Catalog, in the
acme_themeapp - Summer Theme, in the Commera app
- Shop Base Theme, in the Commera app
Each theme in the chain can be in a different app.
Fallback order
| What | Where Commera looks | If no theme has it |
|---|---|---|
A page, such as pages/products/details.html |
Each theme in the chain, child first | Commera's core page serves the URL |
A page controller, such as pages/products/details.py |
Each theme in the chain, child first. The controller and the page can come from different themes. | The page renders without a controller |
A components/... file that a template extends, includes or imports |
Each theme in the chain, child first, then Commera's core templates | Jinja raises a "template not found" error |
Any other template name, such as templates/... |
Frappe's normal template loader, which searches every installed app. A theme folder cannot override it. A templates/... file in another app replaces Commera's file for every theme on the site, so do not add one. |
Jinja raises a "template not found" error |
An asset, through shop_theme_asset_url() |
Each theme's public folder in the chain, child first | The helper returns the active theme's URL, so the 404 names your theme |
A child can override a page's .html and keep its parent's .py, or the reverse. Acme Catalog adds only pages/products/details.py. For that URL, Summer Theme's template renders with Acme Catalog's controller. For every other URL, Summer Theme's page and controller run.
What Shop Base Theme ships
Shop Base Theme has no pages. Activated alone, it changes no URL. It ships:
| File | What it gives |
|---|---|
components/base.html |
The HTML skeleton: the lang and dir attributes, SEO meta tags and JSON-LD, analytics tags, the favicon, the merchant's --ls-* colours, Alpine.js and its Persist and Collapse plugins, the cart, translation, wishlist and toast stores, the query string helper, and the toast |
components/macros/branding.html |
brand_logo(css_class) and brand_name() |
images/placeholder.svg |
An image for products without one |
scripts/vendor/alpinejs/ |
Alpine.js and its plugins |
scripts/synced-query-params.js |
Keeps page state, such as the page number, in the query string |
The base.html blocks are listed in Step 2: Add a layout.