Theme Commands v26.9+
Three commands cover the life of a storefront theme:
| Command | What it does | Who needs it |
|---|---|---|
dev:frontend:theme:create | Scaffolds a new theme, as plain CSS or with its own Tailwind build | Every theme author |
dev:frontend:theme:build | Compiles the CSS sources of a theme into its deployable bundles | Themes with a src/ directory, and Maho contributors |
dev:frontend:theme:export | Writes the Theme Settings of a store into a theme.css file | Developers who move admin settings into git |
All three run from the project root with ./maho. The Theme Development Guide explains the theme system the commands work on. This page is the reference for the commands themselves.
Three ways to restyle a store
Maho has three customization paths. The admin (System > Configuration > Design > Theme Settings) restyles a store with no files and no build. A plain CSS theme sets the same variables in a css/theme.css file and adds its own rules. A Tailwind theme compiles its own stylesheet, for when you write your own templates with Tailwind class names. The commands below serve the last two paths, and export is the bridge from the first one.
dev:frontend:theme:create
Creates a theme with the correct directory structure and starter files.
Interactive mode
Without options, the command asks four questions:
- Package name, for example
acmestore. - Theme name, default
default. - Parent theme, chosen from a list of the installed themes. The suggested parent is
acmestore/defaultwhen the package already has a default theme, andbase/defaultotherwise. Choose Other to type anypackage/themevalue. - Use Tailwind?, default no. Answer no to write plain CSS in
css/theme.css. Answer yes to writesrc/tailwind.cssand compile it with the build command. You can change your mind later, because both shapes end up in the samecss/files.
Names must be lowercase, start with a letter, and contain only letters, digits, hyphens and underscores.
The command refuses to overwrite a theme that exists. When you create a theme that is not default in a package that has no default theme, the command warns you and asks to confirm. A package default theme is the recommended base: every other theme in the package inherits from it automatically.
Non-interactive mode
Pass --package to skip every question. The other options fill in the remaining answers.
| Option | Short | Value | Effect |
|---|---|---|---|
--package | -p | package name | Required for non-interactive mode |
--theme | -t | theme name | Default default |
--parent | package/theme | Default: the package default theme when it exists, otherwise base/default | |
--tailwind / --no-tailwind | Choose the plain CSS shape or the Tailwind shape. Default: plain CSS |
# A plain CSS theme, inheriting from base/default
./maho dev:frontend:theme:create -p acmestore -t default
# A plain CSS theme that starts from the Fashion identity
./maho dev:frontend:theme:create -p acmestore -t default --parent base/fashion
# A theme with its own Tailwind build
./maho dev:frontend:theme:create -p acmestore -t default --tailwind
The parent must exist. When it does not, the command lists the available themes and stops.
What it writes
For a plain CSS theme:
app/design/frontend/acmestore/default/
├── etc/theme.xml Declares the parent theme
└── layout/local.xml Your layout changes, with commented examples
public/skin/frontend/acmestore/default/
└── css/theme.css Your design tokens and CSS rules
For a Tailwind theme, css/theme.css is replaced by src/tailwind.css, the build entry. Its first line imports Maho's own build entry, which carries the whole configuration: the daisyUI plugin, the component layer and the template scan rules.
css/theme.css needs no entry in local.xml: every page already loads it after the compiled styles.css.
When the parent is not base/default, the generated theme.css starts with an import of the parent's theme.css. The skin fallback serves the first theme.css it finds, so a file in your theme would otherwise hide the whole identity of the parent.
After a Tailwind scaffold
When the Tailwind toolchain is installed, the command compiles the theme once, so css/styles.css exists. Without the toolchain, it prints a warning and the storefront shows the colors of the parent until you run the build command, which offers to install the toolchain.
A Tailwind theme owns its compiled engine. Maho's styles.css no longer reaches the store, so rebuild the theme after every Maho upgrade.
Next steps
The command prints them at the end:
- In the admin, go to System > Configuration > Design. Set the package and the theme.
- Edit
css/theme.css(plain CSS) orsrc/tailwind.css(Tailwind). - Add layout changes to
layout/local.xml, and templates totemplate/only when you must.
dev:frontend:theme:build
Compiles the CSS sources of every theme that has them.
What it compiles
The command finds every top-level src/*.css file of every theme under public/skin/frontend/, except files whose names start with an underscore. Those are partials that the entries import. Each entry compiles into css/, minified, with a name that follows the entry:
| Source | Output |
|---|---|
src/tailwind.css | css/styles.css, which replaces Maho's compiled bundle |
src/theme.css | css/theme.css |
src/<name>.css | css/<name>.css |
A theme without a src/ directory needs no build. Its css/ files are served as they are.
Options
| Option | Short | Effect |
|---|---|---|
--theme package/theme | -t | Build one theme instead of all |
--watch | -w | Rebuild on every change until you press Ctrl+C |
# Build one theme
./maho dev:frontend:theme:build --theme acmestore/default
# Rebuild while you work
./maho dev:frontend:theme:build --theme acmestore/default --watch
Watch output is not minified. Run a plain build before you commit.
The toolchain
The command looks for the Tailwind CLI in node_modules/.bin/tailwindcss in the project root. When it is missing, the command offers to install tailwindcss, @tailwindcss/cli and daisyui as dev dependencies. It picks the package manager whose lock file the project carries, from npm, bun, pnpm and yarn, and falls back to the first one installed. A project whose package.json already declares @tailwindcss/cli gets a plain install, so the pinned versions win.
The toolchain needs Node.js or Bun. Without either, the command stops with an error. Store owners never need it: the admin settings and plain CSS themes work without a build.
This works the same when Maho is a Composer dependency of your project. The project root is the working directory in both cases, and the toolchain installs into the project's node_modules/.
Commit the output
The compiled css/ files are meant to be committed. Production never needs Node.js. Maho's own repository runs the same command in CI and fails when the committed bundles do not match the sources.
Exit status
- Success, with one line per compiled bundle.
- A warning and success when no theme has sources.
- Failure when
--themenames a theme without sources, when the toolchain cannot be installed, or when a bundle fails to compile. The Tailwind error output is printed.
dev:frontend:theme:export
Writes the Theme Settings of a store to a theme.css file.
A merchant tunes colors, fonts and shape in System > Configuration > Design > Theme Settings. This command turns that result into a file a developer keeps in git. The fields hold real CSS values, so the export is a straight copy: one :root block with every variable that is set, plus the quiet surface colors Maho derives from the page background.
Options
| Option | Short | Effect |
|---|---|---|
--theme package/theme | -t | Where to write: public/skin/frontend/<package>/<theme>/css/theme.css |
--store <code> | -s | Read the settings of this store view. Default: the default scope |
--stdout | Print the file instead of writing it | |
--force | -f | Overwrite an existing theme.css |
# Review the output first
./maho dev:frontend:theme:export --stdout
# Export the settings of one store view
./maho dev:frontend:theme:export --store fashion_en --theme acmestore/fashion
# Replace the theme.css of an existing theme
./maho dev:frontend:theme:export --theme acmestore/default --force
The store code is the one shown in System > Manage Stores.
Behavior
- When the scope has no Theme Settings, the command says so and stops.
- When the target
theme.cssexists, the command stops unless you pass--force. Use--stdoutto review the output and merge it by hand into a theme that already has an identity file. --themeis required unless you pass--stdout.- On success the command tells you the number of variables written.
After the export, commit the file and clear the fields in Theme Settings. The store looks the same, and the identity now lives in your theme.
A setting a module of yours adds to Theme Settings is exported too. See the Theme Development Guide.
Which command when
| You want to | Run |
|---|---|
| Start a new theme | dev:frontend:theme:create |
| Write Tailwind class names in your own templates | dev:frontend:theme:create --tailwind, then dev:frontend:theme:build after each change |
| Change colors, fonts or shape without files | Nothing: use Theme Settings in the admin |
| Keep admin settings in git | dev:frontend:theme:export |
| Upgrade Maho with a Tailwind theme | dev:frontend:theme:build |
| Work on Maho's own base theme | dev:frontend:theme:build --watch |