Ви відкриваєте Theme Editor, змінюєте текст у секції, а на сайті — нічого. Або блоки з'їжджають, або налаштування не застосовуються. Знайомий біль? Ми, як розробники з 8-річним досвідом у Shopify, знаємо кожну пастку. Розповімо, як правильно налаштувати Sections і Blocks, щоб команда контенту працювала без вас, а редактор тем не ламав верстку.
Online Store 2.0 дав потужний інструмент — секції з блоками. Але використовувати їх потрібно усвідомлено. Неправильна схема перетворює гнучкість на кошмар: блоки перекриваються, налаштування не зберігаються, а пресети не з'являються. Нижче — практика, яка позбавить цих проблем.
Як уникнути конфліктів блоків?
Кожен блок всередині секції повинен мати унікальний type. Якщо два блоки мають однаковий type, вони будуть поводитися як один — налаштування перезапишуться. Використовуйте різні type або обмежуйте кількість через max_blocks. Також обов'язково додавайте атрибут {{ block.shopify_attributes }} — він дозволяє Theme Editor правильно ідентифікувати кожен блок.
Чому статичні секції небезпечні?
Статичні секції жорстко прописані в layout/theme.liquid. Їх не можна перемістити або видалити з редактора — тільки через код. Це збільшує час правок у 3 рази порівняно з динамічними секціями. Для всіх нових проєктів ми рекомендуємо динамічні секції: вони керуються через JSON-шаблон сторінки, що дає повний контроль контент-менеджеру без доступу до коду.
Як влаштовані Sections
Секція — файл у /sections/ з Liquid-шаблоном і JSON-схемою в одному файлі. Схема описує налаштування секції та типи блоків, які вона приймає. Ключове поле — presets: без нього секція не з'явиться в списку «Додати секцію». Докладніше про Liquid можна почитати у Вікіпедії.
Мінімальна секція:
{%- comment -%} sections/text-banner.liquid {%- endcomment -%}
<div class="text-banner text-banner--{{ section.settings.alignment }}">
<div class="container">
{% if section.settings.heading != blank %}
<h2>{{ section.settings.heading }}</h2>
{% endif %}
{% if section.settings.text != blank %}
<div class="text-banner__body">{{ section.settings.text }}</div>
{% endif %}
</div>
</div>
{% schema %}
{
"name": "Текстовий банер",
"tag": "section",
"class": "section-text-banner",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Заголовок",
"default": "Заголовок секції"
},
{
"type": "richtext",
"id": "text",
"label": "Текст"
},
{
"type": "select",
"id": "alignment",
"label": "Вирівнювання",
"options": [
{ "value": "left", "label": "По лівому краю" },
{ "value": "center", "label": "По центру" },
{ "value": "right", "label": "По правому краю" }
],
"default": "center"
}
],
"presets": [
{
"name": "Текстовий банер"
}
]
}
{% endschema %}
Статичні vs динамічні секції: порівняння
| Характеристика |
Статична секція |
Динамічна секція |
| Управління |
Тільки через код |
Через Theme Editor і JSON-шаблон |
| Переміщення |
Неможливе |
Можливе (drag-and-drop) |
| Видалення з редактора |
Не можна |
Можна |
| Гнучкість |
Низька |
Висока |
| Швидкість змін |
Дні |
Хвилини |
Динамічні секції виграють у 3 рази за швидкістю внесення правок. Це особливо важливо для магазинів, де контент змінюється щотижня.
Типи налаштувань (settings types)
| Тип |
Використання |
text |
Короткий рядок |
textarea |
Багаторядковий текст |
richtext |
Текст з форматуванням (bold, italic, посилання) |
html |
Довільний HTML |
image_picker |
Вибір зображення з медіатеки |
url |
Посилання (внутрішнє або зовнішнє) |
link_list |
Меню навігації |
color |
Колір |
color_scheme |
Колірна схема (з config/settings_schema.json) |
font_picker |
Шрифт з Google Fonts |
select |
Випадний список |
radio |
Перемикач |
checkbox |
Прапорець |
range |
Слайдер з числом |
collection |
Посилання на колекцію |
product |
Посилання на товар |
blog |
Посилання на блог |
page |
Посилання на сторінку |
video |
Відео з медіатеки |
video_url |
YouTube / Vimeo URL |
number |
Число |
paragraph |
Нередагований текст-підказка в UI |
header |
Розділювач-заголовок в UI (не виводить контент) |
Blocks всередині секції
Блоки — динамічні повторювані елементи секції. Приклад — секція «Картки переваг»:
{%- comment -%} sections/features-grid.liquid {%- endcomment -%}
<div class="features-grid features-grid--cols-{{ section.settings.columns }}">
{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when 'feature_card' -%}
<div class="feature-card" {{ block.shopify_attributes }}>
{%- if block.settings.icon != blank -%}
<img
src="{{ block.settings.icon | image_url: width: 80 }}"
alt="{{ block.settings.icon.alt | escape }}"
width="80"
height="80"
loading="lazy"
>
{%- endif -%}
<h3>{{ block.settings.title }}</h3>
<p>{{ block.settings.description }}</p>
</div>
{%- endcase -%}
{%- endfor -%}
</div>
{% schema %}
{
"name": "Сітка переваг",
"tag": "section",
"settings": [
{
"type": "range",
"id": "columns",
"min": 2,
"max": 4,
"step": 1,
"label": "Кількість колонок",
"default": 3
}
],
"blocks": [
{
"type": "feature_card",
"name": "Картка переваги",
"settings": [
{
"type": "image_picker",
"id": "icon",
"label": "Іконка"
},
{
"type": "text",
"id": "title",
"label": "Заголовок",
"default": "Перевага"
},
{
"type": "textarea",
"id": "description",
"label": "Опис"
}
]
}
],
"max_blocks": 12,
"presets": [
{
"name": "Сітка переваг",
"blocks": [
{ "type": "feature_card" },
{ "type": "feature_card" },
{ "type": "feature_card" }
]
}
]
}
{% endschema %}
Атрибут {{ block.shopify_attributes }} обов'язковий — він додає data-атрибути для inline-редагування в Theme Editor.
Покроковий процес створення секції
- Створіть файл
.liquid у /sections/.
- Опишіть Liquid-розмітку з використанням
section.settings і block.settings.
- Додайте
{% schema %} з name, tag, settings і, за потреби, blocks.
- Вкажіть хоча б один
preset, щоб секція з'явилася в редакторі.
- Підключіть секцію в JSON-шаблон сторінки (наприклад,
templates/index.json).
- Перевірте в Theme Editor: додайте секцію, налаштуйте блоки, збережіть.
Обмеження для захисту від поломки
limit у конфігурації секції або блоку запобігає додаванню зайвих елементів:
// Заборона на дублювання hero-секції
{ "type": "hero-banner", "limit": 1 }
// Не більше 6 блоків у слайдері
"max_blocks": 6
Що входить у роботу з налаштування
- Аудит поточної теми на наявність хардкоду та негнучких секцій.
- Проектування архітектури секцій під вимоги вашого магазину.
- Розробка 5–8 кастомних секцій з блоками згідно з макетами.
- Налаштування глобальних колірних схем і шрифтів.
- Інтеграція секцій у JSON-шаблони сторінок.
- Документування створених компонентів і навчання команди контенту.
- Гарантія роботи всіх блоків у Theme Editor (2 тижні підтримки після здачі).
Терміни та оцінка
Розробка 5–8 кастомних секцій з блоками для конкретного проєкту: 3–5 днів. Рефакторинг існуючої теми з перенесенням хардкоду в редаговані секції: 1–2 тижні. Якщо у вас уже є тема, але блоки працюють непередбачувано, напишіть нам — ми оцінимо проєкт за 1 день і запропонуємо план рефакторингу. Більше 50 магазинів ми перевели на Online Store 2.0 — у нас є досвід і гарантія якості. Отримайте консультацію щодо ваших завдань.
Розробка інтернет-магазинів
Ми знаємо: інтернет-магазин — це не просто «сайт з кошиком». Це розподілена система управління товарами, інвентарем, замовленнями, платежами, доставкою, поверненнями та комунікацією з клієнтами. Кожен блок має нетривіальну реалізацію, і більшість проблем в e-commerce виникає на стику цих підсистем. Наш досвід — понад 50 реалізованих проектів — показує, що правильна архітектура на старті економить до 40% бюджету на доробках.
Чому продуктивність каталогу деградує при зростанні SKU?
Найчастіша технічна проблема e-commerce — деградація сторінок категорій при збільшенні асортименту. Сторінка працює добре на 500 товарах і починає гальмувати на 10 000. Причини майже завжди одні й ті ж.
N+1 на атрибутах. Завантажуєте список товарів — 50 елементів. Для кожного потрібні категорія, головне фото, ціна з урахуванням знижки, наявність на складі, рейтинг. Без правильного eager loading це 250+ запитів на сторінку. В Laravel вирішується через with(['category', 'mainImage', 'currentPrice', 'stockStatus']) та withAvg('reviews', 'rating'). Але варто з'явитися персональним цінам (b2b) або складським залишкам по регіонах — і одного with() недостатньо. Потрібні Query Object або виділений ReadModel.
Фасетна фільтрація без індексів. Фільтр за кольором + розміром + брендом + діапазоном цін на таблиці в 500 000 записів без складених індексів — це seq scan при кожному запиті. PostgreSQL з правильними індексами тримає фасетну фільтрацію до кількох мільйонів товарів. Для великих каталогів — Elasticsearch або OpenSearch з агрегаціями: вони рахують кількість товарів на фільтр (facet counts) значно швидше.
Пагінація через OFFSET. LIMIT 50 OFFSET 10000 на великій таблиці — погана ідея: PostgreSQL все одно читає перші 10 050 рядків. Keyset pagination (cursor-based) через WHERE id > $last_id ORDER BY id LIMIT 50 працює за постійний час незалежно від сторінки. Як зазначено в документації PostgreSQL, cursor-based pagination гарантує O(log n) при будь-якому зміщенні, що особливо важливо для каталогів із сотнями тисяч товарів.
Конкретний кейс: каталог будівельних матеріалів, 180 000 SKU, фасетна фільтрація по 12 атрибутах. Після переходу з OFFSET-пагінації на курсорну та додавання partial index по (category_id, is_active, price) час відповіді сторінки каталогу знизився з 4,2 с до 280 мс. Економія на серверних ресурсах склала близько 30 000 ₽ на місяць. В іншому проекті (ювелірний маркетплейс) впровадження агрегацій через Elasticsearch скоротило час фільтрації з 8 до 200 мс та заощадило 50 000 ₽ на місяць на інфраструктурі — ще один приклад, як правильна архітектура знижує TCO.
Що таке race condition у кошику та як його уникнути?
Checkout — місце, де гроші або потрапляють на рахунок, або ні. Технічні проблеми тут коштують дорого.
Race condition при резервуванні товару. Два покупці одночасно додають останній екземпляр у кошик і обоє натискають «Оплатити». Без песимістичного блокування або атомарного UPDATE з перевіркою залишку обидва замовлення проходять, інвентар іде в мінус. В PostgreSQL:
UPDATE inventory
SET reserved = reserved + $quantity
WHERE product_id = $id
AND (available - reserved) >= $quantity
RETURNING id;
Якщо RETURNING повернув 0 рядків — товару немає, показуємо помилку до списання грошей.
Ідемпотентність платіжних вебхуків. payment.succeeded від Stripe або ЮКассы може прийти двічі через мережеві збої або retry-логіку на стороні шлюзу. Без перевірки WHERE NOT EXISTS (SELECT 1 FROM processed_events WHERE event_id = $id) — дублювання замовлення або подвійне зарахування. Webhook idempotency — обов'язковий патерн для будь-якого платіжного інтегратора. Ми включаємо тест на ідемпотентність у стандартний чек-лист кожного проекту.
Checkout у кілька кроків. Multi-step checkout (адреса → доставка → оплата → підтвердження) vs single-page checkout. Дослідження показують, що single-page з прогрес-індикатором конвертує на 15–20% краще на мобільних. Стан між кроками — або localStorage + server-side сесія, або повністю server-side з проміжним збереженням. Ми гарантуємо, що кожне замовлення проходить аудит на ідемпотентність та блокування — це входить у стандартний чек-лист тестування.
Чому варто уникати CommerceML для великих каталогів
CommerceML через HTTP — класична інтеграція 1С з сайтом. 1С вивантажує XML за розкладом, сайт імпортує. Для невеликих каталогів (до 5 000 SKU) це прийнятно, але при зростанні до 50 000+ SKU виникають проблеми: файл вивантаження 200 МБ кожні 30 хвилин, парсинг блокує чергу, імпорт займає 10–15 хвилин, в цей час на сайті старі ціни. Рішення — інкрементальне вивантаження (тільки зміни) та фонова обробка через Laravel Queue з кількома workers. Для високонавантажених систем ми рекомендуємо REST API або проміжну шину (RabbitMQ).
Як інтегрувати 1С з інтернет-магазином?
1С — окрема глава. Три поширених способи інтеграції:
-
CommerceML через HTTP — 1С вивантажує XML за розкладом, сайт імпортує. Працює для невеликих каталогів, є затримка синхронізації.
-
REST API / OData від 1С — двостороння синхронізація в реальному часі. Вимагає налаштування на стороні 1С, примхлива до версій конфігурацій.
-
Проміжна шина (RabbitMQ / Kafka) — 1С публікує події, сайт підписується. Найнадійніший підхід для високонавантажених систем, але найдорожчий у розробці.
Служби доставки — СДЕК, Boxberry, Пошта Росії, DHL: всі надають REST API для розрахунку вартості та створення накладних. Агрегатори (Shiptor, Shipnow) дозволяють працювати з кількома службами через єдиний API.
Платіжні шлюзи
| Шлюз |
Особливості інтеграції |
| Stripe |
Webhook-based, відмінна документація, Stripe Elements для PCI DSS |
| ЮКасса |
Популярний в РФ, підтримка ФЗ-54 (фіскалізація) |
| ЄРИП |
Білоруська система, SOAP API, специфічна документація |
| Tinkoff Acquiring |
REST API, 3D Secure 2.0, webhook-повідомлення |
Для кожного шлюзу обов'язкова перевірка підпису вебхука — без цього будь-хто може відправити фейковий payment.succeeded.
CMS vs власна розробка
WooCommerce — виправданий для магазинів до ~5 000 SKU з типовою бізнес-логікою. Швидкий старт, величезна екосистема плагінів. Проблеми починаються при нестандартних цінових правилах, складних варіантах товарів або навантаженні від 10 000+ замовлень на місяць. Економія на ліцензії WooCommerce (безкоштовно) обертається витратами на плагіни та хостинг; для каталогу 50 000 SKU місячна вартість підтримки може перевищити 100 000 ₽.
OpenCart, Prestashop — аналогічна історія. Хороші для старту, обмежені при зростанні.
Власна розробка на Laravel — для:
- Нестандартної бізнес-логіки (підписки, оренда, b2b-прайси, конфігуратор);
- Високих вимог до продуктивності;
- Складних інтеграцій (кілька складів, ERP, маркетплейси);
- Унікального UX checkout.
Як ми розробляємо інтернет-магазин: покроковий процес
-
Аналітика та проектування. Збираємо вимоги, уточнюємо бізнес-процеси, моделюємо доменну логіку. На виході — технічне завдання та архітектурна схема.
-
Backend та API. Реалізуємо ядро (товари, кошик, замовлення), інтеграції з 1С/складами/платіжками. Використовуємо Laravel 11 з Repository pattern, чергами для асинхронних операцій.
-
Frontend та checkout. Налаштовуємо React 18 / Next.js 14 з оптимізованим рендерингом (SSR/SSG для каталогу), єдиний single-page checkout.
-
Тестування. Перевіряємо race condition, ідемпотентність вебхуків, навантажувальне тестування (k6), security-аудит.
-
Деплой та моніторинг. Розгортаємо на Vercel / Docker / виділеному сервері, підключаємо Sentry та Uptime.
SEO для e-commerce
Canonical та дублювання. Фасетна фільтрація генерує тисячі URL (?color=red&size=M&sort=price). Без canonical або noindex на фільтрованих сторінках краулінговий бюджет витрачається на дублі, а основні сторінки індексуються гірше.
Structured data. Product schema з offers, aggregateRating, availability — це rich snippets у видачі: зірочки рейтингу, ціна, наявність. Впливає на CTR.
Core Web Vitals на сторінках товарів. Hero image товару — це LCP element. fetchpriority="high" на першому зображенні, правильні srcset з WebP, width та height атрибути для запобігання CLS.
Що входить у результат роботи
Після завершення проекту ви отримуєте:
- Вихідний код та повну документацію (API, архітектура, інфраструктура);
- Доступи до репозиторію, хостингу, моніторингу (Sentry, Uptime);
- Навчання команди роботі з адмін-панеллю та кастомізаціями;
- Гарантійну підтримку 3 місяці (виправлення помилок, консультації);
- Детальний звіт по навантажувальному тестуванню та оптимізації.
Орієнтири за термінами
| Тип магазину |
Термін |
| Малий (до 1 000 SKU, типова логіка) |
8–12 тижнів |
| Середній (до 50 000 SKU, інтеграція 1С) |
14–20 тижнів |
| Великий (100 000+ SKU, ERP, маркетплейси) |
24–40 тижнів |
Вартість розраховується після аналізу вимог: кількість інтеграцій, складність ціноутворення, обсяг каталогу та унікальність UX — основні фактори. Оцінимо ваш проект безкоштовно — замовте консультацію.
Чек-лист перед запуском
- Race condition при оплаті останнього товару — покритий тестом
- Ідемпотентність вебхуків платіжного шлюзу
- Rate limiting на ендпоїнтах кошика та checkout
- Canonical на фільтрованих сторінках каталогу
- Фіскалізація чеків (ФЗ-54 для РФ або аналог)
- Стрес-тест checkout під навантаженням (k6 або Locust)
- Моніторинг помилок (Sentry) та алерти на payment errors
- Backup бази даних з перевіреним restore-процесом
Гарантуємо — кожен проект проходить цей чек-лист перед релізом. Зв'яжіться з нами — підберемо оптимальну архітектуру під ваш бюджет та терміни.