Розробникам · Теми
Розробка тем
Тема — тека файлів: Liquid, CSS, переклади й налаштування. Структура, theme.json, як почати, перевірки під час імпорту і перша тема за 30 хвилин.
Тема задає вигляд магазину, але не торгівлю: ціна, наявність, кнопка «купити», кошик і оформлення замовлення — компоненти ядра. Тема ставить їх у потрібне місце тегом {% component %} і оформлює. Мова шаблонів — Liquid з назвами обʼєктів як у Shopify.
Довідники до цієї статті:
- Довідник Liquid — обʼєкти, поля, фільтри й теги.
- Компоненти ядра — що ставить і з якими параметрами.
- Сторінки теми — який сніпет малює яку сторінку і набір спільних сторінок.
- Переклади в темі — фільтр , спільний словник і слова теми.
- Поведінки й стилі — атрибути , санітайзер, змінні .
Структура
my-theme/
theme.json маніфест: id, назва, версія, стилі
config/settings_schema.json глобальні налаштування теми
sections/<handle>.liquid секції: Liquid + {% schema %}
snippets/<handle>.liquid сніпети для {% render %} і сторінки теми
assets/ CSS, зображення, шрифти, іконки
locales/uk.json, en.json слова теми для фільтра t
design/*.json токени, стилі, шапка, підвал, шаблони сторінок
README.md нотатки автора (не входить у тему)| Що | Ліміт |
|---|---|
| Пакет | до 300 файлів і 10 МБ; zip в адмінці — до 12 МБ |
| Один файл | до 1 МБ |
| Сніпет | до 64 КБ |
| Liquid однієї секції чи сніпета | до 50 000 символів; довший не рендериться |
| CSS-файл | до 60 000 символів; решта відкидається |
| Переклади | locales/<мова>.json — лише рядки, до 256 КБ; мови — ті, що підтримує вітрина: uk, en, ru, de, es, fr, it, pl, pt |
| Файли assets/ | css, png, jpg, jpeg, gif, webp, avif, svg, ico, woff2, woff; js, mjs, json, map — лише для магазину, якому дозволено JavaScript |
Будь-який інший файл у пакеті — помилка імпорту з назвою файлу. У zip пропускаються теки, файли з крапкою на початку імені (.DS_Store) і __MACOSX; теку .git у архів не кладіть.
theme.json
{
"storeforma_theme": 1,
"id": "ua.my-studio.bloom",
"name": "Bloom",
"version": "1.0.0",
"author": "My Studio",
"description": "Світла тема для квіткових магазинів.",
"stylesheets": ["kit.css", "theme.css"],
"kit": "pages",
"menus": [{"handle": "mega", "name": "Мегаменю"}]
}| Ключ | Обовʼязковий | Що |
|---|---|---|
| storeforma_theme | так | Формат пакета: 1. |
| id | так | Зворотний домен, який належить вам: ua.my-studio.bloom. com.storeforma.* і id офіційних тем зарезервовано; id, закріплений за іншою організацією, відхиляється. Короткий id (bloom) — для теми одного магазину. |
| name | так | Назва, до 120 символів. |
| version | так | semver: 1.0.0. Виправлення — нова версія. |
| author, description | ні | До 120 і 1000 символів. |
| stylesheets | ні | До 5 CSS-файлів з assets/, підключаються на кожній сторінці вітрини в цьому порядку. З набором сторінок kit.css ставте першим, свій CSS — після нього. |
| kit | ні | "pages" — тема бере спільні сторінки (кошик, оформлення, кабінет, вхід, 404, пошук, сторінки записів) і assets/kit.css з набору Storeforma, якщо не має свого файлу з тим самим імʼям. Докладно — /docs/theme-pages. |
| supports | ні | Види сторінок, які оформлює дизайн теми: home, product, content, entry, entry-list, collection, search, blog, article, cart. На кожен потрібен шаблон <вид>.default у design/templates.json, інакше імпорт зупиняється. |
| menus | ні | До 10 меню, яких чекають секції: {handle, name}. Встановлення створює порожні, яких у магазині немає. main і footer-store вбудовані. |
| content_types | ні | Типи контенту, яких чекають секції. Встановлення створює відсутні типи й додає бракуючі поля; нічого не видаляє. |
З чого почати
- Від офіційної теми. Дизайн → Теми: встановіть тему, найближчу до задуму (Forma — еталон, де кожна сторінка — свій шаблон; Primitive — стартова з коментарями). Потім «Експорт поточної теми»: вкажіть назву — zip отримає власний id з неї, а не id офіційної теми.
- Стартова тема. «Стартова тема (zip)» на тій самій сторінці або — Primitive з вашим id і версією 0.1.0.
- Правки на сайті. Дизайн → Код теми — секції активної теми: Liquid і схема, перевірка під час збереження. Сніпети, CSS і переклади змінюйте в zip, через CLI або асистентом.
- Асистент магазину змінює будь-який файл теми: один-два файли — одразу, більшу переробку — пакетом у своїй пісочниці. Кожну зміну ви схвалюєте карткою; JavaScript — лише після перегляду коду.
- Імпорт. «Імпорт теми з файлу» — zip теки або JSON-пакет .
З терміналом або AI-агентом
node storeforma-agent.mjs theme init ua.my-studio.bloom # нова тема з Primitive
node storeforma-agent.mjs theme pull ./theme # або поточна тема магазину
node storeforma-agent.mjs theme check ./bloom # перевірка на сервері, нічого не зберігає
node storeforma-agent.mjs theme dev ./bloom --open # перегляд лише для вас: сторінка оновлюється після кожного збереження
node storeforma-agent.mjs theme push ./bloom --publish # встановитиtheme dev ставить у магазин окрему копію теми «<id>.dev» і друкує посилання на перегляд: воно відкриває копію лише у вашому браузері на 12 годин, з плашкою «Перегляд теми» внизу, а сторінка сама перезавантажується після кожного збереження файлу. Покупці бачать опубліковану тему, чернетка дизайну магазину лишається як була. --path /shop відкриває потрібну сторінку. Для розробки візьміть безкоштовний магазин у розробці з шаблоном і демоданими — посилання відкриває й його. Коли тема готова — theme push ./bloom --publish. Оновлення теми не перезаписує секції, які магазин змінив у себе; щоб замінити й їх — theme push --replace-edits.
Покроково для дизайнера
Потрібні лише Node.js 20 або новіший і будь-який редактор коду. Docker, локальний сервер і база не потрібні: тема показується на справжньому магазині з його товарами, кошиком і оформленням, але бачите її лише ви.
1. Магазин для роботи. Партнер створює безкоштовний магазин у розробці в кабінеті («Партнерам», блок «Магазини для клієнтів») і обирає шаблон — у магазині одразу будуть демо-товари, категорії й сторінки. Можна працювати й у магазині клієнта: покупці нічого не побачать, доки ви не опублікуєте тему.
2. Клієнт терміналу. Завантажте storeforma-agent.mjs (адмінка магазину → «Контент → MCP і термінал») у теку проєкту й підключіться до магазину: відкриється браузер, де ви підтверджуєте доступ. Для theme push --publish позначте «Дизайн і стилі».
node storeforma-agent.mjs login --store mystore.storeforma.shop3. Тека теми. Почніть з офіційної стартової теми або з поточної теми магазину; щоб відштовхнутися від іншої офіційної — встановіть її в «Дизайн → Теми» і стягніть theme pull:
node storeforma-agent.mjs theme init ua.my-studio.bloom # нова тема з Primitive у ./ua.my-studio.bloom
node storeforma-agent.mjs theme pull ./bloom # або поточна тема магазину4. Живий перегляд. Запустіть theme dev і не закривайте термінал: кожне збереження файлу відправляє тему в магазин як копію «<id>.dev», а відкрита сторінка сама перезавантажується за секунду-дві.
node storeforma-agent.mjs theme dev ./bloom --open # головна
node storeforma-agent.mjs theme dev ./bloom --open --path /shop # одразу каталогПосилання діє 12 годин і лише в тому браузері, де ви його відкрили; внизу сторінки — плашка «Перегляд теми · Вийти». Перевіряйте і телефон: відкрийте те саме посилання на телефоні або звузьте вікно до 390 px. Помилка Liquid чи CSS показується в терміналі з назвою файлу, а сторінка лишається на попередній версії.
5. Що редагувати. Вигляд — assets/theme.css на змінних магазину (var(--store-primary), var(--store-paper) …): власник потім змінює кольори й шрифти в «Стилі магазину». Розмітку сторінок — snippets/*-page.liquid і snippets/product-card.liquid; секції головної — sections/*.liquid. Кнопку «у кошик», варіанти, галерею й оформлення ставте компонентами ({% component 'commerce.add-to-cart' %}), не своїм кодом. CSS теми перекриває стилі Storeforma без !important.
6. Перевірка й публікація. theme check перевіряє теку так само, як імпорт; theme push встановлює тему під її справжнім id, а --publish одразу її публікує (кольори, шрифти й шаблони з design/ — у чернетку дизайну, її публікують у редакторі шаблонів).
node storeforma-agent.mjs theme check ./bloom
node storeforma-agent.mjs theme push ./bloom --publishПеревірки під час імпорту
Імпорт, theme check і збереження файлу асистентом проходять ті самі перевірки. Перша помилка зупиняє встановлення й називає файл.
| Перевірка | Що означає |
|---|---|
| Маніфест | storeforma_theme: 1, id, name, semver; stylesheets — існуючі CSS з assets/; supports — лише відомі види з шаблоном <вид>.default. |
| Файли | Лише відомі шляхи, типи й ліміти зі списку вище. |
| Секції | Схема: name до 120 символів, до 60 налаштувань відомих типів, до 20 типів блоків, max_blocks 1–50, select і radio з options, коректний enabled_on. |
| Liquid | Кожна секція й сніпет розбираються; синтаксична помилка зупиняє імпорт. |
| CSS | @import, expression(), javascript: і url() на інші сайти вирізаються; url() на файли теми й шляхи магазину лишаються. |
| Переклади | JSON-обʼєкт, лише рядки, до 256 КБ. |
| Сторінка товару | Назва, ціна, галерея, наявність, вибір варіанта й кнопка «У кошик» — по одному на шаблон товару; повтор дозволено лише в sticky-bar. |
| Id | Не офіційний і не чужий. |
Після імпорту перевірте тему руками: порожній магазин, товар без фото, товар з варіантами, довгі назви, телефон 390 px. Секція, що падає під час рендеру, на вітрині не показується, а в превʼю редактора показує помилку на своєму місці.
Перша тема за 30 хвилин
Мінімальна тема Bloom: одна секція з налаштуванням і блоками, власна картка товару, слова в locales і CSS на змінних магазину. Решту сторінок дає набір спільних сторінок.
1. theme.json:
{
"storeforma_theme": 1,
"id": "ua.my-studio.bloom",
"name": "Bloom",
"version": "0.1.0",
"author": "My Studio",
"stylesheets": ["kit.css", "theme.css"],
"kit": "pages"
}2. sections/bloom-picks.liquid — заголовок і блоки «Товар» та «Примітка». Текст заголовка за замовчуванням — з перекладу, тож порожнє поле говорить мовою сторінки, а вписаний власником текст перемагає. Блок додатка (@app) рендерить render_block.
{%- assign title = section.settings.title | default: 'sec.picks_title' | t -%}
<section class="bloom-picks">
<h2 class="bloom-picks__title">{{ title }}</h2>
<div class="bloom-picks__grid">
{% for block in section.blocks %}
{% if block.type == 'product' and block.settings.product %}
<div {{ block.attributes }}>{% component 'product.card', product: block.settings.product.id %}</div>
{% elsif block.type == 'note' %}
<p class="bloom-picks__note" {{ block.attributes }}>{{ block.settings.text }}</p>
{% else %}
{% render_block block %}
{% endif %}
{% endfor %}
</div>
{% if section.blocks.size == 0 and request.design_mode %}<p>{{ 'ui.choose_product' | t }}</p>{% endif %}
</section>
{% schema %}
{
"name": "Bloom: добірка",
"settings": [
{"id": "title", "type": "text", "label": "Заголовок (порожньо — текст теми)", "default": ""}
],
"blocks": [
{"type": "product", "name": "Товар", "settings": [{"id": "product", "type": "product", "label": "Товар"}]},
{"type": "note", "name": "Примітка", "settings": [{"id": "text", "type": "text", "label": "Текст"}]},
{"type": "@app"}
],
"max_blocks": 8
}
{% endschema %}3. snippets/product-card.liquid — тепер кожна картка в каталозі, пошуку й добірках малюється цим сніпетом. Ціна в картці вже відформатована; купівля — компонентом.
<article class="bloom-card">
<a class="bloom-card__media" href="{{ product.url }}">
{% if product.featured_image %}
<img src="{{ product.featured_image.src }}" srcset="{{ product.featured_image.srcset }}" sizes="(min-width: 1024px) 25vw, 50vw" alt="{{ product.title }}" loading="lazy">
{% endif %}
{% if product.discount_percent %}<span class="bloom-card__sale">−{{ product.discount_percent }}%</span>{% endif %}
</a>
<a class="bloom-card__title" href="{{ product.url }}">{{ product.title }}</a>
{% component 'product.swatches', limit: 5 %}
<p class="bloom-card__price">{% if product.compare_at_price %}<s>{{ product.compare_at_price }}</s> {% endif %}{{ product.price }}</p>
{% unless product.available %}<p class="bloom-card__muted">{{ 'ui.sold_out' | t }}</p>{% endunless %}
{% component 'commerce.add-to-cart' %}
</article>4. locales/uk.json і locales/en.json — лише свої слова; загальні (ui.sold_out, ui.choose_product) уже є в спільному словнику дев’ятьма мовами:
// locales/uk.json
{"sec": {"picks_title": "Свіжі квіти щодня"}}
// locales/en.json
{"sec": {"picks_title": "Fresh flowers every day"}}5. assets/theme.css — лише змінні магазину, тож кольори, шрифти й заокруглення змінюються зі «Стилями магазину»:
.bloom-picks { max-width: var(--store-container); margin: 0 auto; padding: var(--store-space-12) var(--store-space-4); }
.bloom-picks__title { font-family: var(--store-font-display); font-size: var(--store-text-3xl); color: var(--store-ink); }
.bloom-picks__grid { display: grid; gap: var(--store-space-6); grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
.bloom-card { display: grid; gap: var(--store-space-2); padding: var(--store-space-3); border-radius: var(--store-radius-lg); background: var(--store-surface); box-shadow: var(--store-shadow-card); }
.bloom-card__media { position: relative; display: block; aspect-ratio: 4 / 5; overflow: hidden; border-radius: var(--store-radius-md); }
.bloom-card__media img { width: 100%; height: 100%; object-fit: cover; }
.bloom-card__sale { position: absolute; top: var(--store-space-2); left: var(--store-space-2); padding: 0 var(--store-space-2); border-radius: var(--store-radius-full); background: var(--store-accent); color: var(--store-on-accent); font-size: var(--store-text-xs); }
.bloom-card__title { color: var(--store-ink); font-weight: 600; text-decoration: none; }
.bloom-card__price { margin: 0; color: var(--store-primary-strong); font-weight: 700; }
.bloom-card__price s, .bloom-card__muted { color: var(--store-muted); font-weight: 400; }6. Запакуйте й імпортуйте:
cd bloom && zip -r ../bloom.zip . && cd ..
# Дизайн → Теми → «Імпорт теми з файлу» → bloom.zip
# або: node storeforma-agent.mjs theme push ./bloom7. Відкрийте редактор шаблонів, додайте на головну секцію «Bloom: добірка», виберіть товари в блоках і опублікуйте. Картки каталогу вже малюються вашим сніпетом; кошик, оформлення й кабінет — сторінками набору в стилі kit.css.
Далі: власна сторінка товару й каталогу — Сторінки теми; меню, вкладки й шухляди без JavaScript — Поведінки й стилі; шапка й підвал — секції з і компоненти з Компонентів ядра.