Розробка сайту ресторану на 1С-Бітрікс
Сайт ресторану, який працює, — це не сторінка з фото інтер'єру та PDF-меню. Це система, де замовлення з сайту потрапляють у касу, бронювання столиків відображаються в CRM, а стоп-лист оновлюється автоматично, коли на кухні закінчився інгредієнт. Усе побудовано на інфоблоках, кастомних компонентах і REST API касових систем. Якщо на старті неправильно спроєктувати зв'язок між інфоблоком меню та POS-системою, через місяць виявиться, що сайт приймає замовлення на страви, яких уже немає в стоп-листі каси.
Інфоблок «Меню»: архітектура даних
Меню — інфоблок із розділами-категоріями та елементами-стравами. Розділи: «Сніданки», «Салати», «Гаряче», «Десерти», «Напої», «Винна карта». Один рівень вкладеності для підкатегорій (наприклад, «Червоне вино» всередині «Винна карта»).
Властивості елемента (страви):
-
WEIGHT— числове, грами. Відображається на картці та у Schema.org розмітці -
CALORIES— числове, ккал. За потреби — розширений блок:PROTEINS,FATS,CARBSяк окремі числові властивості -
ALLERGENS— множинний список: глютен, лактоза, горіхи, морепродукти, яйця, соя. Фільтрація черезCIBlockElement::GetList()ізPROPERTY_ALLERGENSу масиві фільтра -
PRICE— числове. Зберігається як звичайна властивість інфоблоку, якщо кошик не потрібен. Для онлайн-оплати — підключення до торгового каталогу черезCCatalog::Add() -
PHOTO— файл, основне фото страви. Додаткові фото — множинна властивістьMORE_PHOTOS -
IS_NEW— чекбокс, мітка «Новинка» -
IS_SPICY— чекбокс, гостра страва -
STOP_LIST— чекбокс. Страва тимчасово недоступна. Елемент залишається в базі, але приховується фільтром у шаблоні компонента -
SORT_ORDER— числове. Порядок у розділі, дає змогу шеф-кухарю через адмінку виставити фірмові страви першими -
IIKO_PRODUCT_ID/RK_MENU_ITEM_ID/POSTER_PRODUCT_ID— рядок, ідентифікатор страви в касовій системі
Онлайн-замовлення та інтеграція з POS — найскладніша частина
Тут зосереджена більша частина інженерної роботи. Ресторан працює з касовою системою — iiko, r_keeper або Poster. Сайт повинен передавати замовлення в касу в реальному часі й отримувати зворотний зв'язок: підтвердження, час приготування, статус доставки.
Інтеграція з iiko Transport API:
Авторизація — POST /api/1/access_token із apiLogin. Токен живе 60 хвилин, кешується в Highload-блоці з TTL-полем.
Синхронізація меню — GET /api/1/nomenclature з organizationId. Відповідь містить повне дерево продуктів: групи (категорії) та продукти (страви) з UUID, цінами, вагою, модифікаторами, стоп-листом. Агент CAgent запускається кожні 15 хвилин і звіряє дані:
- Зіставлення продуктів за
IIKO_PRODUCT_ID. Якщо продукт є в iiko, але немає в Бітрікс — створюється елемент зі статусом «Чернетка», не публікується до перевірки адміністратором - Порівняння цін. Якщо ціна в iiko відрізняється від
PRICEв інфоблоці — оновлення черезCIBlockElement::SetPropertyValuesEx() - Синхронізація стоп-листа. iiko позначає позиції як недоступні — агент встановлює
STOP_LIST = Yна відповідному елементі - Завантаження модифікаторів (добавки, гарніри, соуси) в окремий інфоблок «Модифікатори» з
IIKO_MODIFIER_ID
Створення замовлення — POST /api/1/deliveries/create:
Тіло запиту містить маппінг позицій кошика Бітрікс на UUID продуктів iiko:
{
"organizationId": "...",
"order": {
"phone": "+380...",
"orderTypeId": "delivery-type-uuid",
"items": [
{
"productId": "iiko-product-uuid",
"amount": 2,
"modifiers": [
{ "productId": "modifier-uuid", "amount": 1 }
]
}
],
"address": { "street": "...", "house": "...", "flat": "..." },
"comment": "Без цибулі",
"payments": [
{ "paymentTypeId": "online-payment-uuid", "sum": 45.00 }
]
}
}
Відповідь містить correlationId. Сайт зберігає його в Highload-блоці «Замовлення» і використовує для відстеження статусу через GET /api/1/deliveries/by_id.
Відстеження статусу замовлення:
iiko підтримує webhooks для зміни статусу доставки. Endpoint /api/iiko-webhook/ приймає POST-запити зі статусами: «Підтверджено», «Готується», «В дорозі», «Доставлено», «Скасовано». Обробник оновлює запис у Highload-блоці. На сторінці /my-orders/ фронтенд отримує оновлення через AJAX-опитування кожні 30 секунд.
Для POS без webhooks — cron-задача (CAgent) опитує API статусу кожні 60 секунд для всіх замовлень у стані «Активне».
Відмінності інтеграції з r_keeper:
r_keeper працює через UCS DeliveryPOS API з протоколом XML-RPC замість JSON REST. Запити обгорнуті в XML-конверти, відповіді парсяться через SimpleXMLElement. Маппінг товарів — за MenuItemID. Головна складність: r_keeper зазвичай вимагає VPN-тунель до локального сервера ресторану, тоді як iiko та Poster працюють через хмару.
Poster POS:
REST API з OAuth-авторизацією. Створення замовлення — POST /api/incomingOrders.createIncomingOrder. Маппінг за product_id. Poster надсилає webhook-повідомлення при зміні статусу замовлення. З трьох систем Poster найпростіший в інтеграції.
Бронювання столиків
Кастомний компонент project:table.reservation із полями: дата, час, кількість гостей, ім'я, телефон, коментар.
Структура даних:
- Бронювання в Highload-блоці:
DATE,TIME,GUESTS,NAME,PHONE,STATUS,TABLE_ID - Столики в окремому Highload-блоці:
TABLE_NUMBER,CAPACITY,ZONE(зал, тераса, VIP) - Перевірка доступності: вибірка бронювань за
DATEіз вікном ±2 години від запитуваногоTIME, зіставлення з вільними столиками за місткістю
Інтеграція з CRM Бітрікс24:
Кожне бронювання створює лід через REST API crm.lead.add:
$leadData = [
'TITLE' => 'Бронь столика: ' . $date . ' ' . $time,
'NAME' => $name,
'PHONE' => [['VALUE' => $phone, 'VALUE_TYPE' => 'WORK']],
'SOURCE_ID' => 'WEB',
'UF_CRM_TABLE' => $tableNumber,
'UF_CRM_GUESTS' => $guests,
];
CRest::call('crm.lead.add', ['fields' => $leadData]);
Хостес бачить бронювання в CRM і підтверджує їх. Зміна статусу ліда на «Підтверджено» → обробник оновлює STATUS у Highload-блоці → клієнт отримує SMS через модуль messageservice або зовнішній SMS-шлюз.
Оптимізація зображень
Фуд-фотографія — це файли по 5-10 МБ. На сайті потрібні три розміри: thumbnail для списку меню (400x300), середній для картки страви (800x600), повний для лайтбоксу (1600x1200).
Ресайз — CFile::ResizeImageGet() з BX_RESIZE_IMAGE_PROPORTIONAL. Результат кешується в /upload/resize_cache/.
Конвертація в WebP — через imagewebp() в обробнику OnBeforeFileResize або на рівні Nginx через ngx_http_image_filter_module. WebP зменшує розмір на 25-35% порівняно з JPEG при аналогічній якості.
Адаптивні зображення:
<img
src="/upload/resize_cache/menu/800x600/dish.webp"
srcset="/upload/resize_cache/menu/400x300/dish.webp 400w,
/upload/resize_cache/menu/800x600/dish.webp 800w,
/upload/resize_cache/menu/1600x1200/dish.webp 1600w"
sizes="(max-width: 640px) 400px, (max-width: 1024px) 800px, 1600px"
loading="lazy"
alt="Назва страви"
>
Атрибут loading="lazy" — нативне ліниве завантаження. Для старих браузерів — IntersectionObserver. На сторінці меню з 50+ стравами це економить 30-40 МБ початкового завантаження.
Mobile-first: 80%+ трафіку з телефонів
Сайт ресторану шукають із телефону — «ресторан поруч», «меню доставки». Шаблон будується mobile-first:
- Категорії меню — горизонтальний скрол із
overflow-x: auto, а не випадний список - Картка страви — фото на всю ширину, назва, вага, ціна. Кнопка «Додати» зафіксована внизу екрану через
position: sticky - Форма замовлення — мінімум полів: телефон + адреса. Ім'я та коментар опціонально. Автодоповнення адреси через Dadata API або Google Places API
- Форма бронювання — нативні
<input type="date">та<input type="time">
Три breakpoints: 375px (телефон), 768px (планшет), 1280px (десктоп). Цільові показники Lighthouse: Performance > 90, LCP < 2.5s.
Мультимовне меню
Для ресторанів у туристичних зонах — меню кількома мовами. Два підходи в 1С-Бітрікс:
-
Багатосайтовість — окремі прив'язки сайтів (
LID=s1для української,s2для англійської). Інфоблок прив'язаний до обох сайтів, додаткові властивостіNAME_EN,DESCRIPTION_EN. Окремі URL (/menu/та/en/menu/), коректніhreflang-теги, незалежні SEO-налаштування -
Властивість мови —
LANGUAGE(список: uk, en, de) із фільтрацією в компоненті заLANGUAGE_ID
Перший варіант надійніший і кращий для SEO.
Schema.org: Restaurant + Menu
JSON-LD розмітка формується в result_modifier.php:
{
"@context": "https://schema.org",
"@type": "Restaurant",
"name": "Назва ресторану",
"servesCuisine": "Італійська",
"address": {
"@type": "PostalAddress",
"streetAddress": "...",
"addressLocality": "Київ"
},
"openingHoursSpecification": [...],
"menu": {
"@type": "Menu",
"hasMenuSection": [
{
"@type": "MenuSection",
"name": "Гаряче",
"hasMenuItem": [
{
"@type": "MenuItem",
"name": "Стейк рібай",
"nutrition": {
"@type": "NutritionInformation",
"calories": "850 cal"
},
"offers": {
"@type": "Offer",
"priceCurrency": "UAH"
}
}
]
}
]
}
}
Виводиться через $APPLICATION->AddHeadString(). Google розпізнає типи Restaurant, Menu, MenuItem для Rich Snippets у пошуковій видачі.
Акції та спецпропозиції
Інфоблок «Акції» (тип promotions). Властивості: DATE_START, DATE_END, PROMO_TYPE (бізнес-ланч, happy hour, сезонна), DISCOUNT_PERCENT, LINKED_DISHES (множинна прив'язка до елементів інфоблоку «Меню»).
Вивід на головній через news.list із фільтром за датами: >=DATE_START та <=DATE_END відносно поточної дати. Акції, що завершилися, приховуються автоматично.
Для бізнес-ланчу — окремий розділ меню, видимий лише з 12:00 до 16:00. Перевірка серверного часу в component.php.
Інтеграція з агрегаторами доставки
Glovo, Bolt Food та інші агрегатори надають API для ресторанів-партнерів. Інтеграція двостороння:
- Вигрузка меню — XML/JSON-фід із позиціями, цінами, фото, стоп-листом. Генерується агентом кожні 30 хвилин з інфоблоку «Меню»
-
Прийом замовлень — webhook від агрегатора на
/api/aggregator-order/. Обробник створює замовлення в Highload-блоці й передає в POS-систему
Це позбавляє адміністратора від ручного оновлення меню в кабінетах агрегаторів.
Анонси подій ресторану
Інфоблок «Заходи» — для анонсів: жива музика, тематичні вечори, дегустації. Властивості: EVENT_DATE, EVENT_TIME, DESCRIPTION, COVER_CHARGE (чекбокс — вхід платний/безкоштовний), POSTER (зображення).
Вивід — стрічка на головній (три найближчі заходи) та окрема сторінка /events/ зі списком. Минулі заходи переміщуються в архів автоматично за EVENT_DATE < now().
Етапи розробки
- Проєктування (1-2 тижні) — структура інфоблоків, схема інтеграції з POS, прототипи сторінок, маппінг даних між Бітрікс і касовою системою
- Дизайн (1-2 тижні) — макети: головна, меню (список + картка), бронювання, доставка, акції
- Бекенд (2-4 тижні) — інфоблоки, компоненти меню та бронювання, інтеграція з POS, CRM, обробка замовлень
- Фронтенд (1-3 тижні) — адаптивні шаблони, оптимізація зображень, форми замовлення та бронювання, AJAX-оновлення статусів
- Інтеграції (1-2 тижні) — POS-система, агрегатори доставки, SMS-повідомлення, платіжна система
- Тестування (1-2 тижні) — функціональне, тестові замовлення через POS, мобільне тестування, навантажувальне
- Запуск (3-5 днів) — деплой, моніторинг синхронізації з касою, перевірка на реальних замовленнях
| Масштаб проєкту | Орієнтовні терміни |
|---|---|
| Сайт-візитка з меню та бронюванням | 3-5 тижнів |
| Сайт з онлайн-замовленням та інтеграцією POS | 6-9 тижнів |
| Повна система: замовлення, POS, агрегатори, мультимовність | 8-12 тижнів |
Терміни залежать від обраної POS-системи (iiko інтегрується швидше за r_keeper завдяки хмарному API), кількості мов та вимог до особистого кабінету клієнта.







