
Чанки и разметка
Форму фильтров и обёртку результатов выводят чанки. Их можно заменить своими: скрипт mFilter продолжит работать, пока в разметке есть атрибуты и классы из контракта разметки.
Чанки формы
Сниппет mFilterForm собирает форму из шести чанков:
| Параметр | Чанк по умолчанию | Что выводит |
|---|---|---|
tplOuter | mfilter.form | Обёртку формы: тег <form> и кнопки |
tpl | mfilter.filter | Блок одного фильтра: название, счётчик выбранных, значения |
tplItem | mfilter.item | Одно значение списка — флажок, а если в фильтре выбирается одно значение, переключатель radio |
tplSlider | mfilter.slider | Диапазон фильтра типа number: два поля и ползунок |
tplColor | mfilter.color | Одно значение фильтра типа colors |
tplBoolean | mfilter.boolean | Одно значение фильтра типа boolean |
Переменные каждого чанка и стандартная разметка — на странице сниппета mFilterForm.
После фильтрации чанки формы не перерисовываются: счётчики, недоступные значения и ползунки меняет скрипт по контракту разметки. Правка в чанке видна после перезагрузки страницы.
Чанки результатов
Сниппет mFilter выводит результаты тремя чанками:
| Параметр | Чанк по умолчанию | Что выводит |
|---|---|---|
tplOuter | mfilter.outer | Обёртку результатов с атрибутами для скрипта |
tpl | mfilter.row | Одну строку результата |
tplPagination | mfilter.pagination | Пагинацию |
Переменные — в Плейсхолдерах и Пагинации. После фильтрации обёртка не перерисовывается: с сервера заново приходят строки и пагинация.
Свой чанк
{'!mFilterForm' | snippet : [
'tpl' => '@FILE chunks/mfilter/filter.tpl',
'tplItem' => '@FILE chunks/mfilter/item.tpl'
]}Путь @FILE отсчитывается от каталога файловых элементов pdoTools, по умолчанию core/elements/: чанки из примера лежат в core/elements/chunks/mfilter/. Начните с копии стандартного чанка из core/components/mfilter/elements/chunks/.
Короткий чанк можно задать прямо в вызове:
{'!mFilterForm' | snippet : [
'tpl' => '@INLINE <div data-filter-key="{$key | esc}"><b data-filter-label="{$label | esc}">{$label | esc}</b>{$items}</div>'
]}Контракт разметки
Контракт — это data-атрибуты и классы mfilter-*, по которым скрипт находит элементы, и экранирование значений. Атрибуты и классы — не оформление: в своих чанках сохраняйте их, а свои классы добавляйте рядом.
Обязательные точки подключения
| Атрибут | На каком элементе | Зачем |
|---|---|---|
data-mfilter | корень формы | Инициализация формы. Его и остальные атрибуты формы выводит {$formAttrs} — в своей обёртке формы пишите <form{$formAttrs}> |
data-mfilter-results | обёртка результатов | Носитель метаданных (hash, total, page-count) и область, к которой привязываются клики пагинации |
data-mfilter-hash | обёртка результатов | Через него сервер находит параметры вызова сниппета |
data-base-url | корень формы | База для сборки SEO-адреса. На форму его выводит {$formAttrs}; тот же атрибут на обёртке результатов — запасной источник |
data-page-count, data-total | обёртка результатов | Начальное состояние пагинации |
data-mfilter-keys | обёртка результатов | Список ключей фильтров страницы. По нему скрипт отличает свои URL-параметры от чужих (utm_*, gclid) |
mfilter-results (класс) | контейнер внутри обёртки | Куда вставляется HTML результатов при AJAX |
mfilter-pagination (класс) | контейнер пагинации | Куда вставляется HTML пагинации. Ссылки внутри — a[data-page] или a.page-link: по ним скрипт переходит по страницам без перезагрузки |
{* Обёртка результатов — tplOuter сниппета mFilter *}
<div data-mfilter-results
data-mfilter-hash="{$hash}"
data-mfilter-keys="{$filterKeys | esc}"
data-base-url="/{$_modx->resource.uri | esc}"
data-page-count="{$pageCount}"
data-total="{$total}">
{* Сюда вставляется HTML результатов при AJAX *}
<div class="mfilter-results">{$rows}</div>
{* Контейнер выводится всегда, даже пустым *}
<div class="mfilter-pagination">{$pagination}</div>
</div>Обёртка, контейнер и форма — разные элементы
data-mfilter-results держит метаданные, а разметка подменяется во вложенном .mfilter-results. Если оставить только атрибут, результаты обновляться не будут.
На форму data-mfilter-results не ставьте: скрипт сочтёт её обёрткой результатов, и ссылки пагинации перестанут работать через AJAX.
Контейнер пагинации выводите без условия: скрипт вставляет пагинацию только в существующий элемент. Если страница открылась с одной страницей результатов и контейнера нет, после фильтрации ссылки на страницы не появятся.
Без data-mfilter-hash страница не фильтрует
По хешу сервер находит параметры вызова mFilter: элемент, чанки, limit, parents, depth, where. Без атрибута страница не отправляет AJAX-запросы: фильтры, сортировка, лимит, «Показать ещё» и сброс не срабатывают, а в консоли браузера появляется ошибка с подсказкой, что добавить. Ссылки пагинации работают обычным переходом.
Атрибут выводится в tplOuter сниппета mFilter (в чанке доступна переменная {$hash}). Стандартный mfilter.outer его содержит; в свой чанк нужно добавить вручную. Сниппет mFilterForm хеш в свои чанки не передаёт.
Ошибка 410 при атрибуте на месте
Сервер не нашёл параметры по хешу. Так бывает, когда страница две недели и дольше отдавалась из кэша MODX без единой фильтрации, а потом кэш mFilter очистили полностью. В журнале ошибок MODX при этом есть строка [mFilter] Snippet config … not found. Очистите кэш сайта — страница отрисуется заново со свежим хешем.
Зачем data-mfilter-keys
Без атрибута — например, в старой копии чанка — скрипт отличает свои URL-параметры от чужих по полям формы, а если формы нет, принимает все. Фильтр, скрытый параметром min_values фильтра категорий или отрисованный вне формы, поля не имеет, и его значение из URL теряется при первой же AJAX-фильтрации.
Обязательные классы-хуки
| Класс | Где | Что делает скрипт |
|---|---|---|
mfilter-item | обёртка одного значения | Внутри неё ищет счётчик и ставит на неё mfilter-item-empty, когда значение стало недоступным |
mfilter-count | элемент со счётчиком | Пишет сюда пересчитанное количество |
mfilter-range | обёртка диапазона | Следит за полями и ползунком — см. Диапазон |
Свои классы добавляются рядом:
<div class="filter-checkbox mfilter-item">
<input type="checkbox" name="{$key | esc}[]" value="{$value | esc}"{if $active} checked{/if}>
<label>
{$label | esc}
<span class="filter-count mfilter-count">{$count}</span>
</label>
</div>Без mfilter-count счётчики после фильтрации не обновляются. Без mfilter-item скрипт находит счётчик рядом с полем, но не помечает недоступные значения. Ошибок в консоли в обоих случаях нет.
Диапазон
| Элемент | Разметка |
|---|---|
| Обёртка | .mfilter-range с data-filter-key="{$key}" |
| Поля | name="{$key}|min" и name="{$key}|max" с data-range="min" и data-range="max" |
| Ползунок | [data-mfilter-slider] с data-key, data-min, data-max — в том же родителе, что и поля |
Границы уходят в запрос, только если посетитель двигал ползунок или правил поле. Остальные настройки ползунка — в Слайдере диапазона.
Блок фильтра и кнопка сброса
| Атрибут | Где | Зачем |
|---|---|---|
data-filter-key | блок фильтра | По нему скрипт пересчитывает счётчик выбранных. Блок «Выбрано», когда его рисует скрипт, а не сервер, находит по нему название фильтра |
data-filter-badge | внутри блока | Счётчик выбранных значений. При нуле скрипт ставит на него класс d-none |
data-mfilter-reset или класс mfilter-reset-btn | кнопка сброса внутри формы | Сбрасывает фильтры; кнопка видна только при выбранных фильтрах. Число в кнопке — [data-mfilter-reset-count]. Кнопку вне формы подключайте через JS API — см. mFilterForm |
Классы, которые скрипт ставит сам
| Класс | Когда |
|---|---|
mfilter-loading | На корне формы во время запроса. Поля, списки и кнопки формы при этом получают disabled |
mfilter-item-empty | На .mfilter-item, когда количество стало нулевым |
active | На .mfilter-overlay во время запроса; на кнопке или ссылке выбранной сортировки и лимита |
Стандартный mfilter.css делает значения с mfilter-item-empty полупрозрачными, а их поля — недоступными для клика. Своё правило нужно, если стили компонента не подключены или переопределены:
.mfilter-item-empty {
opacity: .5;
}
.mfilter-item-empty input {
pointer-events: none;
}Необязательные атрибуты и классы
| Атрибут или класс | Назначение |
|---|---|
data-mfilter-sort | Управление сортировкой: <select> без значения либо <button>/<a> со значением в самом атрибуте |
data-mfilter-limit | Число товаров на странице — так же, как сортировка: <select> либо <button>/<a> со значением в атрибуте |
data-mfilter-tpl | Переключатель вида: значение — ключ из параметра tpls сниппета mFilter |
data-mfilter-load-more | Кнопка «Показать ещё» в режиме data-mfilter-pagination-mode="loadmore": скрипт прячет её на последней странице. Нажатие подключайте сами — mfilterGet().loadMore() |
data-mfilter-pagination | На корне формы: переопределяет селектор контейнера пагинации (по умолчанию .mfilter-pagination). Это не сам контейнер |
data-mfilter-selected | Блок «Выбрано». Обязательная разметка его чанков — в mFilterSelected |
data-mfilter-h1, data-mfilter-seo-text | Обновление SEO-блоков при AJAX. То же делают классы h1.mfilter-h1 и .mfilter-seo-text |
mfilter-total | Число найденных: скрипт обновляет его после фильтрации |
mfilter-empty | Блок «ничего не найдено»: скрипт показывает его при нуле результатов и прячет в остальных случаях |
mfilter-item-label или mfilter-label, data-filter-label | Подписи значения и фильтра для блока «Выбрано», когда его рисует скрипт, а не сервер |
data-mfilter-url-separator, data-mfilter-values-separator | Разделители SEO-адреса. Сниппет выводит их на форму из настроек |
Остальные настройки скрипта задаются атрибутами формы — см. Настройки формы.
Экранирование значений
Всё, что приходит из данных, выводите через модификатор esc: {$pagetitle | esc}. Без него фигурная скобка в названии товара или в значении опции ломает страницу. Где разметка проходит через Fenom, она перестаёт компилироваться, и ответ приходит пустым.
| Экранировать | Оставить как есть |
|---|---|
| Название, описание, артикул, производителя, значения опций | Числа: {$total}, {$price}, {$count} |
| Ключи фильтров, слаги, подписи значений | Вложенную разметку: {$rows}, {$items}, {$pagination}, {$formAttrs} |
Адреса: {$baseUrl}, {$thumb}, результат | url | Строки лексикона |
Экранируйте и значения атрибутов, и текст: браузер покажет обычную скобку, а Fenom её уже не увидит.
Своя копия чанка исправления не получит
Обновление компонента не перезаписывает чанки, которые уже есть на сайте. В поставке значения экранированы, а в свою копию | esc придётся дописать самому.
