Skip to content

Быстрый старт ​

Эта страница — для работы только в шаблонах MODX. Ни IDE, ни git, ни контроллеров: установил, вызвал сниппет, подменил чанк.

Вывести товары ​

Поставьте пакет и напишите в шаблоне:

[[!pbProducts]]

Всё. На странице появятся выложенные товары в том порядке, в котором их расставил менеджер, — карточка с картинкой, названием, ценой, кнопкой «В корзину» и сердечком избранного.

Восклицательный знак обязателен: без него MODX закеширует вывод, и первый же покупатель, положивший товар в корзину, покажет своё состояние остальным.

Что нужно один раз настроить ​

Строго говоря — ничего. Свежая установка открывает витрину на /shop, кладёт в неё раздел «Демонстрация» с тремя товарами и включает один способ оплаты — офлайновый, «Наличными при получении». Заказ проходит целиком, оплату подтверждает менеджер в гриде платежей.

Дальше это меняют под себя:

НастройкаЗачем менять
pbshop_route_prefixПрефикс каталога, по умолчанию shop. Пустое значение выключает витрину целиком. Если на сайте уже есть страница /shop, витрина её перекроет — смените префикс
pbshop_currencyВалюта по умолчанию. Товар без цены в этой валюте карточка печатает без цены — это не то же самое, что «ноль»
pbshop_catalog_limitСколько товаров на странице каталога и раздела, по умолчанию двенадцать. Ноль — все разом. На сниппеты не влияет: у них свой &limit
Способы оплатыОстальные четырнадцать приезжают выключенными, и это не недоделка: включённый эквайер с чужими ключами уводит деньги на чужой shop_id. Включайте тот, по которому есть договор
Раздел «Демонстрация»Удалите его вместе с товарами, когда заведёте свои. Все псевдонимы начинаются с demo-

Товары, категории, опции и варианты заводятся в разделе pbShop в менеджере — конструктор полей приходит из PageBlocks, поэтому своё поле добавляется мышкой и никаких колонок под него не нужно.

Пять сниппетов ​

[[!pbProducts]]                      товары каталога
[[!pbProduct? &id=`mug-logo`]]       один товар карточкой
[[!pbCategories]]                    разделы каталога
[[!pbCart]]                          корзина: состав, скидка, итог
[[!pbOrder? &uuid=`…`]]              заказ карточкой

pbProducts, pbCategories и pbCart работают без параметров: первый печатает выложенные товары, второй — корни каталога, то есть сам каталог (&parent спускает на уровень ниже), третий — корзину того, кто пришёл.

pbProduct и pbOrder без параметра обойтись не могут и не делают вид, что могут: угадать, какой товар или чей заказ вы имели в виду, нечем. Вызов без &id и без &uuid печатает, чего не хватает, — «Укажите товар: &id=псевдоним или &id=12».

Корзина и заказ — только некешированным вызовом

И не работают при включённом pageblocks_http_cache: кеш ответов ключуется адресом без cookie, поэтому напечатанный в разметку состав одного покупателя достался бы остальным. Сниппет в этом случае отказывается вслух и объясняет, что делать, — молчаливая пустая корзина выглядела бы пустой корзиной.

Поменять разметку ​

Два способа, и первый обычно достаточен.

Править дефолтный чанк ​

При установке компонент заводит свои чанки обычными записями в дереве менеджера, в категории pbShop:

ЧанкЧто печатает
pbShop.cardкарточка товара в списке — её же берёт pbProduct
pbShop.listобёртка списка товаров и категорий
pbShop.categoryCardраздел в списке
pbShop.cartRowстрока корзины
pbShop.cartRowsобёртка корзины с итогом и скидкой
pbShop.orderCardкарточка заказа

Откройте, поправьте, сохраните — изменения видны на витрине сразу. Обновление компонента не затрёт вашу правку: при установке сохраняется хеш поставленного содержимого, и перезаписывается только то, чего никто не касался. Если правили — в лог уйдёт строка «дефолтный чанк обновлён, ваш изменён», а ваш останется как есть.

Отдельно лежат чанки страниц витрины: pbShop.catalog, pbShop.category, pbShop.product, pbShop.cart, pbShop.order, pbShop.layout и другие. Они нужны, если вы правите не карточку, а страницу целиком.

Галочка «статичный» требует системной настройки MODX

Поле «Статичный файл» у наших чанков заполнено сразу — поставив галочку, вы забираете чанк себе файлом под git. Но MODX запишет файл только если в static_elements_allowed_extensions разрешено расширение tpl. Пустая настройка означает «ни одного статичного элемента»: источник объявляется немутабельным, и менеджер ответит ошибкой поля. Проверено на стенде 01.10.2026 — настройка там пуста, и файл не создался ни из менеджера, ни из API.

Указать свой чанк в вызове ​

[[!pbProducts? &tpl=`myCard`]]

Значение &tpl понимает четыре формы — те же, к которым аудитория MODX привыкла:

card                     чанк из базы
file:chunks/card         файл из pageblocks_elements_path
@FILE chunks/card        то же самое, привычка пользователей pdoTools
@INLINE <b>{$title}</b>  инлайн

Отката между источниками нет

