A Theme
A theme is a directory with theme.xml and registration.php: what each file does and how a parent is declared.
app/design/<area>/<Vendor>/<theme>/theme.xmlA theme is the component that decides how pages look. It holds templates, layout XML, stylesheets, images and fonts, and it lives in app/design/<area>/<Vendor>/<theme>. An area is the part of the application the files apply to: frontend for the storefront, adminhtml for the admin. A storefront theme has no effect on admin pages.
Two files make a theme
theme.xml declares it. It carries the title shown in the admin, an optional preview image, and the <parent> theme it inherits from. Magento 2.4.9 ships two storefront themes, Magento/blank and Magento/luma, and a custom theme normally names one of them as its parent. registration.php tells the framework that the directory is a theme and under which name, for example frontend/Acme/storefront.
The rest of the directory
etc/view.xml— image sizes and view variablesweb/css,web/images,web/fonts,web/js— the theme's own assets<Vendor>_<Module>/templatesand<Vendor>_<Module>/layout— per-module overridesmedia/preview.jpg— the thumbnail the admin showscomposer.json— needed only to distribute the theme as a package
Making it visible
Themes are written into the database by a data patch, so after adding the files run bin/magento setup:upgrade and then bin/magento cache:flush. The theme then appears in Content > Design > Configuration, where you apply it to a store view.
Example
<!-- app/design/frontend/Acme/storefront/theme.xml -->
<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
<title>Acme Storefront</title>
<parent>Magento/luma</parent>
<media>
<preview_image>media/preview.jpg</preview_image>
</media>
</theme>
<!--
The title is what merchants see in Content > Design > Configuration.
<parent> makes every file this theme does not define fall back to Luma,
and then to Blank, which is Luma's own parent.
Put the thumbnail at app/design/frontend/Acme/storefront/media/preview.jpg.
Apply it with:
bin/magento setup:upgrade
bin/magento cache:flush
then select Acme Storefront for a store view in the admin.
-->When to use it
- Start a client build as a child of Luma without editing Luma itself.
- Give two similar themes preview images so a merchant can tell them apart in the admin.
- Package a finished theme so another installation can require it with Composer.
- Create a second theme for a second store view that differs in only a few files.
More examples
registration.php for a theme
Every theme needs this file, and the string is the theme's identity: area, vendor, theme, matching the directory it sits in. For a theme inside app/design the framework finds the file when it scans app/design at bootstrap; for a theme installed through Composer the autoload.files entry in composer.json loads it. Adding or changing the file needs bin/magento setup:upgrade before the theme is usable, and bin/magento cache:flush afterwards.
<?php
// app/design/frontend/Acme/storefront/registration.php
declare(strict_types=1);
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
ComponentRegistrar::THEME,
'frontend/Acme/storefront',
__DIR__
);composer.json, only for distribution
A theme in app/design works without this file. You add it when the theme must travel: the type magento2-theme tells the Magento Composer installer where to place it, and the require section names the parent theme's package so the parent cannot be missing. Luma's package is magento/theme-frontend-luma, Blank's is magento/theme-frontend-blank.
{
"name": "acme/theme-frontend-storefront",
"description": "Acme storefront theme",
"type": "magento2-theme",
"license": "proprietary",
"require": {
"php": "~8.4.0",
"magento/framework": "*",
"magento/theme-frontend-luma": "*"
},
"autoload": {
"files": [
"registration.php"
]
}
}What the directory looks like filled in
A realistic small theme: two declaration files, view configuration, its own styles and images, and overrides for exactly the two modules it needed to change. Nothing here is mandatory except theme.xml and registration.php, and a file you do not create is taken from the parent theme instead.
app/design/frontend/Acme/storefront/
├── theme.xml
├── registration.php
├── composer.json
├── media/
│ └── preview.jpg
├── etc/
│ └── view.xml
├── web/
│ ├── css/
│ │ └── source/
│ │ └── _extend.less
│ ├── fonts/
│ └── images/
│ └── logo.svg
├── Magento_Theme/
│ ├── layout/
│ │ └── default.xml
│ └── templates/
│ └── html/
│ └── copyright.phtml
└── Magento_Catalog/
└── web/
└── css/
└── source/
└── _extend.less
Discussion