Виджет Смартомато
Смартомато предоставляет возможность создания онлайн-витрины ресторана с функцией заказа посредствой одной из встроенных в сервис тем. Однако, рестораны, для которых функционала тем недостаточно, могут использовать решение в виде встроенного на пользовательский сайт виджета.
Использование виджета позволяет организовать возможность онлайн-заказа на сайте с произвольным дизайном и структурой.
Размещение виджета на стороннем сайте
Использование виджета возможно, если:
- настроен ресторан в системе Смартомато;
- ресторан содержит актуальное опубликованное меню.
На страницах сайта вашего ресторана должен быть размещен код виджета:
<!-- Smartomato Widget -->
<script src="//smartomato.ru/basket/widget/widget.js"></script>
<script type="text/javascript">smartomatoWidget.initialize({
host: "//_ид_вашей_организации.smartomato.ru/", // Например, "//26.smartomato.ru/",
assetsBase: "//smartomato.ru/basket/widget",
organization_id: "9999" // id вашей организации
});</script>
<!-- Smartomato Widget -->
Виджет умеет фиксировать цели в веб-аналитике. Если на сайте вставлен код Яндекс.Метрики или Google Analytics — добавьте информацию об аналитике:
<!-- Smartomato Widget -->
<script src="//smartomato.ru/basket/widget/widget.js"></script>
<script type="text/javascript">smartomatoWidget.initialize({
host: "//9999.smartomato.ru/",
assetsBase: "//smartomato.ru/basket/widget",
organization_id: "9999",
analytics: {
yandex_metrika_code: "99999999", // актуальный id метрики
google_analytics_code: "UA-99999999-1" // актуальный id аналитики
}
});</script>
<!-- Smartomato Widget -->
Необходимо предусмотреть в макете сайта кнопку либо иной элемент, нажатие на который будет помещать определенное блюдо в корзину. Для того чтобы виджет понимал, какое именно блюдо необходимо поместить в корзину, нужно добавить следующий атрибут к кнопке data-dish-id="код блюда в системе Смартомато"
. Например:
<div data-dish-id="1854">Добавить</button>
Могут быть использованы любые html-элементы, принимающие событие onClick
. Если в системе управления сложно предусмотреть хранение кодов блюда Cмартомато, можно использовать id, используемые в вашей системе, тогда в интерфейсе управления Смартомато необходимо задать соответствие кодов.
В таком случае в кнопке, вместо data-dish-id
необходимо добавлять атрибут data-dish-external-id
. Например так:
<div data-dish-external-id="1854">Добавить</button>
Настройка feature-флагов
В настройках инициализации виджета можно указать дополнительные параметры для включения функций, которые отключены по умолчанию:
smartomatoWidget.initialize({
host: 'setters.smartomato.ru',
features: {
// Данный флаг позволяет автоматически расширить высоту страницы сайта
// c учетом нижней панели виджета
extendPageHeight: true
}
});
Отображение состояния стоп-листов на сайте
Смена условий доставки заказа в виджете, таких как адрес и время, может приводить к измению доступности блюд в контексте выбранных ресторанов. Интеграция виджета на стороннем сайте позволяет определить особое поведение при изменении этого состояния.
При инициализации возможна передача параметра-функции dishAvailabilityHandler, которую виджет будет вызывать при смене стоп-листов. Единственным параметров функции является массив availability, который имеет следующий формат:
var availability = [
{
restaurant_id: 332, // Выбранный ресторан
dish_id: 148, // Идентификатор блюда
external_id: "dish-3", // Внешний идентификатор
// Статус доступности:
// - available блюдо доступно
// - not_available блюдо недоступно в ресторане
// - call уточнить наличие блюда по телефону
status: "available"
},
...
]
Приведем пример инициализации с параметром dishAvailabilityHandler:
smartomatoWidget.initialize({
host: '...',
dishAvailabilityHandler: function(availabilityData) {
// Идея следующая: находим соответствующую карточку блюда и
// выставляем класс в зависимости от доступности блюда
// Карточка блюда имеет класс .dish-card
var dishCards = {};
$('[data-dish-id]').each(function(i, el) {
// От кнопки "купить" идем вверх до карточки блюда
var $card = $(el).closest('.dish-card');
var dishId = $(el).data('dishId')
// Сбрасываем классы доступности
$card
.toggleClass("status-available", true)
.toggleClass("status-not-available", false)
.toggleClass("status-call", false);
dishCards[ dishId ] = $card;
});
if (availabilityData == null) return;
// Выставляем классы в соответствии с availabilities
for (var j = 0; j < availabilityData.length; ++j) {
var entry = availabilityData[j];
var $card = dishCards[ entry.dish_id ];
$card
.toggleClass("status-available", entry.status === "available")
.toggleClass("status-not-available", entry.status === "not_available")
.toggleClass("status-call", entry.status === "call"));
}
}
});
Импорт меню
API Смартомато позволяет осуществлять пакетный импорт элементов меню ресторана с учетом связей на основе внешних идентификаторов и поддержкой итеративного импорта (для сохранения статистики).
Для описания методов импорта меню при интеграции виджета с сайтом смотрите раздел «методы импорта, в котором затронуты схемы для периодического импорта и описано значение внешних идентификаторов.
Сбор данных для импорта
В случае отсутствия прямого доступа к базе данных интегрируемого ресторана подготовку данных для импорта можно осуществлять посредством сбора напрямую со страниц сайта ресторана. Рекомендуемыми средствами для этого являются: выполнение скрипта сбора в контексте странице (подразумевается разбор структуры DOM, для этого могут быть использованы вспомогательные библиотеки, например, jQuery) или использование окружений headless-браузеров, например, CasperJS или PhantomJS (этот вариант наиболее удобен, когда сбор подразумевает навигацию между разными страницами сайта).
Приведем пример скрипта CasperJS для сбора данных меню с сайта одного из популярных ресторанов Москвы. Сайт содержит страницу с категориями меню, блюда каждой категории находятся на отдельных страницах, а информация о блюде представлена в виде модального окна, которое открывается при нажатии на карточку блюда:
var casper = require('casper').create({
remoteScripts: [
'http://code.jquery.com/jquery-2.1.4.min.js'
],
pageSettings: {
loadImages: false,
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5)'
}
// Опции для отладки:
// logLevel: "debug",
// verbose: true
});
// Базовый адрес сайта
var BASE_URL = 'http://*****.ru';
// Страница со списком категорий
var CATEGORIES_URL = BASE_URL + '/ru/menu/';
var result = [];
casper.start(CATEGORIES_URL, function() {
// ---
// Получаем список ссылок на категории
// ---
var categories = this.evaluate(function() {
return $('.b-menuList > a.item').map(function() {
return {
path: $(this).attr('href'),
name: $(this).find('.title').text()
};
}).get();
});
console.log('Получили список категорий:');
categories.forEach(function(c) {
console.log(' * ' + c.name + ' ' + BASE_URL + c.path)
});
// ---
// Переходим на страницу каждой категории
// ---
this.eachThen( categories, function(response) {
var link = BASE_URL + response.data.path;
var categoryName = response.data.name;
this.thenOpen(link, function(response) {
console.log('[!] Открываем страницу "' + categoryName + '"', link);
// ---
// Получаем id всех блюд на странице
// ---
var dishesIds = this.evaluate(function(categoryName) {
return $('.products a.item').map(function() {
return $(this).attr('data-pk');
}).get();
});
console.log(' [+] Найдено ' + dishesIds.length + ' блюд на странице' )
// ---
// Нажимаем на карточку каждого блюда и ждем появления модального окна через
// `waitUntilVisible`, далее получаем атрибуты блюда через элементы
// модального окна
// ---
this.eachThen(dishesIds, function(response) {
var dishId = response.data;
this.thenClick('.products a.item[data-pk="' + dishId + '"]', function() {
console.log(' [+] Кликнули на элемент ' + dishId);
this.waitUntilVisible('.b-popup', function(argument) {
var dish = this.evaluate(function() {
var $root = $('.b-popup');
var name = $root.find('.title').text();
var description = $root.find('.ingridients .text').text();
var image = $root.find('.left img').attr('src');
var weight = $root.find('.weight .digit').text();
var price = parseFloat(
$root.find('.price .digit').text()
.replace(/[^\d\.]/g,'')
);
return {
name: name,
weight: weight,
description: description,
remote_photo_url: image,
price: price
};
});
dish.external_id = dishId;
if(dish.remote_photo_url) {
dish.remote_photo_url = BASE_URL + dish.remote_photo_url;
}
dish.category_name = categoryName;
console.log(' [+] Собрали блюдо ' + dish.name);
result.push(dish);
});
});
});
});
});
})
// ---
// Выводим результат после завершения всех навигационных шагов
// ---
casper.run(function() {
console.log(JSON.stringify(result, null, 2))
casper.exit();
});
Запуск скрипта производится командой casperjs import.js --ignore-ssl-errors=yes --ssl-protocol=tls
, рекомендуемая версия CasperJS >= 1.1.0
.