Розробка кастомної теми Magento 2
Тема Magento 2 — це набір XML-конфігурацій, PHTML-шаблонів, Less/CSS та JavaScript, які визначають зовнішній вигляд та поведінку фронтенду. На відміну від Shopify, тут немає візуального редактора — розробка ведеться файлами з розумінням системи наслідування тем та layout XML.
Система наслідування тем
Теми Magento будуються на ланцюжку наслідування. Кастомна тема не копіює всі файли базової — вона переопределяє тільки необхідні. Приклад ланцюжка наслідування:
Magento/blank
└── Magento/luma
└── MyCompany/mytheme (кастомна тема)
Під час рендеру Magento шукає шаблон спочатку в кастомній темі, потім піднімається по ланцюжку до базової. Це дозволяє змінити один файл, не торкаючись інших.
Структура файлів теми
app/design/frontend/MyCompany/mytheme/
├── etc/
│ └── view.xml # конфігурація зображень (розміри, якість)
├── i18n/
│ └── en_US.csv # переводи рядків
├── media/
│ └── preview.jpg # превью в Admin
├── registration.php # реєстрація теми
├── theme.xml # метаданні та parent
├── web/
│ ├── css/
│ │ ├── source/
│ │ │ ├── _theme.less # змінні теми
│ │ │ └── _extend.less # розширення базового CSS
│ │ └── _module.less
│ ├── fonts/
│ ├── images/
│ └── js/
│ └── theme.js
└── Magento_Catalog/ # переопределення модуля Catalog
├── layout/
│ └── catalog_product_view.xml
└── templates/
└── product/
└── view/
└── attributes.phtml
theme.xml:
<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
<title>MyCompany Theme</title>
<parent>Magento/luma</parent>
<media>
<preview_image>media/preview.jpg</preview_image>
</media>
</theme>
registration.php:
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::THEME,
'frontend/MyCompany/mytheme',
__DIR__
);
Layout XML — основа системи рендеру
Layout XML керує структурою сторінки: де знаходяться блоки, які шаблони вони використовують. Без розуміння Layout неможливо правильно змінити структуру сторінки.
Типи layout-файлів:
-
default.xml— застосовується до всіх сторінок -
catalog_product_view.xml— сторінка товару -
catalog_category_view.xml— сторінка категорії -
checkout_cart_index.xml— кошик -
cms_index_index.xml— головна сторінка (CMS)
Приклад — додавання кастомного блоку на сторінку товару:
<!-- app/design/frontend/MyCompany/mytheme/Magento_Catalog/layout/catalog_product_view.xml -->
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<!-- Видалити стандартний блок порівняння -->
<referenceBlock name="product.info.addtocart.additional" remove="true"/>
<!-- Додати блок гарантії після ціни -->
<referenceContainer name="product.info.main">
<block class="MyCompany\Catalog\Block\Product\Warranty"
name="product.warranty.info"
template="MyCompany_Catalog::product/warranty.phtml"
after="product.info.price"/>
</referenceContainer>
<!-- Перемістити відгуки вище вкладок -->
<move element="product.info.details" destination="content" before="product.info.media"/>
</body>
</page>
PHTML шаблони
Шаблони — це PHP-файли з HTML-розміткою. Переопределення стандартного шаблону ціни:
<?php
// app/design/frontend/MyCompany/mytheme/Magento_Catalog/templates/product/price/final_price.phtml
/** @var \Magento\Catalog\Block\Product\View\Description $block */
/** @var \Magento\Catalog\ViewModel\Product\Checker\AddToCompareAvailability $compareAvailability */
$priceType = $block->getPriceType('final_price');
$id = $block->getPriceId() ?: 'product-price-' . $block->getProduct()->getId();
?>
<span class="price-wrapper price-final_price"
data-price-amount="<?= $block->escapeHtmlAttr($priceType->getAmount()->getValue()) ?>"
data-price-type="finalPrice">
<?php if ($block->getProduct()->hasCustomOptions()): ?>
<span class="price-label"><?= $block->escapeHtml(__('As low as')) ?></span>
<?php endif; ?>
<span id="<?= $block->escapeHtmlAttr($id) ?>" class="price-container">
<span class="price">
<?= $block->renderAmount($priceType->getAmount(), ['display_label' => false]) ?>
</span>
</span>
</span>
Система Less/CSS
Magento 2 використовує Less з preprocessor-pipeline. Базові змінні переопределяються в web/css/source/_theme.less:
// Фірмові кольори
@color-primary: #1a73e8;
@color-primary-darker: #1557b0;
@color-secondary: #ff6b35;
// Типографіка
@font-family-name__base: 'Inter';
@font-size-base: 16px;
@line-height-base: 1.6;
@font-weight__regular: 400;
@font-weight__bold: 700;
// Кнопки
@button__background: @color-primary;
@button__border: 1px solid @color-primary;
@button__color: #ffffff;
@button__hover__background: @color-primary-darker;
// Хедер
@header__background-color: #ffffff;
@header-icons-color: @color-primary;
// Брейкпоінти
@screen__m: 768px;
@screen__l: 1024px;
@screen__xl: 1440px;
Розширення в _extend.less:
// Імпорт кастомного шрифту
@font-face {
font-family: 'Inter';
src: url('../fonts/Inter-Regular.woff2') format('woff2'),
url('../fonts/Inter-Regular.woff') format('woff');
font-weight: 400;
font-display: swap;
}
// Кастомний стиль карточки товару
.product-item {
border: 1px solid @color-border;
border-radius: 8px;
transition: box-shadow 0.2s ease;
&:hover {
box-shadow: 0 4px 20px rgba(0,0,0,0.12);
}
&-photo {
border-radius: 8px 8px 0 0;
overflow: hidden;
}
}
JavaScript у темі
Magento 2 використовує RequireJS для завантаження модулів. Конфігурація в requirejs-config.js:
// web/requirejs-config.js
var config = {
map: {
'*': {
// Замінюємо стандартний компонент
'Magento_Catalog/js/product/view/product-info': 'MyCompany_Catalog/js/product-info-extended',
}
},
config: {
mixins: {
'Magento_Checkout/js/view/minicart': {
'MyCompany_Checkout/js/view/minicart-mixin': true
}
}
}
};
Mixin для розширення існуючого компонента без замін:
// web/js/view/minicart-mixin.js
define(['jquery', 'mage/utils/wrapper'], function ($, wrapper) {
'use strict';
return function (Component) {
return Component.extend({
// Переопределення методу
getCartParam: wrapper.wrap(Component.prototype.getCartParam, function (original, name) {
if (name === 'summary_count') {
// Додаємо кастомну логіку підрахунку
return this.cartData()[name] || 0;
}
return original(name);
})
});
};
});
Конфігурація зображень
Розміри зображень задаються в etc/view.xml:
<vars module="Magento_Catalog">
<var name="product_image_white_borders">1</var>
</vars>
<images module="Magento_Catalog">
<image id="product_page_image_large" type="image">
<width>1200</width>
<height>1200</height>
</image>
<image id="category_page_grid" type="image">
<width>400</width>
<height>400</height>
<constrain>true</constrain>
</image>
<image id="product_thumbnail_image" type="thumbnail">
<width>80</width>
<height>80</height>
</image>
</images>
Деплой статики
# Деплой для конкретної теми та локалі
bin/magento setup:static-content:deploy en_US \
--theme MyCompany/mytheme \
--jobs=4 \
-f
# Під час розробки — симлінки замість копіювання
bin/magento dev:source-theme:deploy \
--locale en_US \
--theme MyCompany/mytheme \
css/styles-m css/styles-l
# Компіляція Less вручну (для швидкої ітерації)
grunt watch
Hyva — альтернатива Luma
Hyva Themes — сучасний стек для тем Magento 2: Tailwind CSS + Alpine.js + серверний рендер через Magento layout. Замість складного RequireJS + KnockoutJS + Less — простий, швидкий та зрозумілий стек.
Комерційна ліцензія ($1000/сайт). Видає Lighthouse 90+ без додаткової оптимізації. Розробка в 2–3 рази швидше порівняно з Luma.
Термін виконання
Кастомна тема на базі Luma/Blank за готовим дизайном (10–20 типів сторінок): 5–8 тижнів. Hyva-тема з тією ж складністю: 3–5 тижнів. Кастомізація існуючої теми (кілька шаблонів, брендинг): 1–2 тижні.







