Установить и вызвать
Эта страница — для вёрстки: PHP здесь не нужен. Всё, что ниже, пишется в шаблоне MODX и в чанках.
Установка
- Поставьте PageBlocks alfa24 или новее — без него компонент выключится с записью в лог.
- Поставьте пакет pbFavorites через «Установщик».
- Проверьте журнал установки: миграция создаёт таблицу
pb_favoritesи пишет об этом строкой.
Миграции идут отдельным шагом
Если на хостинге отключена функция exec(), резолвер честно скажет об этом в журнале и подскажет команду. Таблицу тогда нужно создать руками:
php core/components/pageblocks/vendor/bin/phinx migrate \
--configuration=core/components/pbfavorites/src/phinx.php --environment=productionЧто должно быть установлено ещё
Сам по себе пакет ничего не покажет, и это не недоработка: он не знает ни одной модели, пока её кто-нибудь не зарегистрирует. Регистрируют спутники:
- pbShop с
alfa44регистрируетpbshop.productи больше ничего не требует; - свою модель регистрирует сайт — одной строкой, см. раздел разработчика.
Если закладки «не работают», первым делом посмотрите, что печатает кнопка: при незнакомой модели она отвечает текстом с перечислением известных ключей, а не молчит.
Кнопка в карточке
[[!pbFavoriteButton? &model=`pbshop.product` &id=`[[+id]]`]]&model и &id обязательны. Кнопка сама знает своё состояние («отложить» или «отложено») и сама меняет подпись после нажатия.
Только некешируемым вызовом
[[! с восклицательным знаком — обязательно, во всех трёх сниппетах. Состояние закладок персональное; кешированный тег отдал бы список первого посетителя всем остальным.
Со счётчиком «сколько человек отложило»:
[[!pbFavoriteButton? &model=`pbshop.product` &id=`[[+id]]` &watchers=`1`]]Без &watchers счётчик не считается вовсе — лишний запрос на каждую карточку нужен не всякой витрине.
Счётчик в шапке
[[!pbFavoritesCount]]Без &tpl возвращает одно число, без разметки: счётчик обычно печатают внутрь своего элемента, и обёртка вокруг него мешала бы.
<a class="header-wish" href="/favorites">
Избранное <span>[[!pbFavoritesCount]]</span>
</a>Считаются видимые закладки: снятое с показа в списке не печатается, и число над ним обещало бы то, чего человек не увидит.
Только товары — [[!pbFavoritesCount? &model=pbshop.product]].
Страница списка
Создайте ресурс (например, с алиасом favorites) и позовите в нём:
[[!pbFavorites]]Без &model печатаются все закладки посетителя: у блога и магазина на одном сайте список один. Только товары:
[[!pbFavorites? &model=`pbshop.product` &tpl=`myFavoriteRow`]]Страницу держит сайт, а не компонент
Своего адреса у списка нет намеренно. Закладывают на таком сайте и статьи тоже, поэтому адрес вида «/каталог/favorites» обещал бы, что это раздел магазина. Ресурс и его адрес — ваши.
Параметры
Словарь общий для всех трёх сниппетов и совпадает с pbShop.
| Параметр | Что делает |
|---|---|
&model | ключ модели (pbshop.product). Без него — все закладки |
&id | id объекта. Только pbFavoriteButton, обязателен |
&tpl | чанк строки. У pbFavoritesCount его отсутствие значит «отдай числом» |
&tplWrapper | чанк обёртки списка; внутри доступны {$output} и {$total} |
&tplEmpty | чанк пустого списка |
&limit, &offset | срез списка. &limit=0 — без ограничения |
&sortby, &sortdir | порядок по полю строки; по умолчанию — последнее отложенное сверху |
&outputSeparator | чем склеить строки |
&toPlaceholder | вывод в плейсхолдер, сниппет возвращает пустоту |
&showLog | показать журнал вызова (видно только вошедшему в менеджер) |
&watchers | считать «сколько человек отложило». Только pbFavoriteButton |
¤cy | валюта строк. Передаётся поставщику насквозь |
Опечатка не молчит
Незнакомый &model, пропущенный &id, несуществующее поле в &sortby — всё это печатается текстом в точке вызова и уходит в &showLog. Пустой список и опечатка на витрине выглядят одинаково, поэтому компонент их различает за вас.
То же самое есть и в коде
&limit, &offset, &sortby и &sortdir считает сервис, а не сниппет — поэтому разработчик рядом с вами получает их тем же вызовом $favorites->all($model, [], ['limit' => 20]). Это не мелочь для смешанного проекта: возможность, которая есть только в шаблоне, однажды приходится переписывать заново.
Готовый раздел «Избранное»
Копируется целиком. Три сниппета, свой чанк строки, скрипт — дальше правится только разметка.
1. Ресурс с алиасом favorites и таким содержимым:
[[!pbFavorites? &tpl=`myFavoriteRow`]]2. Чанк myFavoriteRow — за основу берётся поставочный pbFavorites.row.tpl. ⚠️ Чанки компонента рисует Fenom, поэтому поля пишутся {$item.title}, а не [[+title]]:
<div class="card" data-pbfav-row data-model="{$item.model}" data-id="{$item.item_id}">
<a href="{$item.url}"><img src="{$item.image}" alt="{$item.title}"></a>
<a class="card-title" href="{$item.url}">{$item.title}</a>
{if $item.formatted}<span class="card-price">{$item.formatted}</span>{/if}
<button type="button" class="card-remove"
data-pbfav-toggle="{$item.model}" data-pbfav-id="{$item.item_id}" aria-pressed="true">
{'pbfav_remove'|lexicon}
</button>
</div>3. Ссылка в шапке — в общем шаблоне сайта:
<a href="/favorites">Избранное <span>[[!pbFavoritesCount]]</span></a>4. Кнопка в карточке каталога — туда, где выводится товар:
[[!pbFavoriteButton? &model=`pbshop.product` &id=`[[+id]]`]]5. Скрипт и токен — один раз в шаблоне, см. раздел «Подключить скрипт» ниже.
Строка списка — от поставщика
{$item.formatted} и {$item.image} даёт поставщик товаров pbShop. У своей модели поля будут другие, и их список знает тот, кто писал поставщика.
Своя разметка
Цепочка такая: &tpl → чанк в дереве менеджера → файл поставки.
Записи при установке не заводятся. Чтобы перебить разметку, создайте чанк с нужным именем — обновление пакета его не тронет, потому что записей он не трогает вовсе:
| Чанк и файл | Что рисует |
|---|---|
pbFavorites.row | строку списка |
pbFavorites.list | обёртку списка |
pbFavorites.empty | пустой список |
pbFavorites.button | кнопку |
pbFavorites.count | счётчик (когда позван с &tpl) |
В дереве менеджера этих чанков нет
И это осознанная цена, а не недоработка: пакет ставится без резолвера элементов, поэтому записи не заводятся — и найти поставочную разметку, листая дерево, нельзя. Имена берите из таблицы выше.
Файлы лежат в core/components/pbfavorites/elements/chunks/ и названы так же, как записи: pbFavorites.row.tpl, pbFavorites.list.tpl и так далее. Самый короткий путь — скопировать файл, создать чанк с тем же именем, править его.
Чанки рисует Fenom, а не парсер MODX: внутри пишется {$item.title}, а не [[+title]]. Полное имя файлового шаблона — file:pbFavorites:pbFavorites.row, но писать его в &tpl обычно незачем: без параметра дефолт находится сам.
Что доступно в строке
Строку собирает поставщик, поэтому набор полей зависит от модели. Пакет добавляет к ним свои два:
| Поле | Откуда |
|---|---|
{$item.model} | пакет: ключ модели |
{$item.item_id} | пакет: id объекта |
{$item.title}, {$item.url}, {$item.image}, {$item.formatted} | поставщик товара pbShop |
Поля берите мягко — чего поставщик не дал, то не печатается:
{if $item.formatted}<span class="price">{$item.formatted}</span>{/if}Что нужно скрипту
Скрипт пакета (assets/components/pbfavorites/js/favorites.js) ищет в разметке атрибуты. Если пишете свои чанки, сохраните их:
| Атрибут | На чём | Зачем |
|---|---|---|
data-pbfav-toggle="<модель>" + data-pbfav-id | кнопка | по нажатию переключает |
data-pbfav-label-add, data-pbfav-label-in | кнопка | подписи состояний; без них скрипт не меняет текст |
data-pbfav-count | любой элемент | обновляется числом |
data-pbfav-row | строка списка | убранная строка исчезает |
data-pbfav-clear | кнопка | очистка, в два нажатия |
data-pbfav-confirm | та же кнопка | подпись подтверждения |
data-pbfav-error | любой элемент | куда напечатать отказ сервера |
Разметку скрипт не собирает
Новые строки в списке не появляются без перезагрузки, и это решение: собирай их скрипт, вёрстка жила бы в двух местах — в чанке и в JS, — и правка чанка молча не доезжала бы до перерисованного списка. Закладку ставят в каталоге, а смотрят в списке; эти два места редко открыты одновременно.
Подключить скрипт
Пакет не вставляет себя в страницу: чужой шаблон — не его дело. Добавьте в свой шаблон:
<script src="/assets/components/pbfavorites/js/favorites.js" defer></script>И токен — запросы пакета идут POST'ом, PageBlocks их проверяет. В файловом шаблоне на Fenom это одна строка в <head>:
{meta_csrf}Скрипт ищет токен в meta[name="csrf-token"], а если его нет — в input[name="_token"] на странице. Так что в шаблоне MODX, где функции Fenom недоступны, достаточно, чтобы на странице была любая форма PageBlocks с её скрытым полем токена.
Без токена кнопка «просто не работает»
Запрос уйдёт и вернётся отказом, а на витрине это выглядит как сломанная кнопка. Если нажатие ничего не делает — посмотрите в консоли ответ /favorites/toggle первым делом.
Без скрипта
Кнопка без JS не работает — она шлёт запрос. Если скрипт не нужен, список всё равно печатается сниппетом: страница с [[!pbFavorites]] показывает отложенное и без единой строки JavaScript.