MODX 3 MiniShop3 Несколько списков

ms3Favorites

Списки избранного для MODX Revolution 3 и MiniShop3: пользователи сохраняют товары и ресурсы, возвращаются к покупке позже, делятся списком по ссылке и оформляют заказ со страницы /wishlist/.

Данные в браузере (localStorage или cookie), синхронизация в БД для авторизованных и гостей (по настройкам). Кнопки data-favorites-toggle, счётчик data-favorites-count, сниппеты ms3Favorites, ms3FavoritesIds, ms3FavoritesPage и др., интеграция с mxQuickView и mFilter.

Преимущества

  • Несколько именованных списков (подарки, планы покупок и свои названия) с лимитами в настройках.
  • Шаринг уникальной ссылкой /wishlist/share?token=… и копирование чужого списка к себе.
  • Страница wishlist с табами и пагинацией: ms3FavoritesIdspdoPagems3Favorites.
  • Добавление выбранных позиций или всего списка в корзину MiniShop3 одним действием.
  • Заметки к позициям в карточках, единый сценарий для разных типов контента через resource_type.
  • AJAX-коннектор: синхронизация, шаринг, комментарии, корзина; уведомления через ms3fConfig.notify → MiniShop3 → iziToast.

Требования

  • MODX Revolution 3.0.3+
  • PHP 8.1+
  • MiniShop3 1.0+
  • pdoTools 3.x (рекомендуется для вывода списков и Fenom)

ms3Favorites

Пример 1. Кнопка добавления товара (products)

Постановка: показать минимальную кнопку «в избранное» для товара MiniShop3 (resource_type=products).

Вызов: разметка с data-favorites-toggle, data-id, data-resource-type="products" (в чанке подставьте id товара).

Вызов · Fenom / HTML
<button type="button" class="btn btn-outline-secondary ms3f__button"
    data-favorites-toggle
    data-id="{$product_id}"
    data-resource-type="products"
    title="{$_modx->lexicon('ms3favorites_add_tooltip')}">
    …
</button>

Пример 2. Кнопка добавления ресурса (resources)

Постановка: добавить в избранное документ сайта (MODX resource), а не товар MS3.

Вызов: кнопка с data-resource-type="resources" и data-id текущего или нужного ресурса.

Вызов · Fenom / HTML
<button type="button" class="btn btn-outline-secondary ms3f__button"
    data-favorites-toggle
    data-id="{$_modx->resource.id}"
    data-resource-type="resources"
    title="{$_modx->lexicon('ms3favorites_add_tooltip')}">
    …
</button>

Пример 3. Кнопка через ms3FavoritesBtn

Постановка: та же кнопка избранного через сниппет (удобно для единообразия с параметрами).

Вызов:

Вызов · Fenom
{'ms3FavoritesBtn' | snippet : [
    'id' => 26,
    'resource_type' => 'products'
]}

Пример 4. Счётчик избранного (JS)

Постановка: показать число позиций в избранном без сниппета — значение обновляет favorites.js.

Вызов: разметка + при необходимости скрыть «0» до инициализации JS.

Вызов · HTML (обновляет favorites.js)
<span data-favorites-count style="display: none;">0</span>
Избранное 0

Пример 5. Счётчик через ms3FavoritesCounter

Постановка: то же количество через сниппет (удобно для первого кадра и кэша).

Вызов: минимальный вызов, с параметрами и некэшируемый (! в имени сниппета — для pdoTools).

Вызов · Fenom
{'ms3FavoritesCounter' | snippet}

{'ms3FavoritesCounter' | snippet : [
    'list' => 'default',
    'resource_type' => 'products'
]}

{'!ms3FavoritesCounter' | snippet : [
    'list' => 'default',
    'resource_type' => 'products'
]}
Избранное 0

Пример 6. Счётчики только products

Постановка: считать только товары, не включая ресурсы в том же списке.

Вызов:

Вызов · HTML
<span data-favorites-count data-resource-type="products" style="display: none;">0</span>
0

Пример 7. Выбор списка при добавлении

Постановка: перед кликом «добавить» выбрать именованный список (default, gifts, plans и др.).

Вызов: чанк селектора + кнопка без data-list (список берётся из селектора).

Вызов · Fenom
{'tplFavoritesListSelector' | chunk}

<button type="button" class="btn btn-outline-primary"
    data-favorites-toggle
    data-id="{$product_id}">
    …
</button>

Пример 8. Кнопки для разных списков

Постановка: явно класть товар в нужный список через атрибут data-list.

Вызов:

