Помощник $shop: списки магазина
Категории, страницы, подборки товаров, бренды, метки, отзывы и корзина — прямо из шаблона, без подготовки данных.
На этой странице
$shop — помощник, который есть в каждом шаблоне. Через него тема берёт то, что
ей нужно, не дожидаясь, пока данные передадут: категории для меню, подборки
товаров на главную, бренды, метки, отзывы, состояние корзины.
Помощник живёт один на запрос и запоминает результаты — повторный вызов с теми
же параметрами в базу не ходит. Звать {$shop->categories()} в шапке, в меню
каталога и в плитках на главной не накладно.
Сводка
| Метод | Что отдаёт |
|---|---|
contacts() |
контакты магазина |
locales() |
языки витрины со ссылками на текущую страницу |
categories($parentId, $depth, $media) |
дерево категорий |
pages($parentId) |
меню страниц, созданных владельцем |
products($code, $preset, $limit, $sort) |
карточки товаров подборки |
tags($limit) |
метки каталога |
brands($limit) |
бренды с логотипами |
reviews($limit) |
последние одобренные отзывы |
accessories($productId) |
группы аксессуаров товара |
cartCount() |
число позиций в корзине |
cartTotal() |
сумма корзины |
cartPath() |
куда ведёт значок корзины |
isOnepageCheckout() |
включено ли оформление в один шаг |
favoritesCount() |
число товаров в избранном |
compareCount() |
число товаров в сравнении |
inCart() |
что уже лежит в корзине |
cartItem($productId, $skuId) |
позиция корзины с этим товаром |
inCartQty($productId, $skuId) |
сколько этого товара в корзине |
cardVariantsEnabled() |
показывает ли тема варианты покупки на карточках |
Категории
{$shop->categories()} верхний уровень
{$shop->categories(null, 2)} два уровня
{$shop->categories(null, 2, true)} два уровня, с картинками
{$shop->categories($category.id, 1)} подкатегории текущей
| Параметр | По умолчанию | Что задаёт |
|---|---|---|
parentId |
пусто | корень поддерева; пусто — верхний уровень |
depth |
1 |
на сколько уровней вглубь |
media |
нет | добавить ли картинки |
Поля узла: id, name, initial (первая буква — для плитки без картинки),
slug, url, children. С media добавляются logo, icon, cover — либо
адрес файла, либо пусто.
{foreach $shop->categories(null, 2, true) as $cat}
<a href="{$cat.url}">
{if $cat.icon}<img src="{$cat.icon}" alt="">{/if}
{$cat.name}
</a>
{foreach $cat.children as $sub}
<a href="{$sub.url}">{$sub.name}</a>
{/foreach}
{/foreach}
Выключенные категории не приходят.
Информационные страницы
{foreach $shop->pages() as $page}
<a href="{$page.url}">{$page.title}</a>
{/foreach}
Поля: id, slug, title, url. Выключенные не приходят, порядок — как задан
в панели. Страниц нет — пустой список.
Подборки товаров
Два способа получить список товаров на главную.
По коду подборки, заведённой владельцем:
{$shop->products('new-arrivals', null, 12)}
Код задаётся в панели, в разделе подборок. Подборки с таким кодом нет или она выключена — пустой список. Это основной способ: владелец сам решает, что показывать, не трогая шаблон.
По готовому набору правил:
{$shop->products(null, 'discount', 8)}
| Набор | Что отбирает |
|---|---|
new |
добавленные за последние 30 дней |
discount |
только со скидкой |
low_stock |
остаток от 1 до 5 |
random |
случайные |
bestsellers |
по продажам |
popular |
по просмотрам |
top_rated |
по оценкам |
Неизвестное имя молча превращается в new.
⚠️ Честно про три последних: bestsellers, popular и top_rated сейчас
сортируют по новизне. Товары придут правильные, порядок — как у новинок.
Сортировка по продажам, просмотрам и оценкам объявлена, но пока не сделана.
Возвращаются полные карточки товара — тот же набор полей, что у товаров категории. Он описан на странице Данные товара.
Метки и бренды
{foreach $shop->tags(20) as $tag}<a href="{$tag.url}">{$tag.name}</a>{/foreach}
{foreach $shop->brands(30) as $brand}
<a href="{$brand.url}">
{if $brand.logo}<img src="{$brand.logo}" alt="{$brand.name}">{else}{$brand.name}{/if}
</a>
{/foreach}
Метки: id, slug, name, url, по алфавиту. Бренды: то же плюс logo.
Логотип берётся уменьшенным, при отсутствии уменьшенной копии — оригинал. По
умолчанию — 50 штук.
Отзывы
{foreach $shop->reviews(6) as $r}
<blockquote>
<p>{$r.text}</p>
<cite>{$r.name}, <a href="{$r.product_url}">{$r.product}</a>, {$r.date}</cite>
</blockquote>
{/foreach}
Последние одобренные отзывы о товарах — для блока на главной. Поля: name,
initial, product, product_url (ведёт на #, если товар удалён), rating,
text, date в формате дд.мм.
Аксессуары
{foreach $shop->accessories($product.id) as $group}
<h3>{$group.title}</h3>
{foreach $group.items as $item}
<label>
<input type="checkbox" value="{$item.sku_id}">
<img src="{$item.image}" alt="">
{$item.name}
{money amount=$item.final_price currency=$storefront.currency}
</label>
{/foreach}
{/foreach}
Группа: id, title, multiple (можно выбрать несколько), items. Аксессуар:
product_id, sku_id, name, url, image, in_stock, is_available,
discount (процент группы), price, final_price (со скидкой группы),
compare_price, default_quantity, unit, qty_step, qty_min, is_default.
Аксессуары выключены в настройках — пустой список. Группа, в которой не осталось ни одного доступного товара, не приходит вовсе.
На странице товара то же самое уже лежит в $product.accessories — отдельно
звать не нужно. И помните: живой пересчёт комплекта делает сам магазин, тема
только размечает блок — см. Атрибуты data-*.
Языки
{foreach $shop->locales() as $l}
<a href="{$l.url}"{if $l.active} class="is-active"{/if}>{$l.short}</a>
{/foreach}
Поля: code (ru), prefix (uk или ua — задаётся в справочнике языков),
name (название на родном языке), short (префикс заглавными), active, url.
url — путь текущей страницы на этом языке, а не полный адрес:
переключатель обязан остаться на том домене, по которому покупатель зашёл.
Корзина
<a href="{$shop->cartPath()}">
Корзина
<span data-badge="cart">{$shop->cartCount()}</span>
<span data-cart-total-header>{money amount=$shop->cartTotal() currency=$storefront.currency precision=0}</span>
</a>
cartPath() отдаёт /checkout, если у витрины включено оформление в один шаг,
иначе /cart — значок корзины должен вести туда, куда владелец настроил.
cartTotal() берёт готовый итог корзины, а не складывает позиции: своя
формула в шапке разъедется со страницей корзины и с оформлением. Корзины ещё
нет — ноль.
favoritesCount() и compareCount() — то же самое для избранного и сравнения.
Все четыре дёшевы, зовите откуда угодно.
Что уже в корзине
inCart(), cartItem(), inCartQty() отвечают, лежит ли товар в корзине.
Позиция: item_id, product_id, sku_id, qty, qty_text, unit, packs,
lines. Товар лежит несколькими вариантами — количества складываются, а
item_id, sku_id и packs приходят пустыми: позиция уже не одна.
⚠️ Обычный путь другой. Эти методы помечают страницу как личную и выключают для неё общий кэш витрины: страница перестаёт отдаваться из кэша и собирается заново каждому покупателю.
Штатный способ показать «уже в корзине» — атрибут на карточке:
<article class="card" data-in-cart="{$product.id}">
…
<span class="card__in-cart">
В корзине <b data-in-cart-qty></b> <span data-in-cart-unit></span>
</span>
</article>
Количество проставит магазин уже в браузере, и страница останется кэшируемой. Подробности — на странице Атрибуты data-*.
Варианты покупки на карточках
cardVariantsEnabled() читает настройку темы card_variants — показывать ли
выбор цвета и размера прямо в списке товаров.
⚠️ Настройка обязана быть объявлена в theme.json. У базовой темы её нет,
поэтому базовая тема варианты на карточках не показывает. Пока поля нет в схеме,
магазин не тратит запросы на подготовку вариантов — и правка шаблона ничего не
изменит. Как объявить поле, написано на странице
Файл theme.json.
Чего у $shop нет
Помощник отдаёт списки и состояние, а не всё подряд. Заказов покупателя, произвольной выборки товаров по своим условиям, чужих сущностей магазина в нём нет — и обойти это, обратившись из шаблона к базе, нельзя: шаблон работает в песочнице.
Если теме нужны данные, которых у $shop нет, — это задача дополнения. Оно
считает своё и выводит через точку встраивания или
собственный тег.