Разработка кастомной темы Shopify (Liquid)
Кастомная тема — это когда ни одна из тем Theme Store не подходит по дизайну, структуре секций или производительности. Разработка ведётся на Liquid — шаблонизаторе Shopify — в связке с CSS (обычно Tailwind или BEM-методология) и Vanilla JS / Alpine.js.
Online Store 2.0 — обязательный стандарт
Все современные темы строятся на архитектуре OS 2.0. Ключевые отличия от legacy-тем:
-
JSON-шаблоны вместо Liquid-шаблонов для страниц (
templates/product.json,templates/collection.json) - Sections Everywhere — секции можно добавлять на любую страницу, не только главную
- Blocks внутри секций — вложенная структура с редактированием в Theme Editor
- app blocks — приложения внедряются через официальный App Extension, не хардкодом в шаблоне
Структура файлов темы:
theme/
├── assets/ # CSS, JS, изображения, шрифты
├── config/ # settings_schema.json, settings_data.json
├── layout/ # theme.liquid, password.liquid
├── locales/ # переводы строк темы
├── sections/ # .liquid файлы секций
├── snippets/ # переиспользуемые фрагменты
└── templates/ # .json шаблоны страниц
Секция — основная единица темы
Секция — это .liquid файл в /sections/ с обязательным {% schema %} блоком:
{%- comment -%} sections/product-hero.liquid {%- endcomment -%}
<div class="product-hero" style="--accent: {{ section.settings.accent_color }}">
{% for block in section.blocks %}
{% case block.type %}
{% when 'title' %}
<h1 class="product-hero__title">{{ product.title }}</h1>
{% when 'price' %}
<div class="product-hero__price">
{{ product.selected_or_first_available_variant.price | money }}
</div>
{% when 'add_to_cart' %}
<button
type="submit"
form="product-form-{{ section.id }}"
class="btn btn--primary"
{% unless product.available %}disabled{% endunless %}
>
{{ block.settings.button_text | default: 'В корзину' }}
</button>
{% endcase %}
{% endfor %}
</div>
{% schema %}
{
"name": "Product Hero",
"tag": "section",
"class": "section-product-hero",
"settings": [
{
"type": "color",
"id": "accent_color",
"label": "Акцентный цвет",
"default": "#0066cc"
}
],
"blocks": [
{ "type": "title", "name": "Название товара", "limit": 1 },
{
"type": "price",
"name": "Цена",
"limit": 1
},
{
"type": "add_to_cart",
"name": "Кнопка «В корзину»",
"limit": 1,
"settings": [
{
"type": "text",
"id": "button_text",
"label": "Текст кнопки",
"default": "В корзину"
}
]
}
],
"presets": [
{
"name": "Product Hero",
"blocks": [
{ "type": "title" },
{ "type": "price" },
{ "type": "add_to_cart" }
]
}
]
}
{% endschema %}
Работа с данными Shopify в Liquid
Основные объекты, доступные в шаблонах:
{%- comment -%} Вариант товара с учётом URL-параметра {%- endcomment -%}
{%- assign current_variant = product.selected_or_first_available_variant -%}
{%- comment -%} Коллекция с сортировкой {%- endcomment -%}
{%- assign sorted_products = collection.products | sort: 'price' -%}
{%- comment -%} Метаполя {%- endcomment -%}
{%- assign delivery_days = product.metafields.custom.delivery_days.value -%}
{%- comment -%} Покупатель {%- endcomment -%}
{%- if customer -%}
Привет, {{ customer.first_name }}!
{%- endif -%}
JavaScript в теме
Shopify не навязывает фреймворк. Рекомендуемый подход в 2024–2025 — Web Components или Alpine.js для интерактивности без тяжёлого бандла:
// assets/product-form.js
class ProductForm extends HTMLElement {
connectedCallback() {
this.form = this.querySelector('form');
this.submitButton = this.querySelector('[type="submit"]');
this.form.addEventListener('submit', this.onSubmit.bind(this));
}
async onSubmit(event) {
event.preventDefault();
this.submitButton.setAttribute('disabled', '');
const formData = new FormData(this.form);
const response = await fetch('/cart/add.js', {
method: 'POST',
body: formData
});
if (!response.ok) {
const error = await response.json();
console.error('Cart error:', error.description);
return;
}
// Диспатч события для обновления счётчика корзины
document.dispatchEvent(new CustomEvent('cart:item-added', {
detail: await response.json()
}));
this.submitButton.removeAttribute('disabled');
}
}
customElements.define('product-form', ProductForm);
Производительность темы
Lighthouse Score — косвенный фактор ранжирования и прямой фактор конверсии. Типичные проблемы кастомных тем и их решение:
Render-blocking скрипты — все сторонние скрипты только с defer или async. Встроенные скрипты темы — в конце </body> или через DOMContentLoaded.
Неоптимизированные изображения — Shopify CDN обрабатывает изображения через URL-параметры:
{{ product.featured_image
| image_url: width: 800
| image_tag:
loading: 'lazy',
widths: '400, 800, 1200',
sizes: '(max-width: 768px) 100vw, 50vw'
}}
Избыточный CSS — разделение критического и некритического CSS. Критический — inline в <head>, некритический — с rel="preload" и onload.
Font loading — preconnect + font-display: swap:
{%- comment -%} В layout/theme.liquid <head> {%- endcomment -%}
<link rel="preconnect" href="https://fonts.shopifycdn.com" crossorigin>
Инструменты разработки
# Shopify CLI 3.x
npm install -g @shopify/cli
# Запуск локального сервера с hot-reload
shopify theme dev --store=mystore.myshopify.com --live-reload=hot-reload
# Пуш изменений на стейджинг-тему
shopify theme push --theme=THEME_ID
# Создание нового проекта темы на базе Dawn
shopify theme init my-custom-theme
Сборка CSS и JS — обычно Vite или webpack, результаты копируются в /assets/. Shopify CLI не заменяет бандлер — он только синхронизирует файлы с магазином.
Тестирование
- Функциональное: проверка корзины, чекаута, фильтров через браузер
-
Кросс-браузерное: Chrome, Firefox, Safari (особенно iOS Safari — свои баги с
position: stickyи scroll-behaviour) - Производительность: Lighthouse в режиме инкогнито, WebPageTest с throttling 4G
- Theme Check — линтер от Shopify:
shopify theme check
# Проверяет: устаревшие фильтры, отсутствие alt у изображений,
# некорректные ссылки на ассеты, проблемы с переводами
Сроки
Кастомная тема с нуля по готовому дизайну (до 15 типов страниц): 3–6 недель. Кастомизация существующей темы под брендбук с сохранением обновляемости: 1–2 недели. Рефакторинг legacy-темы в OS 2.0: 2–3 недели.