Вызов · HTML
<button data-favorites-toggle data-id="{$product_id}" data-list="default">…</button>
<button data-favorites-toggle data-id="{$product_id}" data-list="gifts">…</button>
<button data-favorites-toggle data-id="{$product_id}" data-list="plans">…</button>

Пример 9. Блок избранного (JS render)

Постановка: отрисовать карточки избранного в контейнере через API фронтенда, несколько списков и переключение табами.

Вызов:

Вызов · JavaScript
ms3Favorites.render('#container');
ms3Favorites.render('#box', { list: 'gifts' });
ms3Favorites.switchList('plans');
ms3Favorites.render('#tabs', { list: 'plans' });

9a. Основной список

9b. Разные списки (default / gifts / plans)

9d. Переключение списка по табам

Пример 10. Пустое состояние

Постановка: проверить отображение пустого списка после очистки избранного.

Вызов: ms3Favorites.render('#id', { list: 'default' }) при пустом хранилище.

Вызов · JavaScript
ms3Favorites.render('#favorites-empty-demo', { list: 'default' });

Очистите избранное и обновите страницу.

Пример 11. Режим mode="list" (Товар A / Товар B)

Постановка: на странице списка избранного кнопки работают как «удалить из списка», а не «добавить».

Вызов: обёртка с data-favorites-mode="list", внутри — карточки с data-favorites-toggle.

Вызов · Fenom / HTML
<div data-favorites-mode="list">
    <button type="button" data-favorites-toggle
        data-id="$product_id"
        data-list="default">
        Удалить
    </button>
</div>
Товар A
Товар B

Пример 12. Страница избранного

Постановка: перейти на отдельный ресурс wishlist из системной настройки ms3favorites.list_page.

Вызов: ссылка на URI списка из настройки или на id ресурса.

Вызов · Fenom
<a href="{$_modx->makeUrl(123)}">Избранное</a>

<a href="/{('ms3favorites.list_page' | option) | trim : '/'}/">Избранное</a>

<a href="{$id | url}">Избранное</a>
Открыть /wishlist/

Пример 13. Очистить список

Постановка: одним действием очистить выбранный именованный список на клиенте и синхронизировать с сервером (по настройкам).

Вызов:

Вызов · HTML
<button type="button" data-favorites-clear data-list="default">…</button>

Пример 14. Поделиться списком

Постановка: получить публичную ссылку на копию списка (нужна сессия пользователя MODX).

Вызов:

Вызов · HTML
<button type="button" data-favorites-share data-list="default">…</button>

Нужна авторизация на сайте (сессия MODX). Это кнопка для коннектора; для страницы просмотра списка по ссылке используйте сниппет ms3FavoritesShare (см. документацию, пример 22).

Пример 15. Популярность

Постановка: вывести, у скольких пользователей в избранном данный товар/ресурс.

Вызов:

Вызов · Fenom
{'!ms3FavoritesPopularity' | snippet : [
    'resource_id' => $product_id
]}

{'!ms3FavoritesPopularity' | snippet : [
    'resource_id' => $product_id,
    'tpl' => '@INLINE У [[+count]] в избранном',
    'minCount' => 1
]}
У 0 пользователей в избранном

Пример 16. Список по ids: pdoPage + ms3Favorites

Постановка: серверная цепочка: в ms3FavoritesIds задать список и resource_type (фильтр типа при сборке id), затем пагинированный вывод через pdoPagems3Favorites по строке ids — у ms3Favorites параметр resource_type не передаётся (см. документацию).

Вызов:

Вызов · Fenom
{'!ms3FavoritesIds' | snippet : [
    'list' => 'default',
    'resource_type' => 'products',
    'toPlaceholder' => 'ms3f.ids'
]}

{set $idsStr = $_modx->getPlaceholder('ms3f.ids')}

{'!pdoPage' | snippet : [
    'element' => 'ms3Favorites',
    'ids' => $idsStr,
    'list' => 'default',
    'limit' => 3,
    'pageLimit' => 5,
    'tpl' => 'tplFavoritesItem',
    'emptyTpl' => 'tplFavoritesEmpty',
    'pageVarKey' => 'favpage',
    'totalVar' => 'ms3ffav.total',
    'pageNavVar' => 'ms3ffav.nav'
]}

{$_modx->getPlaceholder('ms3ffav.nav')}

Почему список «замирает» после удаления: HTML от pdoPage собран на сервере при ответе страницы. Добавление/удаление в избранном обрабатывает JavaScript и не перезапускает MODX-сниппеты, поэтому разметка сама не меняется.

