
msBundles
Product bundles for miniShop3 with shared pricing, discounts, and cart sync
- MODX 3
- PHP 8.2
- miniShop3
- Vue 3


Компонент предоставляет четыре маршрута через роутер miniShop3. База: /api/v1/msbundles.
/assets/components/minishop3/api.php?route=/api/v1/msbundles/…Требуется ms3_token (авторизация в корзине). Штатный JS-фронт ходит в API сам.
Успех:
{
"success": true,
"message": "",
"data": {},
"errors": [],
"warnings": []
}Ошибка: HTTP 4xx, success: false, data: null.
/bundle/calculate Пересчёт цены и остатков комплекта.
Query-параметры:
| Параметр | Обязателен | Описание |
|---|---|---|
id или bundle_id | Да | ID комплекта |
quantity | Нет | Число комплектов (по умолчанию 1) |
Пример:
…/api.php?route=/api/v1/msbundles/bundle/calculate&id=5&quantity=2Ответ:
{
"success": true,
"data": {
"price": {
"total": 12500,
"original_total": 15000,
"savings": 2500,
"total_formatted": "12 500 ₽",
"original_total_formatted": "15 000 ₽",
"savings_formatted": "2 500 ₽",
"price_html": "<span class=\"msbundles__price\">…</span>"
},
"stock": {
"available": true,
"message": "",
"warnings": []
},
"quantity": 2
}
}Поля price:
| Поле | Описание |
|---|---|
total | Итоговая цена (число) |
original_total | Сумма по оригинальным ценам |
savings | Экономия |
*_formatted | Строки с валютой или «Бесплатно» |
price_html | Готовый HTML для [data-msbundles="price"] |
Поля stock:
| Поле | Описание |
|---|---|
available | true / false — можно заказать |
message | Сообщение об остатке (плейсхолдер stock_message) |
warnings | Массив предупреждений для необязательных позиций |
/bundle/add Добавить комплект в корзину. Лимит: msbundles_max_bundle_quantity.
Body (JSON):
{
"id": 5,
"quantity": 2
}Алиас: bundle_id.
Ответ:
{
"success": true,
"data": {
"bundle_hash": "a1b2c3d4e5…",
"quantity": 2
}
}Поведение:
warnings. Остальной комплект добавится.msOnBeforeBundleAdd / msOnBundleAdded./bundle/remove Удалить строки комплекта из корзины по bundle_hash.
Body (JSON):
{
"bundle_hash": "a1b2c3d4e5…"
}Алиас: hash.
Ответ:
{
"success": true,
"data": {
"removed_count": 3,
"bundle_hash": "a1b2c3d4e5…"
}
}Поведение:
bundle_hash.msOnBeforeBundleRemove / msOnBundleRemoved./bundle/get Получить данные комплекта с ценой и остатками.
Query-параметры:
| Параметр | Обязателен | Описание |
|---|---|---|
id или bundle_id | Да | ID комплекта |
quantity | Нет | Число комплектов (по умолчанию 1) |
Ответ:
{
"success": true,
"data": {
"bundle": {
"id": 5,
"name": "Набор для путешествий",
"description": "…",
"image": "…",
"active": true,
"context_key": "web"
},
"price": { … },
"stock": { … },
"quantity": 1
}
}| Метод | Путь | Описание |
|---|---|---|
GET | /bundle/calculate | Пересчёт цены и остатков |
POST | /bundle/add | Добавление в корзину |
POST | /bundle/remove | Удаление из корзины |
GET | /bundle/get | Данные комплекта |
| Код | Ситуация |
|---|---|
400 | Неверные параметры (нет id, quantity < 1) |
403 | Нет ms3_token или недостаточно прав |
404 | Комплект не найден или неактивен |
422 | Превышен лимит msbundles_max_bundle_quantity |
const res = await fetch('/assets/components/minishop3/api.php?route=/api/v1/msbundles/bundle/calculate&id=5&quantity=2');
const json = await res.json();
if (json.success) {
console.log(json.data.price.total_formatted);
}const res = await fetch('/assets/components/minishop3/api.php?route=/api/v1/msbundles/bundle/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 5, quantity: 2 })
});
const json = await res.json();
if (json.success) {
console.log('bundle_hash:', json.data.bundle_hash);
}const res = await fetch('/assets/components/minishop3/api.php?route=/api/v1/msbundles/bundle/remove', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ bundle_hash: 'a1b2c3d4e5…' })
});
const json = await res.json();События JS: Вывод на сайте.
События MODX: События.