Skip to content
mFilter
mFilter
Фасетная фильтрация для MODX 3 с поддержкой SEO URL
  • MODX 3
  • PHP 8.1
  • Vue 3
  1. Компоненты
  2. mFilter
  3. Фронтенд
  4. Чанки

Чанки и разметка ​

Форму фильтров и обёртку результатов выводят чанки. Их можно заменить своими: скрипт mFilter продолжит работать, пока в разметке есть атрибуты и классы из контракта разметки.

Чанки формы ​

Сниппет mFilterForm собирает форму из шести чанков:

ПараметрЧанк по умолчаниюЧто выводит
tplOutermfilter.formОбёртку формы: тег <form> и кнопки
tplmfilter.filterБлок одного фильтра: название, счётчик выбранных, значения
tplItemmfilter.itemОдно значение списка — флажок, а если в фильтре выбирается одно значение, переключатель radio
tplSlidermfilter.sliderДиапазон фильтра типа number: два поля и ползунок
tplColormfilter.colorОдно значение фильтра типа colors
tplBooleanmfilter.booleanОдно значение фильтра типа boolean

Переменные каждого чанка и стандартная разметка — на странице сниппета mFilterForm.

После фильтрации чанки формы не перерисовываются: счётчики, недоступные значения и ползунки меняет скрипт по контракту разметки. Правка в чанке видна после перезагрузки страницы.

Чанки результатов ​

Сниппет mFilter выводит результаты тремя чанками:

ПараметрЧанк по умолчаниюЧто выводит
tplOutermfilter.outerОбёртку результатов с атрибутами для скрипта
tplmfilter.rowОдну строку результата
tplPaginationmfilter.paginationПагинацию

Переменные — в Плейсхолдерах и Пагинации. После фильтрации обёртка не перерисовывается: с сервера заново приходят строки и пагинация.

Свой чанк ​

fenom
{'!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/.

Короткий чанк можно задать прямо в вызове:

fenom
{'!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: по ним скрипт переходит по страницам без перезагрузки
html
{* Обёртка результатов — 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обёртка диапазонаСледит за полями и ползунком — см. Диапазон

Свои классы добавляются рядом:

html
<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 полупрозрачными, а их поля — недоступными для клика. Своё правило нужно, если стили компонента не подключены или переопределены:

css
.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 придётся дописать самому.