Как синхронизировать: по событиям ms3f:added / ms3f:removed вызывать ms3Favorites.render() в контейнер списка (как ниже), либо перезагружать страницу, либо отдавать новый HTML своим AJAX к ресурсу. После первого такого обновления серверная навигация pdoPage скрывается — без отдельного запроса она уже не соответствует клиентскому списку.

Список пуст при загрузке. Добавьте товары кнопками выше — блок обновится через ms3Favorites.render.

Пример 17. Каталог: pdoPage + msProducts

Постановка: вывести каталог товаров с пагинацией и чанком строки, где есть кнопка избранного.

Это обычный каталог, а не «только избранное»: снятие товара с избранного не удаляет строку из таблицы — меняется только кнопка. После событий избранного ниже вызывается updateButtonStates(); при ajaxMode у pdoPage добавьте тот же вызов в callback подгрузки страницы (см. документацию интеграции).

Вызов:

Вызов · Fenom
{'!pdoPage' | snippet : [
    'element' => 'msProducts',
    'parents' => 0,
    'limit' => 10,
    'tpl' => 'tpl.msProducts.row',
    'pageVarKey' => 'catpage',
    'totalVar' => 'ms3fcat.total',
    'pageNavVar' => 'ms3fcat.nav'
]}

{$_modx->getPlaceholder('ms3fcat.nav')}

Чанк tplCatalogRowMs3f из пакета или замените tpl на свой (например msProducts_row с кнопкой избранного).

В избранное 0

Шуруповёрт Huawei Lite
В наличии
NEW ХИТ
Huawei арт. ART-000008
Шуруповёрт Huawei Lite
Синий Фиолетовый XL 38 39
0.976 кг 1-3 дня
108934.00
✓ В корзине
Наушники Huawei Mark II
В наличии
Huawei арт. ART-000009
Наушники Huawei Mark II
Красный Зелёный Фиолетовый +1 XS S XXL +2
4.392 кг 1-3 дня
91395.00
✓ В корзине
Тренажёр Huawei Series X
В наличии
-4%
Huawei арт. ART-000010
Тренажёр Huawei Series X
Зелёный XXL 36 39
2.061 кг 1-3 дня
28872.00
27860.00
✓ В корзине
Шуруповёрт Huawei Air
В наличии
-51%
Huawei арт. ART-000011
Шуруповёрт Huawei Air
Белый Золотой Фиолетовый +1 XL XXL 39
4.895 кг 1-3 дня
26336.00
12953.00
✓ В корзине
Наушники Apple Series S
В наличии
-11% NEW
Apple арт. ART-000012
Наушники Apple Series S
Золотой 39 44
1.731 кг 1-3 дня
127254.00
113154.00
✓ В корзине
Фен Huawei Essential
В наличии
-20%
Huawei арт. ART-000013
Фен Huawei Essential
Коричневый XS S L
2.708 кг 1-3 дня
93061.00
74896.00
✓ В корзине
Телевизор Samsung Edge 14
В наличии
-23%
Samsung арт. ART-000014
Телевизор Samsung Edge 14"
Фиолетовый XS S 37 +1
2.499 кг 1-3 дня
72712.00
55631.00
✓ В корзине
Фен Xiaomi Classic
В наличии
-5% NEW
Xiaomi арт. ART-000015
Фен Xiaomi Classic
Серый Серебристый Бежевый XS S XL +1
1.965 кг 1-3 дня
131212.00
124968.00
✓ В корзине
Кроссовки Samsung Advanced
В наличии
Samsung арт. ART-000016
Кроссовки Samsung Advanced
Синий Красный Коричневый L 40
3.641 кг 1-3 дня
118481.00
✓ В корзине
Тренажёр Apple Neo
В наличии
Apple арт. ART-000017
Тренажёр Apple Neo
Чёрный Серый Красный +1 M XL 36 +2
4.985 кг 1-3 дня
20019.00
✓ В корзине

Пример 18. События (консоль)

Постановка: подписаться на кастомные события добавления/удаления для аналитики или UI.

Вызов:

Вызов · JavaScript
document.addEventListener('ms3f:added', function (e) { console.log(e.detail); });
document.addEventListener('ms3f:removed', function (e) { console.log(e.detail); });

Пример 19. Callback onAdd

Постановка: выполнить свой JS после успешного добавления в избранное (без правки ядра коннектора).

Вызов: в конфиге после ms3fLexiconScript задать window.ms3fConfig.onAdd = function (id, list, resourceType) { … } (см. блок scripts в шаблоне).