Указали file: — ищется только файл. Не нашли — в разметке появится понятная надпись, а не тихий поиск того же имени в базе: неявный откат делает поведение недетерминированным и неотлаживаемым.

Чего в вызове нет и не будет: отдельного параметра пути (customPath и подобных). Источник указывается внутри значения — иначе &tpl и &tplWrapper в одном вызове не смогли бы брать шаблоны из разных мест.

Что доступно в карточке ​

pbShop.card получает плоский набор — модель в чанк не приезжает намеренно, иначе верстальщику пришлось бы знать про валюты и про то, что у составного товара своя цена служебная:

ПлейсхолдерЧто внутри
{$title}название
{$url}адрес карточки; пусто, если витрина выключена
{$image}путь к картинке как его сохранил менеджер. Уменьшает её блок image.tpl через Glide: {include 'file:image' src=$image alt=$title w=400 h=400}
{$formatted}цена строкой, у составного товара — «от 1990 ₽». Пусто значит «в этой валюте не продаётся»
{$old_formatted}старая цена для зачёркивания. Пусто, если скидки нет: сравнение с текущей ценой делает товар, шаблону остаётся напечатать непустое
{$alias}псевдоним, он же ключ для кнопок «в корзину» и «в избранное»
{$product_id}идентификатор
{$in_stock}есть ли что отгружать
{$variable}составной ли товар: у такого выбирают вариант на карточке, а не кладут в корзину из списка
{$idx}, {$first}, {$last}номер строки и её края — для «каждый третий в ряд»

Картинки ​

Товар, раздел и вариант хранят путь к картинке (image), а уменьшает её Glide из PageBlocks — своей обвязки компонент не держит. В шаблонах это общий блок:

{include 'file:image' src=$image alt=$title w=400 h=400}
{include 'file:image' src=$product->image alt=$product->title w=800 h=800 crop=0}

Он отдаёт webp запрошенного размера (q=82) с width/height в атрибутах и loading="lazy". Размеры в атрибутах не украшение: без них браузер не знает высоту до загрузки, и список прыгает под курсором ровно тогда, когда покупатель целится в карточку. crop=0 — вписать целиком вместо обрезки по центру.

У товара без картинки печатается рамка той же пропорции с надписью «Нет фото». Не пустота: карточка без рамки встаёт выше соседей, и ряд в сетке разъезжается.

Поставочные демо-товары идут без фотографий

Три товара раздела «Демонстрация» показывают заглушку — стоковых картинок компонент не везёт: это лишний вес пакета и чужая лицензия в вашем магазине. Добавьте свои, и уменьшение заработает само.

Битый файл не ломает страницу, но и не чинится сам

Нет файла по пути, нулевой файл, HEIC под именем .jpg — Glide пишет одну строку в лог и возвращает исходный адрес. Страница цела, картинка не уменьшена: смотрите журнал MODX, там сказано, что именно с файлом.

Параметры ​

Одни и те же у всех списков. Выучив их здесь, вы напишете вызов любого другого сниппета линейки, не открывая документацию.

ПараметрСмысл
&tplчанк элемента; не указан — дефолтный чанк компонента
&tplWrapperчанк обёртки; 0 — без обёртки
&tplEmptyчанк для пустого списка; не указан — пустой вывод
&limitсколько выводить; 0 — все
&offsetсколько пропустить
&pageномер страницы вместо смещения
&sortименованный набор витрины: cheap, expensive, new, name. Незнакомое значение — обычный порядок, а не отказ
&sortbyпо какому полю сортировать; несколько — через запятую
&sortdirasc или desc
&whereдополнительные условия, JSON
&parentраздел: псевдоним или id
&outputSeparatorразделитель между строками
&toPlaceholderположить вывод в плейсхолдер вместо печати на месте
&showLogотладка; печатается только вошедшему в менеджер

У pbProduct вместо раздела — &id (псевдоним или число), у pbOrder — &uuid.

Порядок на самих страницах каталога и раздела — те же наборы в адресе: ?sort=cheap. Ряд ссылок печатает блок sorting.tpl, данные приходят в $sorting. Отсортированная страница закрыта <meta robots="noindex,follow"> — это те же товары, переставленные местами, то есть дубль раздела; постраничность при этом открыта, вторая страница несёт другие товары.

Сортировать можно только по колонкам таблицы

Поле, добавленное конструктором, живёт в JSON-колонке, и сортировка по нему не сортирует, а валится ошибкой SQL. Поэтому &sortby с таким полем отвечает отказом до запроса и перечисляет, по чему можно: id, alias, title, price, old_price, stock, weight, menuindex, published_at, created_at, updated_at.

Когда что-то не вышло ​

Сниппет не молчит. Опечатались в имени чанка — на месте вызова появится «Чанк «myCard» не найден»; в имени раздела — «Раздел «mugs» не найден»; в &where — что именно не разобралось в JSON. Пустой вывод означает ровно одно: выводить нечего.

Имя настройки в надпись не попадает — оно уходит в лог MODX: покупателю знать внутреннее устройство магазина незачем.

Дальше ​

  • Разработчику — если понадобится своя страница с данными из магазина мимо сниппетов. Один и тот же проект спокойно живёт и так, и так.

pbShop — магазин для сайтов на PageBlocks