- Проверено Modstore
- Бесплатные будущие обновления
- Работа на тестовом и публичном домене
- 12 месяцев тех. поддержки


Возможности
- Фасетная фильтрация — по полям ресурсов, TV, данным и опциям MiniShop3
- Кросс-фильтрация — числа рядом со значениями считаются с учётом уже выбранных фильтров
- Индекс фасетов — значения и счётчики читаются из подготовленной таблицы, а не собираются запросом на каждый показ
- SEO URL — человекочитаемые адреса вида /catalog/vendor_id--acme/color--black/, с настраиваемым порядком сегментов
- SEO-шаблоны — динамические title, H1, description и текст по набору выбранных фильтров
- Индивидуальные SEO — свой текст под конкретную подборку, поверх шаблона
- Словоформы — склонение значений фильтров в SEO-текстах, с автозаполнением через Morpher API
- AJAX — обновление выдачи, адреса и заголовков без перезагрузки страницы
- Headless API — REST для интеграции с Vue, React, Svelte
- Карта сайта — XML с отфильтрованными страницами
- Хлебные крошки и перелинковка — сегменты активных фильтров в крошках, SEO-ссылки по значениям
- Фоновые задачи — синхронизация индекса, прогрев кэша и карта сайта по расписанию Scheduler
- Интеграция — MiniShop3, mSearch, pdoTools
- Vue-интерфейс — админка на Vue 3 + PrimeVue
Системные требования
- MODX Revolution | 3.0.0+
- PHP | 8.0+
- MySQL | 5.7+ / MariaDB 10.3+
Зависимости
- pdoTools 3.0.2-pl и новее — сниппеты и шаблонизатор Fenom
- VueTools 1.0.0-beta1 и новее — административный интерфейс
- MiniShop3 (опционально) — фильтрация товаров, производителей и опций
- Scheduler (опционально) — фоновые задачи: синхронизация индекса, прогрев кэша, карта сайта
Быстрый старт
Добро пожаловать в документацию — docs.modx.pro/components/mfilter/quick-start
1.8.0-beta2
Исправления
-
Сайт переставал открываться сразу после установки. Компонент собирался без своих зависимостей: каталог
vendorуезжал в пакет пустым, без файла автозагрузки. На сайте он подключается при старте MODX, поэтому отсутствие файла роняло не админку, а всё — и витрину, и панель управления. Переустановка не помогала: зависимостей в пакете не было вовсе, а запускать composer на сайте не требуется, они должны ехать готовыми. Теперь сборка проверяет их наличие и без них не запускается. -
Пакет распух до 2.6 МБ и перестал ставиться. MODX по умолчанию не принимает загрузку больше 2 МБ, и установка обрывалась на выборе файла. Виноват был не код: в каталогах сборки админки лежали файлы прежней схемы именования — вторая копия приложения, шрифты и иконки, всё от января. Сборщик забирает каталог ассетов с диска целиком, поэтому 2.6 МБ ненужного ехали в пакет. Теперь каталоги сборки очищаются перед каждым запуском, и в пакет попадает только то, что собрано сейчас.
- Шаблон каталога из комплекта подключал noUiSlider с внешнего адреса (#123). Библиотека входит в пакет, и плагин подключает её сам, так что копий на странице было две. Работу ломала не вторая копия, а то, как она подключалась: обычный
в конце страницы задерживает её разбор, пока файл не загрузится, а все скрипты mFilter ждут конца разбора — они отложенные. Недоступный или медленный внешний адрес задерживал вместе с собой и фильтры. Обе строки убраны, а с ними и такой же дубль `mfilter.css`. Взамен в комментарии передперечислены файлы из пакета — на случай выключенногоmfilter.register_frontend.
Внимание при обновлении: пакет 1.8.0-beta1 не ставится
Если вы уже скачали 1.8.0-beta1 и сайт после установки отдаёт пустую страницу или ошибку про vendor/autoload.php — установите эту версию поверх. Файлы встанут на место, настройки и данные фильтров не пострадают.
Если сайт не открывается даже в панели управления, удалите каталог core/components/mfilter/ по FTP — MODX заработает, после чего пакет можно поставить заново из менеджера дополнений.
Внимание при обновлении: шаблон каталога, списанный с образца
Исправление лежит в файле из поставки, а шаблон ресурса на сайте — ваша копия, и обновление её не трогает. Если вы списывали разметку с catalog.tpl прежних версий, уберите у себя подключение noUiSlider с внешнего адреса и строку с mfilter.css: и то и другое подключает плагин. Проверить просто — в сетевых запросах страницы каталога nouislider.min.js должен приходить один раз.
1.8.0-beta1
Исправления
-
Поле «Приоритет» у набора фильтров называлось не тем, чем было. Подпись «Меньше = выше приоритет» обещала правило разрешения конфликтов, хотя поле задаёт только порядок строк в списке наборов. Какой набор применится к странице, решается иначе: прямая привязка, а если её нет — ближайший родитель с включённым наследованием. Поле переименовано в «Порядок в списке», в подсказке сказано, на что оно не влияет. У паттернов и SEO-шаблонов приоритет работает по-настоящему и назван прежним словом.
-
Формы наборов и прогрева были вытянуты в одну колонку (#124). Набор фильтров редактируется в окне, где слева задумывались настройки, а справа — дерево страниц каталога. Разметка это описывала, но правил для сетки в сборке не было: классы пришли из библиотеки, которую в админку так и не подключили. В итоге всё вставало друг под другом, и до дерева приходилось листать мимо всей формы — а настройки при этом уходили из виду. Теперь колонки стоят рядом, окно стало шире, а на узком экране складывается обратно в одну колонку. Заодно то же самое исправилось в настройке прогрева.
По тому же следу нашлись и остальные места, где разметка рассчитывала на правила, которых нет: отступы между метками в таблицах, размер шрифта у примеров SEO-шаблонов, ширина поля «Приоритет», которое растягивалось во всю колонку вместо короткого. Часть правил вдобавок была объявлена только для модальных окон, поэтому во вкладках те же классы молчали. Теперь набор общий для всей админки.
Той же причиной была вытянута в одну колонку форма словоформы: падежи задумывались по три в ряд, а стили для них лежали внутри компонента и до модального окна не доходили — оно открывается за пределами области, к которой они привязаны. Теперь падежи снова стоят по три.
Заодно стало читаемым поле «Ключ» в таблице фильтров: выпадающие списки «Источник» и «Тип» с длинными подписями забирали ширину под себя, и ключу оставалось два-три символа —
pвместоprice.Дерево страниц каталога снова помещается в отведённую ему высоту и прокручивается внутри себя, у таблиц вернулась рамка, у подсказок — фон: это оформление лежало внутри компонентов и до модальных окон не доходило, а часть цветов ссылалась на переменные темы, переименованные в четвёртой версии PrimeVue.
Раскладка формы перестала зависеть от набора. Прежде у набора с десятью фильтрами таблица требовала больше места, чем колонка, и дерево уезжало под форму, а у набора с одним фильтром оставалось справа — при одинаковом размере окна. Теперь переносом распоряжается только ширина окна.
Колонки расходятся по ширине окна, а не экрана: окно уже самого экрана, поэтому на ноутбуке с масштабом 125% форма набора оставалась двухколоночной, а таблица фильтров не помещалась в свою половину.
-
Привязка
@SELECTу TV не работала (#102). Значения такого TV попадали в индекс без подписей, и фильтр показывал их как есть — для TV со списком ресурсов это идентификаторы вместо названий. Разбор срезал@SELECTи требовал, чтобы остаток снова начинался со словаSELECT, тогда как в MODX@SELECT— это и есть имя привязки, за которым идёт список полей. Теперь принимается обычная запись@SELECT pagetitle, id FROM modx_site_content WHERE …; строка со вторымSELECT, если её успели написать в обход, тоже продолжает работать. После правки TV нужно переиндексировать — кнопка «Переиндексация» в шапке админки mFilter.Одно ограничение осталось: привязка проверяется на второй оператор по точке с запятой, поэтому запись, где точка с запятой стоит внутри строки —
CONCAT(pagetitle, '; ', longtitle), — отклоняется, хотя сам MODX её выполняет. Такую привязку придётся переписать без точки с запятой. -
Сорвавшаяся привязка
@SELECTмолчала. Если запрос не выполнялся — опечатка в имени колонки, несуществующая таблица, — mFilter не писал об этом ничего: TV просто оказывался в индексе без подписей, и причину было не найти. Теперь в лог уходит сообщение MySQL целиком. -
Фильтр по TV со списком ресурсов показывал числа (#103). Такой TV хранит идентификаторы страниц, а подписи mFilter брал только из поля «Возможные значения», которое у него пустое: список задаётся настройками ввода — родителем и глубиной, — а не строкой элементов. В результате посетитель видел в фильтре
152149вместо названия раздела, и число уходило дальше: в адрес страницы, в блок «Выбрано» и в заголовок с описанием.Теперь подпись берётся из названия страницы. Это меняет четыре места сразу: значение в форме, алиас в адресе (
/catalog/oformlenie-zakaza/вместо/catalog/225/), подпись на плашке выбранного значения и подстановку в SEO-шаблонах. Алиас строится из названия — прежние адреса с числом продолжают открываться, потому что сегмент-число разбирается как раньше.Чтобы подписи появились, нужна переиндексация — кнопка «Переиндексация» в шапке админки mFilter. Ссылки на удалённые страницы остаются числами: брать название неоткуда.
-
Кнопка «Переиндексация» не трогала индекс TV (#107). Она обещает привести данные фильтров в порядок целиком, но индекс TV обходила: поправленные подписи значений так и не доезжали до фильтра, и понять это было нельзя — рядом на вкладке «Обслуживание» показывалось число записей индекса, которое не менялось. Теперь индексация TV идёт первым шагом, до генерации алиасов: алиас строится из подписи, которую держит индекс. В сообщении о завершении видно, сколько значений проиндексировано.
Раньше индекс TV обновляли только кнопка «Сгенерировать» на вкладке «Алиасы» и задача планировщика. Они продолжают работать как прежде.
-
Кнопка «Переиндексация» почти не создавала алиасов (#109). Она строила их пообъектно по источникам, а два источника из четырёх — значения TV и поля ресурсов — в этом пути не реализованы и молча возвращали пустой список. На деле кнопка создавала алиасы только для опций и данных товаров, а остальное оставалось на кнопке «Сгенерировать» вкладки «Алиасы». Теперь алиасы строятся по наборам фильтров — тем же способом, что на вкладке «Алиасы» и в задаче планировщика, — и три способа обновить данные фильтров дают один результат.
Обход всех наборов по каждой привязанной странице на крупном каталоге занимает минуты, поэтому кнопка теперь отдаёт эту работу планировщику, если он установлен, — как уже делает со сборкой индекса фасетов. Без планировщика всё выполняется сразу, и страницу придётся подождать.
В сообщении о завершении вместо «обновлено» теперь «уже было» и число обработанных наборов: прежнее число всегда было нулём, потому что этот путь алиасы не обновлял.
-
Кэш данных фильтров очищался не вовремя. Кнопка «Переиндексация» чистила его первым делом, а обход наборов после этого идёт минутами — за это время посетители наполняют кэш наполовину обновлёнными данными. Теперь кэш очищается последним, после алиасов, и то же самое делает задача планировщика: раньше она не очищала его вовсе, и на сайте с планировщиком фильтр показывал старые подписи, пока записи не устареют сами.
Заодно очистка перестала стирать служебные метки индекса фасетов. Они лежат в той же таблице, но кэшем не являются: по одной из них задача синхронизации понимает, с какого момента догонять правки товаров. Без метки следующий запуск считал себя первым, сдвигал точку отсчёта на текущий момент и правки, сделанные за это время, в индекс не попадали до полной пересборки. Это же чинит кнопку «Очистить кэш», где ошибка была и раньше.
-
Очистка кэша ломала фильтрацию на закэшированных страницах (#29). В той же таблице лежат настройки вызова сниппета — по ним AJAX восстанавливает чанки, лимит, разделы и глубину. Очистка сносила их вместе с кэшем, а восстановить их нельзя: ключ остаётся в уже закэшированной разметке страницы, запрос приходит с ключом, которого больше нет, и ответ собирается стандартными чанками с лимитом 20. Со стороны это выглядит как «после фильтрации сбросился мой шаблон».
Больнее всего била точечная очистка по одной странице — та, что срабатывает при сохранении набора фильтров. Она искала ключи по образцу вида
%_5%, а в поиске по образцу_означает «любой один символ», то есть на деле это «в ключе где-нибудь есть цифра 5». Ключ настройки вызова — сорок шестнадцатеричных знаков, и любая заданная цифра встречается в нём почти всегда: под однозначный номер страницы попадало около 92% всех настроек вызова на сайте, под двузначный — около 14%. Сохранили набор, привязанный к странице 5, — и настройки почти всех страниц каталога снесены.Полная очистка — кнопка «Очистить кэш», «Перестроить кэш» в наборах фильтров и задачи планировщика — сносила настройки вызова целиком.
Теперь образцы привязаны к началу ключа, подчёркивания в них экранированы и перечислены явно. Экранирование заодно развело соседние номера: очистка страницы 5 больше не задевает страницы 50–59. В список точечной очистки добавлены три вида записей, которых там не хватало.
Просроченные настройки вызова теперь удаляются при полной очистке: раньше их уносила та же тотальная очистка, а после исправления они копились бы без предела.
-
«Перестроить кэш» в наборах фильтров ломал синхронизацию индекса фасетов. Исправление служебных меток в предыдущей записи закрыло кнопку «Очистить кэш», но второй путь полной очистки остался прежним и стирал метку, от которой задача синхронизации отсчитывает правки товаров. Теперь оба пути ходят через одно определение того, что в таблице не кэш.
-
Фигурная скобка в данных роняла страницу в пустоту (#93). Стандартные чанки выводили названия товаров, значения опций, ключи фильтров и адреса как есть, мимо модификатора
esc. Товар с названием вроде «Шуруповёрт {Люкс}» попадал в разметку вместе со скобкой, и на сайтах, где разметка проходит через Fenom, страница не компилировалась: пустое тело ответа иUnexpected tagв логе. Это тот же дефект, что в 1.7.0-beta1 закрыли для строки атрибутов формы, — оставшаяся половина. Теперь такие значения экранируются — правка задела десять чанков из четырнадцати.Ломалось не на каждой странице: чтобы Fenom взялся компилировать, в той же разметке должен встретиться хоть один его собственный оборот —
{$переменная},{if …}, вызов сниппета через|. На странице, где его нет, скобка в данных проходила незаметно, и дефект годами не проявлялся, пока в каталог не попадал товар с фигурной скобкой в названии.Числа, готовая разметка и строки лексикона не экранируются: первые безопасны, вторая сломалась бы от экранирования, а третьи правятся владельцем сайта и иногда содержат теги намеренно. Текст кнопки сброса в блоке «Выбрано» — как раз такой случай: его задают параметром
&resetText, куда иногда кладут иконку.Правка задела и встроенные чанки по умолчанию у сниппетов
mFilterNav,mFilterCrumbsиmFilterSitemap: подписи и адреса в них выводились так же, без экранирования. В карте сайта это заодно чинит разметку — амперсанд в адресе фильтра делал XML невалидным. -
Задачи по расписанию не запускались ни разу (#116). Синхронизация индекса фасетов каждые пять минут, прогрев кэша, карта сайта и уборка
mfl_request_idsрегистрировались при установке, но не выполнялись — ни на одной установке компонента. Планировщик берёт работу из очереди запусков, а не из списка задач, и следующий запуск повторяющейся задаче планируется только по итогам состоявшегося. Первого запуска задаче никто не ставил, поэтому цепочка не начиналась. Теперь установка заводит первый запуск каждой повторяющейся задаче, а уже начатые не трогает.Из-за этого правки товаров через API и прямой SQL не доезжали до индекса фасетов между полными пересборками — тем, что пятиминутная синхронизация и должна была подхватывать.
Заодно разовая пересборка индекса, которую установка ставит в очередь, перестала плодить дубли: раньше каждое обновление добавляло ещё одну, и на сайте без настроенного планировщика они просто копились. Теперь, если пересборка уже ждёт или выполняется, вторая не ставится.
-
Повторные постановки задач удваивали расписание. Кнопка «Прогреть сейчас» ставила задаче прогрева новый запуск, не глядя на уже стоящий. Для повторяющейся задачи это хуже дубля: закончившись, лишний запуск планирует следующий за собой, и рядом с первой цепочкой навсегда появляется вторая — своя на каждое нажатие. Теперь постановка идёт через общую проверку: ожидающий запуск переносится на более раннее время и вбирает новые параметры, а повторяющейся задаче во время выполнения ничего не ставится — следующий запуск она заведёт сама.
Разовые задачи — пересборка индекса, переиндексация алиасов, словоформы — ведут себя иначе: если попросить их во время работы, запуск встанет следом. «Уже выполняется» не значит «твою просьбу учтут»: пересборка читает каталог на старте, и товары, пришедшие импортом уже после, в неё не попадут. Больше одного ожидающего и одного выполняющегося запуска у задачи при этом не бывает.
-
Две пересборки индекса шли одновременно (#118). Планировщик берёт из очереди следующий запуск, не глядя на то, что предыдущий ещё работает. Для сборки индекса фасетов это значит вот что: она начинается с очистки обеих таблиц, поэтому вторая выбрасывала всё, что успела записать первая, и на крупном каталоге окно, когда фильтры показывают неполный набор значений, растягивалось на обе пересборки вместо одной. Каталог при этом читался дважды ради одного результата. Ловили это магазины, которые грузят прайс партиями: каждый импорт ставит пересборку следом, а предыдущая ещё идёт.
Само содержимое индекса от этого не терялось: строки добавляются с проверкой по первичному ключу, а вторая пересборка обходит все фильтры заново — после её окончания индекс полный. Зато пока он строится, кэш успевает набраться неполными данными и держит их ещё до часа (
mfilter.cache_lifetime) после того, как пересборка закончилась.У генерации алиасов последствия хуже: обход проверяет, есть ли алиас, и только потом вставляет, а уникальный ключ здесь не спасает — в него входит
culture_key, и на сайте без культур он пустой, а MySQL разрешает повторять пустые значения в уникальном ключе. Два параллельных обхода записывали одному значению два алиаса. Индексация значений TV от столкновения не портилась, но половина вставок падала на уникальном ключе: ошибки в журнале и заниженные числа в отчёте.Теперь одновременно выполняется только одна такая работа. Вторая не пропадает: она встаёт в очередь на две минуты позже и дожидается своей очереди, так что изменения, ради которых её поставили, в индекс попадут. Пятиминутная синхронизация индекса на время полной пересборки пропускает такт и возвращается в следующий, не сдвигая точку отсчёта.
В админке кнопки «Переиндексация», «Пересобрать индекс фасетов» и «Сгенерировать» теперь предупреждают «Уже выполняется» — раньше они запускали вторую копию поверх первой.
Внимание при обновлении: фоновые задачи начнут выполняться
После обновления повторяющиеся задачи заработают — на сайте с настроенным планировщиком это заметно по нагрузке в первые минуты: индекс фасетов синхронизируется, прогревается кэш, строится карта сайта.
Отключить отдельную задачу нечем: у задачи планировщика нет признака «выключена». Удалить её ожидающий запуск или саму задачу можно, но до следующего обновления mFilter — установка заведёт их снова. Единственный рычаг — cron: без него задачи просто встанут в очередь и будут ждать.
Проверить, работает ли планировщик, можно по времени запуска у задач в разделе Scheduler: у выполненной оно заполнено.
За один запуск планировщик выполняет одну задачу — это его настройка scheduler.tasks_per_run. Синхронизация индекса раз в пять минут и уборка раз в десять занимают заметную долю запусков: при cron раз в минуту около трети. Если cron у вас реже, задачи других компонентов будут ждать дольше обычного — увеличьте scheduler.tasks_per_run или запускайте cron чаще.
Внимание при обновлении: свои чанки нужно поправить руками
Обновление компонента не перезаписывает чанки, которые уже есть на сайте. Если вы правили стандартные чанки под себя или сделали с них копии, исправление до них не доедет — добавьте | esc сами. Экранировать нужно всё, что приходит из данных: название товара, описание, артикул, производителя, значения опций, ключи фильтров, слаги, адреса. Не нужно — числа и вложенную разметку вроде {$rows}, {$items}, {$pagination}.
Внимание при обновлении: у mFilterNav разметку задаёт свойство сниппета
У mFilterNav разметка пункта и обёртки хранится не в коде, а в свойствах сниппета — их видно на вкладке «Свойства» в дереве элементов. Значение свойства перебивает значение из кода, поэтому на сайте, где свойство уже заполнено, исправление само не применится.
Если после обновления навигация по-прежнему выводит скобку как есть, откройте свойства mFilterNav и допишите | esc в tpl и tplOuter — либо очистите оба свойства, тогда возьмётся значение из кода:
@INLINE {$label | esc}
@INLINE {$output}
Внимание при обновлении: анонс товара выводится текстом
В стандартном чанке списка анонс товара теперь экранируется, как и остальные данные. Если вы держите в анонсе разметку — например, ` для выделения, — она станет видна текстом. Перенесите её в отдельное поле или уберите| escу{$introtext}` в своей копии чанка.




Последние обсуждения в сообществе MODX.pro