Вызов · JavaScript
window.ms3fConfig = window.ms3fConfig || {};
window.ms3fConfig.onAdd = function (id, list, resourceType) {
    console.log('onAdd', id, list, resourceType);
};

Вверху задан onAdd(id, list, resourceType) — при добавлении смотрите консоль. Тосты при этом показываются (iziToast / MS3). Чтобы проверить режим без тостов: в консоли выполните window.ms3fConfig.showToast = false и снова нажмите кнопку.

Пример 20. Заметки к позициям в избранном

Постановка: пользователь оставляет текстовую заметку к товару в списке (до 500 символов). Работает при включённой настройке ms3favorites.comments_enabled; на странице /wishlist/ заметки выводятся в чанке tplFavoritesPageItem.

Документация: ms3Favorites — интеграция, раздел «Заметки к элементам».

Вызов · HTML: элемент с data-favorites-comment, data-product-id, data-list; ограничение длины — maxlength="500".

Вызов · HTML
<textarea
    data-favorites-comment
    data-product-id="{$product_id}"
    data-list="default"
    data-resource-type="products"
    maxlength="500"
    rows="3"
    class="form-control"
    placeholder="Заметка к позиции"></textarea>

Вызов · JavaScript: программное сохранение текста заметки.

Вызов · JavaScript
ms3Favorites.updateComment(productId, list, comment);

Коннектор: action update_comment (см. обзор компонента).

Сохранение с textarea на странице выполняет favorites.js (blur/отправка на сервер). Если comments_enabled выключено, разметку с data-favorites-comment в пакете обычно не выводят — проверяйте настройку в менеджере MODX. На этой тестовой странице поля заметок в списках примеров 9–19 и в серверных выводах скрыты стилями — остаётся только блок ниже.

Живая проверка (нужны избранное + comments_enabled)

Добавьте товар в список default, затем введите заметку и уйдите с поля — запрос уйдёт в коннектор.

Пример 21. Сниппет ms3FavoritesLists

Постановка: вывести именованные списки избранного с количеством элементов (ms3FavoritesLists).

Сниппет отдаёт одну строку на каждый именованный список (название + число позиций), а не карточки товаров. В выборку обычно попадают только списки, в которых есть элементы (пустые «Подарки» / «Планы» могут не показываться). Если с tplWrapper видна одна строка — проверьте чанк обёртки (плейсхолдер для всех строк, например [[+output]] в pdoTools); ниже живой вывод без tplWrapper и с явным limit = 0.

Вызов:

Вызов · Fenom
<div class="vstack gap-1">
{'!ms3FavoritesLists' | snippet : [
  'tpl' => 'tplMs3fListsRow',
  'limit' => 0,
  'sortby' => 'name',
  'sortdir' => 'ASC'
]}
</div>

<!-- Вариант с tplWrapper (в чанке обёртки — плейсхолдер [[+output]]): -->
{'!ms3FavoritesLists' | snippet : [
  'tpl' => 'tplMs3fListsRow',
  'tplWrapper' => 'tplMs3fListsWrapper',
  'limit' => 0,
  'sortby' => 'name',
  'sortdir' => 'ASC'
]}

<!-- Только имена и счётчики, без ms3f_ids: -->
{'!ms3FavoritesLists' | snippet : [
  'tpl' => 'tplMs3fListsRow',
  'withItems' => '0',
  'limit' => 0
]}

Живой вывод (без tplWrapper, limit = 0, сортировка по имени)

Тот же сниппет для resource_type = resources

Пример 22. Сниппет ms3FavoritesShare

Постановка: разметка страницы шаринга по токену из URL (/wishlist/share?token=…), а не кнопка «поделиться» из примера 14.

Вызов: в шаблоне ресурса share — документация ms3FavoritesShare. Без токена в URL сниппет должен вернуть текст из лексикона ms3favorites_share_not_found; если на странице пусто — проверьте лексикон и кэш. Ниже — вызов на этой странице и ссылка с заведомо неверным token для проверки разметки.

Вызов · Fenom
{'!ms3FavoritesShare' | snippet}

{'!ms3FavoritesShare' | snippet : [
  'tpl' => 'tplFavoritesItem',
  'emptyTpl' => 'tplFavoritesEmpty',
  'wrapperTpl' => 'tplFavoritesSharePage'
]}

Результат {'!ms3FavoritesShare' | snippet} здесь (без ?token= в адресе этой страницы):

Список не найден или срок действия ссылки истёк.

Если блок выше пустой — откройте страницу шаринга с токеном (валидным из «Скопировать ссылку») или с тестовой строкой:

Открыть /wishlist/share?token=invalid-token-demo