Перейти к основному содержимому

Добавление в корзину (Short Flow)

Руководство по интеграции кнопки "Купить" с прямым добавлением товара в корзину на сайте.

Мобильное приложение?

Если ShopStory открывается в WebView нативного приложения (iOS/Android), используйте mobile bridge вместо callback'ов. Bridge-событие add-product передаёт feedProductId в нативный слой, где приложение само добавляет товар в корзину.

Что такое Short Flow

SDK поддерживает два режима кнопки "Купить":

РежимПоведениеНастройка
Redirect (по умолчанию)Переход на страницу товараНе требуется
Short FlowДобавление в корзину без переходаПередать actions при инициализации SDK

При Short Flow: кнопка "Купить" → спиннер → "В корзине" → клик открывает страницу корзины.

Предварительные требования

  1. В YML-фиде у каждого <offer> заполнен атрибут id. Это ID товара/оффера в вашей CMS, например <offer id="2858">.
  2. SDK встроен на домене сайта как <script> (same-origin для cookies). См. Установка SDK.
  3. На сайте есть способ добавить товар в корзину программно (AJAX или JS API).

Интеграция

Ниже показаны только параметры Short Flow, которые нужно добавить к уже работающему ShopStorySDK.show(...).

Параметры Short Flow

short-flow-options.ts
type ShortFlowOptions = {
actions?: {
// Добавить товар по ID из фида (feedProductId)
addProductToCartById?: (id: string, callback: (result: boolean) => void) => void;
// Добавить товар по артикулу (vendorCode)
addProductToCart?: (vendorCode: string, callback: (result: boolean) => void) => void;
};
cartUrl?: string; // URL страницы корзины
};

Для YML-фида рекомендуемый путь интеграции: addProductToCartById.

Полный пример инициализации

shopstory-short-flow.js
ShopStorySDK.show({
containerElement: document.getElementById('shopstory'),
cartUrl: '/personal/cart/',
actions: {
addProductToCartById: function(id, callback) {
// Ваш код добавления товара в корзину
fetch('/your-cart-endpoint', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ productId: id, quantity: '1' }),
})
.then(function(r) { return r.json(); })
.then(function(data) { callback(data.success === true); })
.catch(function() { callback(false); });
},
},
});

Что передаётся в id

Параметр id — это значение атрибута id из тега <offer id="..."> в вашем YML-фиде. SDK передаёт его как строку, даже если значение числовое.

Пример: если в фиде <offer id="2858">, то в callback придёт id = "2858".

В id приходит не артикул

В YML-фидах Битрикс у товара два разных идентификатора:

yml-offer-example.xml
<offer id="1537" available="true">
<vendorCode>4009</vendorCode>
<name>Крем для ног Super Moisture</name>
</offer>
Поле в фидеПримерЧто этоВ callback?
<offer id="1537">1537iblock element ID (внутренний ID в БД Битрикс)Да — передаётся как id
<vendorCode>4009</vendorCode>4009Артикул (виден покупателю на сайте)Нет

SDK передаёт <offer id> (= iblock element ID), потому что именно его ожидает Basket::addProduct(['PRODUCT_ID' => ...]) в Битрикс.

Артикул (vendorCode) используется в ShopStory для отображения стримерам, но для добавления в корзину не нужен.

Контракт callback

ВызовРезультат в UI
callback(true)Кнопка меняется на "В корзине", клик открывает cartUrl
callback(false)Кнопка меняется на "Нет в наличии" (disabled)

Важно: callback нужно вызвать ровно один раз. Если callback не вызван, кнопка останется в состоянии загрузки (спиннер) навсегда.

callback(false) означает только то, что товар не удалось добавить. Это может быть как бизнес-ошибка, так и проблема в вашем HTTP/JS-обработчике.

Параметр cartUrl

  • Относительный путь (/personal/cart/ или personal/cart/) — SDK добавит location.origin автоматически, ведущий / необязателен.
  • Абсолютный URL (https://example.com/cart/) — используется как есть.
  • Если cartUrl не указан, кнопка "В корзине" не будет кликабельной.

Примеры по платформам

1С Битрикс

PHP-обработчик. Создайте на сайте файл /local/ajax/shopstory-cart.php:

shopstory-cart.php
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');

use Bitrix\Main\Loader;

header('Content-Type: application/json');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'error' => 'Method not allowed']);
die();
}

Loader::includeModule('sale');
Loader::includeModule('catalog');

$productId = intval($_POST['productId'] ?? 0);
$quantity = intval($_POST['quantity'] ?? 1);

if ($productId <= 0) {
echo json_encode(['success' => false, 'error' => 'Invalid product ID']);
die();
}

$result = \Bitrix\Catalog\Product\Basket::addProduct([
'PRODUCT_ID' => $productId,
'QUANTITY' => $quantity,
]);

if ($result->isSuccess()) {
echo json_encode(['success' => true]);
} else {
echo json_encode([
'success' => false,
'error' => implode(', ', $result->getErrorMessages()),
]);
}

require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php');

JS callback:

bitrix-short-flow.js
ShopStorySDK.show({
containerElement: document.getElementById('shopstory'),
cartUrl: '/personal/cart/',
actions: {
addProductToCartById: function(id, callback) {
fetch('/local/ajax/shopstory-cart.php', {
method: 'POST',
credentials: 'include', // Обязательно: отправляет cookies сессии корзины
headers: {
'Content-Type': 'application/x-www-form-urlencoded', // Не JSON
},
body: new URLSearchParams({
productId: id,
quantity: '1',
}),
})
.then(function(r) { return r.json(); })
.then(function(data) { callback(data.success === true); })
.catch(function() { callback(false); });
},
},
});

Важные нюансы Битрикс:

  • В callback приходит iblock element ID из атрибута <offer id="...">, а не <vendorCode>. Именно этот ID нужен для Basket::addProduct.
  • Для товаров с вариантами в фиде должен быть ID торгового предложения (offer/SKU), а не родительского товара. Если у <offer> есть атрибут group_id, для корзины нужен именно id этого предложения.
  • Content-Type: application/x-www-form-urlencoded обязателен, потому что PHP $_POST не парсит application/json.
  • credentials: 'include' обязателен, иначе корзина создастся в другой сессии.
  • sessid (CSRF) не нужен. Сессионной cookie достаточно для аутентификации.
  • URL обработчика может быть любым, если он создаётся на сайте.

Shopify

shopify-short-flow.js
ShopStorySDK.show({
containerElement: document.getElementById('shopstory'),
cartUrl: '/cart',
actions: {
addProductToCartById: function(id, callback) {
fetch('/cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
items: [{ id: Number(id), quantity: 1 }],
}),
})
.then(function(r) {
callback(r.ok);
})
.catch(function() { callback(false); });
},
},
});

Универсальный пример

Контракт простой: любая функция, которая вызывает callback(true) при успехе и callback(false) при ошибке. Это может быть HTTP POST, JS-вызов глобальной функции или любой другой способ.

generic-short-flow.js
ShopStorySDK.show({
containerElement: document.getElementById('shopstory'),
cartUrl: '/cart/',
actions: {
addProductToCartById: function(id, callback) {
fetch('/api/cart/add', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ id: id }),
})
.then(function(r) { callback(r.ok); })
.catch(function() { callback(false); });

// Если CMS предоставляет глобальный JS API:
// window.yourCMS.addToCart(Number(id), {
// onSuccess: function() { callback(true); },
// onError: function() { callback(false); },
// });
},
},
});

Чек-лист интеграции

  • AJAX или JS-добавление в корзину работает независимо.
  • В XML-фиде у <offer> заполнен атрибут id.
  • SDK загружен как <script> на домене сайта, не в iframe.
  • callback(true) или callback(false) вызывается ровно один раз.
  • cartUrl указан и ведёт на страницу корзины.
  • После клика "Купить" кнопка показывает спиннер, затем "В корзине".
  • При ошибке callback(false) кнопка показывает "Нет в наличии".
  • Клик по "В корзине" открывает страницу корзины в новой вкладке.

Частые проблемы

СимптомПричинаРешение
Кнопка "Купить" переходит на страницу товара вместо добавления в корзинуactions не передан при sdk.show()Добавить actions.addProductToCartById в конфиг
Кнопка не реагируетАтрибут id пустой в фидеЗаполнить атрибут id в XML-фиде
403/401 от сервераCookies не отправляютсяДобавить credentials: 'include' в fetch()
Товар не в корзине (Bitrix)Отправлен parent product ID вместо offer IDВ фиде указать ID торгового предложения (SKU)
Пустой $_POST на PHPОтправлен Content-Type: application/jsonИспользовать application/x-www-form-urlencoded
"В корзине" не кликаетсяcartUrl не указанДобавить cartUrl при инициализации SDK
Корзина "пустая" после добавленияЗапрос создал новую сессиюSDK должен быть на same-origin, не в iframe
Добавляется не тот товар (Bitrix)В обработчик передан артикул вместо iblock element IDВ callback приходит <offer id>, а не <vendorCode>
Кнопка "зависла" на спиннереcallback() не вызван в вашей функцииВызвать callback(true) или callback(false) во всех ветках, включая .catch()

Быстрый старт: 1С Битрикс

Типовой сценарий для сайта на 1С Битрикс.

Шаг 1. Создайте файл /local/ajax/shopstory-cart.php на вашем сайте по примеру выше.

Шаг 2. Протестируйте обработчик из консоли браузера:

bitrix-cart-check.js
fetch('/local/ajax/shopstory-cart.php', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ productId: '1537', quantity: '1' }),
})
.then(function(r) { return r.json(); })
.then(function(data) { console.log('Результат:', data); });

Ожидаемый ответ: { success: true }.

Здесь productId должен быть равен iblock element ID из <offer id="1537">, а не артикулу 4009 из <vendorCode>. Подставьте значение из вашего фида.

Шаг 3. Добавьте actions и cartUrl в инициализацию SDK:

bitrix-sdk-init.js
ShopStorySDK.show({
containerElement: document.getElementById('shopstory'),
cartUrl: '/personal/cart/',
actions: {
addProductToCartById: function(id, callback) {
fetch('/local/ajax/shopstory-cart.php', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ productId: id, quantity: '1' }),
})
.then(function(r) { return r.json(); })
.then(function(data) { callback(data.success === true); })
.catch(function() { callback(false); });
},
},
});

Кнопка "Купить" после этого будет добавлять товар в корзину Битрикс, а кнопка "В корзине" будет открывать /personal/cart/.