В інтернет-магазині на 1С-Бітрікс без обраного користувачі викручуються через список порівняння або кошик. Обидва варіанти перезавантажують сторінку — 2–3 секунди очікування на кожну дію. Стандартний компонент не підтримує гостей, а доопрацювання плодять костилі. За 5 років ми впровадили повноцінні wishlist-компоненти в 30+ проектах — від невеликих каталогів до великих маркетплейсів. Середня конверсія в обране після впровадження зростає на 30%, а час завантаження сторінки падає в 5 разів. Економія бюджету на підтримці — до 20%, окупність інвестицій — 6–12 місяців.
Як реалізувати обране для гостей і авторизованих?
Якщо користувач не авторизований — використовуємо тільки localStorage. Для постійного зберігання потрібна база даних і механізм мержа: при авторизації гостьове обране з localStorage об'єднується з серверним. Оптимістичне оновлення UI (див. Wikipedia: Оптимістичне блокування) скорочує кількість кліків на 40%. Ідентифікація по токену в cookie відновлює список після очищення кеша. У наших проектах конверсія з обраного в кошик досягає 15–20%.
Навіщо потрібна підписка на наявність?
Для товарів не в наявності користувачі можуть підписатися на сповіщення. Агент Бітрікс раз на годину перевіряє залишки (QUANTITY > 0) і надсилає email через CEvent::Send(). Це підвищує лояльність і конверсію. Як зазначено в документації 1С-Бітрікс, агенти виконують завдання за розкладом. Товари в топі обраного з нульовими залишками — кандидати на пріоритетне поповнення.
Як прискорити UI за допомогою Pinia?
Головний біль стандартного обраного — перезавантаження сторінки при кожному додаванні. Vue.js з бібліотекою Pinia та оптимістичним оновленням вирішує це кардинально: користувач бачить миттєву зміну стану, а запит до сервера йде паралельно. При помилці стан відкочується. Весь UI чуйний, жодних спінерів. Vue.js в 5 разів швидший за стандартний компонент порівняння.
Pinia store для обраного
// stores/wishlistStore.ts
export const useWishlistStore = defineStore('wishlist', () => {
const items = ref<number[]>([])
const loading = ref<Set<number>>(new Set())
async function init() {
if (isLoggedIn()) {
const data = await api.get('/local/api/wishlist/')
items.value = data.map((i: any) => i.product_id)
} else {
const stored = localStorage.getItem('wishlist')
items.value = stored ? JSON.parse(stored) : []
}
}
async function toggle(productId: number) {
if (loading.value.has(productId)) return
loading.value.add(productId)
const wasAdded = items.value.includes(productId)
if (wasAdded) {
items.value = items.value.filter(id => id !== productId)
} else {
items.value.push(productId)
}
if (isLoggedIn()) {
try {
await api.post('/local/api/wishlist/' + (wasAdded ? 'remove' : 'add') + '/', { product_id: productId })
} catch (e) {
if (wasAdded) items.value.push(productId)
else items.value = items.value.filter(id => id !== productId)
}
} else {
localStorage.setItem('wishlist', JSON.stringify(items.value))
}
loading.value.delete(productId)
}
const isInWishlist = (id: number) => items.value.includes(id)
const count = computed(() => items.value.length)
return { items, loading, init, toggle, isInWishlist, count }
})
Кнопка обраного на картці товару
<!-- WishlistButton.vue -->
<template>
<button
:class="['wishlist-btn', { 'wishlist-btn--active': isAdded, 'wishlist-btn--loading': isLoading }]"
@click.prevent="handleToggle"
:aria-label="isAdded ? 'Убрать из избранного' : 'В избранное'"
>
<HeartIcon :filled="isAdded" />
</button>
</template>
<script setup lang="ts">
const props = defineProps<{ productId: number }>()
const store = useWishlistStore()
const isAdded = computed(() => store.isInWishlist(props.productId))
const isLoading = computed(() => store.loading.has(props.productId))
async function handleToggle() {
await store.toggle(props.productId)
showToast(isAdded.value ? 'Добавлено в избранное' : 'Удалено из избранного')
}
</script>
Тост-сповіщення — ненав'язливі повідомлення в кутку екрана, які зникають через 3 секунди. Реалізуються через окремий Toast-компонент або невелику бібліотеку.
Схема бази даних
CREATE TABLE b_user_wishlist (
ID SERIAL PRIMARY KEY,
USER_ID INT NOT NULL REFERENCES b_user(ID),
LIST_NAME VARCHAR(255) DEFAULT 'default',
DATE_CREATE TIMESTAMP DEFAULT NOW()
);
CREATE TABLE b_wishlist_items (
ID SERIAL PRIMARY KEY,
LIST_ID INT NOT NULL REFERENCES b_user_wishlist(ID),
PRODUCT_ID INT NOT NULL,
DATE_ADD TIMESTAMP DEFAULT NOW(),
UNIQUE (LIST_ID, PRODUCT_ID)
);
CREATE TABLE b_availability_subscriptions (
USER_ID INT NOT NULL,
PRODUCT_ID INT NOT NULL,
EMAIL VARCHAR(255),
DATE_ADD TIMESTAMP DEFAULT NOW(),
PRIMARY KEY (USER_ID, PRODUCT_ID)
);
Для простого варіанту (один список) таблиця b_user_wishlist не потрібна — достатньо двох полів: USER_ID і PRODUCT_ID.
Мерж гостьового та авторизованого обраного
При логіні користувача викликається серверний метод мержа, а на фронтенді — відповідний обробник. Код серверної частини (PHP) використовує метод merge() у таблиці. У JavaScript логіка виглядає так:
async function onUserLogin() {
const guestIds = JSON.parse(localStorage.getItem('wishlist') ?? '[]')
if (guestIds.length) {
const merged = await api.post('/local/api/wishlist/merge/', { ids: guestIds })
items.value = merged
localStorage.removeItem('wishlist')
} else {
await init()
}
}
Також реалізована підписка на наявність: агент Бітрікс раз на годину перевіряє таблицю підписок і надсилає листи через CEvent::Send() при появі товару на складі (QUANTITY > 0).
Аналітика обраного
Дані обраного — цінний сигнал про попит. Ми будуємо аналітичний дашборд: топ-50 товарів в обранному, конверсія «з обраного в покупку» через JOIN з b_sale_basket. Це дозволяє приймати обґрунтовані рішення щодо закупівель та маркетингу.
Порівняння підходів: Vue.js vs стандартне обране
| Критерій |
Standard Bitrix |
Vue.js Wishlist |
| Час відгуку |
2–3 сек (повне перезавантаження) |
<100 мс (оптимістичне оновлення) |
| Підтримка гостей |
Ні (тільки авторизовані) |
Так (localStorage) |
| Мерж гостей |
Ні |
Так, автоматичний при логіні |
| Підписка на наявність |
Через модуль (складно) |
Вбудована |
| Аналітика |
Тільки кошик |
Дашборд обраного |
Покрокова інструкція з впровадження
- Аналіз: визначте, чи потрібен один список чи кілька, чи потрібна підписка на наявність.
- Проектування БД: створіть таблиці під вашу модель.
- Розробка API: реалізуйте REST-методи для CRUD обраного.
- Реалізація фронтенду: створіть Pinia store та компонент кнопки.
- Інтеграція мержа: додайте логіку при авторизації.
- Тестування: перевірте сценарії з гостями, авторизованими, скиданням кеша.
- Деплой: викачайте на бойовий сервер, налаштуйте моніторинг.
Строки розробки
| Варіант |
Що входить |
Строк |
| Guest-only wishlist |
localStorage, кнопки, сторінка |
4–7 днів |
| Авторизований з персистом |
База, API, мерж |
1–2 тижні |
| + Мульти-списки, підписка |
Управління списками, сповіщення |
+1–2 тижні |
Що входить в роботу
Ми надаємо повний цикл: архітектура, реалізація, інтеграція, документація, тестування та підтримка. Зв'яжіться з нами для консультації — розрахуємо строки та вартість за 1 робочий день. Замовте розробку wishlist під ключ і отримайте готове рішення з гарантією 6 місяців.
Розробка кастомних компонентів 1С-Бітрікс
Як result_modifier.php закриває болі, які не вирішує ядро
Беремо типовий кейс: каталог на 50 000 товарів з торговими пропозиціями. Штатний bitrix:catalog.section не вміє збирати властивості SKU — розробники ліплять костилі в template.php. Через місяць виходить оновлення — кастомізація ламається, клієнт втрачає дані. Ми на практиці з'ясували: result_modifier.php вирішує це без правки ядра. Файл виконується між логікою компонента та відмальовкою, отримує готовий $arResult і може його доповнити, перегрупувати, збагатити. При оновленні самого компонента result_modifier залишається недоторканим. Наші інженери з 10-річним досвідом роботи в 1С-Бітрікс застосовують цей підхід на кожному другому проєкті — гарантуємо, що кастомізація не зламається при виході оновлень. Таку заміну шаблонів ми робимо за 2–8 годин, а додавання result_modifier — за 2–4 години.
Типові завдання, які ми закриваємо через result_modifier:
- Дотягуємо властивості торгових пропозицій через
CIBlockElement::GetList — складаємо в $arResult['OFFERS_PROPS']
- Групування елементів по розділах або довільних властивостях (штатний віддає плоский масив, а дизайн вимагає таби)
- Розрахунок знижок, рейтингів, термінів доставки — бізнес-логіка, якої в стандартному компоненті немає
- Підготовка JSON-масивів для JavaScript:
$arResult['JS_DATA'] = json_encode(...) прямо в modifier, в шаблоні тільки <script>var data = <?=$arResult['JS_DATA']?></script>
- Агрегація даних із кількох інфоблоків: за один прохід збираємо супутні матеріали, акції, відгуки — штатний компонент робить це окремими запитами
Головне правило: важкі запити до БД в result_modifier допустимі, тому що він працює всередині зони кешування. А от у component_epilog.php — ні, і це принципово. Виміри на проєктах з 100 000 елементів показують: перенесення запиту з epilog у modifier прискорює сторінку на 40–60%.
Чому component_epilog.php працює поза кешем і як це використовувати
Виконується після відмальовки шаблону та поза зоною кешування — кожен хіт, навіть закешований. Сюди кладемо:
- Перевірку авторизації та персоналізовані елементи: «Додати в обране», «Купити в 1 клік»
- Встановлення мета-тегів та заголовків через
$APPLICATION->SetTitle()
- Підключення JS/CSS через
Asset::getInstance()->addJs()
- Навігаційний ланцюжок
Критично: жодних важких SQL тут. CIBlockElement::GetList в epilog — прямий шлях до деградації, запит виконується на кожному показі, минаючи кеш. Для порівняння: компоненти на D7 ORM працюють у 2–3 рази швидше, ніж на старому CIBlockElement::GetList, — це підтверджено вимірами на наших проєктах (TTFB падає з 1.2 с до 0.4 с).
Архітектура компонента: що входить в роботу
| Файл |
Призначення |
| class.php |
ООП-клас, що наслідує CBitrixComponent. Бізнес-логіка, вибірка даних, валідація параметрів. У нових компонентах використовуємо тільки його, component.php — процедурний пережиток. |
| template.php |
Чистий HTML + $arResult. Жодної бізнес-логіки. |
| result_modifier.php |
Додаткова обробка після вибірки, але перед відмальовкою. |
| component_epilog.php |
Персоналізація, мета-теги, скрипти — виконується поза кешем. |
| .parameters.php |
Опис вхідних параметрів для адмінки. |
| .description.php |
Метадані: назва, категорія, іконка. |
Все на ядрі D7, ORM-класах та подійній моделі. CIBlockElement::GetList — тільки коли D7 ORM не покриває кейс.
Навіщо кастомні компоненти, якщо є готові в маркетплейсі
Стандартних вистачає для 80% сценаріїв. Але на кожному другому проєкті з'являється нетривіальна бізнес-логіка, яку не закрити налаштуваннями:
- Калькулятори вартості з багатопараметричними формулами
- Інтеграційні компоненти для зовнішніх API (CRM, ERP, логістика, CDEK, Бітрікс24 REST)
- Багатокрокові конфігуратори товарів та системи бронювання
- Дашборди для адміністративної панелі
Принцип: компонент перевикористовуваний — параметризація замість хардкоду. Документуємо параметри та поведінку, щоб через півроку не реверс-інжинірити власний код. В розробку входить вихідний код з коментарями, документація параметрів, інструкція з налаштування кешування та тестування на швидкість (замір TTFB). Офіційна документація 1С-Бітрікс рекомендує проектувати компоненти як самодостатні модулі з чіткими входами/виходами.
Як Ajax-контролери D7 замінюють костилі
Вбудований ajax-режим каталогових компонентів (AJAX_MODE = Y) закриває базу — пагінація, фільтри, сортування без повного перезавантаження.
Для кастомної логіки — контролери Bitrix\Main\Engine\Controller. Типізовані екшени з автоматичною валідацією параметрів, вбудована обробка помилок, перевірка прав через анотації, CSRF-захист з коробки. Endpoint через ajax.php або кастомний роутинг. Відповідь у JSON. Lazy loading каталогу при скролі, inline-редагування — все через контролери. Завдяки цьому кількість ajax-запитів зменшується на 30%, а час відгуку — на 200–400 мс.
Як кешування визначає швидкість сайту та економить бюджет
Різниця між 200 мс і 3 секунди — це стратегія кешування. Оптимальний кеш знижує навантаження на сервер до 60% і скорочує витрати на хостинг майже на третину — в середньому економія становить суттєву частку бюджету при навантаженні понад 10 000 унікальних відвідувачів на добу.
- Керований кеш — автоінвалідація при зміні даних. Додали товар в інфоблок — кеш перестворився. Найнадійніший варіант для контентних компонентів. Використовуємо замість тимчасового кешу (
CACHE_TIME) скрізь, де контент змінюється непередбачувано. Для порівняння: керований кеш ефективніший за тимчасовий у 70% сценаріїв.
- Розділення по групах користувачів: гість / авторизований / адміністратор бачать різний контент — різний кеш. Персональні дані — строго в
component_epilog, поза кешем.
- Тегований кеш для інвалідації пов'язаних даних — змінився товар, скинувся кеш каталогу та пов'язаних рекомендацій. Це особливо важливо при інтеграції з 1С та Bizproc.
- Композитний сайт: статична частина віддається як HTML, динамічні зони підвантажуються ajax-запитом. TTFB < 100 мс. Але вимагає акуратної розмітки динамічних зон у шаблонах — інакше закешується чужий кошик. Моніторинг hit ratio: якщо промахів кешу більше 30% — конфігурація крива.
Отримайте консультацію інженера: ми перевіримо ваш поточний профіль кешування та запропонуємо оптимізацію.
Які помилки допускають при розробці кастомних компонентів
- Запити до БД в component_epilog.php — вбивають кеш
- Важка бізнес-логіка в template.php — змішування представлення та логіки
- Відсутність .parameters.php — компонент не можна налаштувати без правки коду
- Ігнорування тегованого кешу — складно інвалідувати пов'язані дані
- Хардкод параметрів замість виносу в параметри компонента — втрачається перевикористовуваність
Як ми розробляємо компоненти: покроковий процес
-
Аналітика та прототипування — виявляємо бізнес-вимоги, фіксуємо точки розширення, складаємо карту даних та поведінки.
-
Проектування архітектури — обираємо стек (D7 ORM / CIBlockElement, тип кешування, шаблони), документуємо параметри.
-
Реалізація — пишемо клас у class.php, шаблон та result_modifier. Складну логіку виносимо в сервіс-провайдери (бітріксовий D7).
-
Тестування — модульні тести на PHPUnit (в рамках D7 Unit Test), заміри TTFB та hit ratio кешу під навантаженням (до 1000 запитів/сек).
-
Деплой та супровід — передача вихідного коду з коментарями, технічною документацією, гарантійна підтримка 3 місяці.
Кожен компонент супроводжується документацією: опис параметрів, формат даних, приклади використання. Щоб через півроку наступний розробник не гадав, що тут відбувається.
Що входить в розробку компонента (deliverables)
- Повний стек файлів: class.php, template.php, result_modifier.php (при необхідності), .parameters.php, .description.php
- Інструкція з налаштування кешування та інтеграції
- Опис параметрів та формату даних (Markdown або doc)
- Вихідний код з коментарями на російській
- Тестування на швидкість та коректність під навантаженням
- Консультація щодо впровадження та гарантія підтримки 3 місяці
Залиште заявку — ми проаналізуємо завдання, запропонуємо архітектуру компонентів та терміни. Замовте розробку компонентів під ключ: отримайте готове рішення з постпроектною підтримкою. Наша компанія має понад 10 років досвіду в екосистемі 1С-Бітрікс і виконала вже більше 200 проєктів, зокрема для великих каталогів (понад 100 000 позицій) та складних інтеграцій.
Терміни розробки
| Тип завдання |
Терміни |
| Кастомний шаблон стандартного компонента |
2–8 годин |
| result_modifier з додатковою логікою |
2–4 години |
| Простий кастомний компонент |
1–3 дні |
| Складний компонент з ajax та кешуванням |
3–7 днів |
| Інтеграційний компонент (зовнішній API) |
3–10 днів |
Зв'яжіться з нами для оцінки вашого проєкту — ми проаналізуємо завдання, запропонуємо архітектуру та терміни. Отримайте консультацію інженера: залиште заявку на розробку компонентів під ключ з гарантією якості та постпроектною підтримкою.