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


Возможности
- Фасетная фильтрация — фильтрация по любым полям ресурсов, TV, опциям MiniShop3
- SEO URL — человекочитаемые URL вида /catalog/brand_apple/color_black/
- Кросс-фильтрация — подсчёт доступных значений с учётом активных фильтров
- AJAX — обновление результатов без перезагрузки страницы
- Headless API — REST API для интеграции с Vue, React, Svelte
- SEO оптимизация — динамические title, description, H1, canonical
- Словоформы — склонение названий фильтров в SEO-текстах
- Интеграция — работает с MiniShop3, mSearch, pdoTools
- Vue-интерфейс — современная админ-панель на Vue 3 + PrimeVue
Системные требования
- MODX Revolution | 3.0.0+
- PHP | 8.1+
- MySQL | 5.7+ / MariaDB 10.3+
Зависимости
- pdoTools 3.x — для работы сниппетов и шаблонизатора Fenom
- VueTools — для административного интерфейса
- MiniShop3 (опционально) — для фильтрации товаров
Быстрый старт
Добро пожаловать в документацию — docs.modx.pro/components/mfilter/quick-start
1.5.1-beta1
Исправления
-
Переменные, заявленные в документации, не доходили до чанков. Четыре штуки, все одного вида: значение собиралось из источника, которого не существует, и молча подменялось запасным. Заметить это мог только тот, кто переопределил чанк — стандартные чанки половину этих переменных не выводят.
Чанк Переменная Что выводилось tplSlider$labelключ фильтра вместо названия из поля «Заголовок» tplSlider$prefix,$suffixпусто при любых настройках tplReset(«Выбрано»)$urlпусто — переменная не передавалась вовсе tplOuter(«Выбрано»)$totalпусто — код передавал только $countПричина у первых трёх общая: значения читались из результата
getFiltersData(), который возвращаетkey,type,configиvalues— и ничего больше. Теперь заголовок берётся по той же цепочке, что и в обёртке фильтра: поле «Заголовок» набора → подпись TV или опции MS3 → лексикон. Префикс и суффикс — из настроек фильтра.$totalпередаётся рядом с$countкак второе имя того же значения: переименование сломало бы чанки, опирающиеся на существующее. -
$hexв чанке цветового свотча ставился не всегда. Если у значения не задан HEX, переменная отсутствовала, и чанк должен был это предусматривать. Теперь всегда приходит, пустой строкой. -
$filtersвtplOuterсниппетаmFilterсуществовал только в native-режиме. С параметромelementчанк, перебирающий$filters, молча выводил пустоту. Теперь оба режима передают его одинаково. -
Ссылки пагинации вели в 404 на сайтах с нестандартным разделителем. Чанк
mfilter.paginationсобирал сегмент какpage_2, игнорируя настройкуmfilter.url_separator. На установках с--— а это значение по умолчанию для новых установок с 1.4.0 — роутер такой адрес не разбирал. Изнутри сайта дефект незаметен: JS перехватывает клик и строит адрес сам, минуя роутер. В 404 попадали при прямом открытии — из закладки, новой вкладки или поиска. Разделитель теперь берётся из настройки:{var $sep = 'mfilter.url_separator' | option}. -
Настройка
mfilter.default_limitне влияла на размер страницы. Её читали роутер,UrlBuilderи native-режим, но не сниппет — там было зашито 20. Менялось только то, какие адреса несут сегмент лимита, а каталог продолжал отдавать по двадцать. Теперь настройка задаёт значение по умолчанию для&limit, а переданный&limitеё перекрывает.Значение доводится и до AJAX. Иначе исправление создало бы разрыв ровно на тех сайтах, ради которых сделано: первая отрисовка по 12, первый же клик по фильтру — по 20, число страниц меняется под посетителем, а товары между двумя размерами страницы становятся недостижимы.
-
Селект сортировки и переключатель вида в
mfilter.outerвсегда показывали значения по умолчанию. Чанк читал$_pls['mfilter.sort']и$_pls['mfilter.tpl'], а$_pls— это не массив глобальных плейсхолдеров:pdoToolsзаполняет его из$modx->placeholdersпри разборе шаблона ресурса, но данными самого чанка при вызовеgetChunk(). Этих ключей там никогда не было. Страница, открытая по адресу/catalog/sort_price-asc/, показывала в селекте «По названию», а переключатель подсвечивал сетку независимо от вида. Сниппет теперь передаёт$currentSortи$currentTplготовыми значениями. -
&pageParamне доходил до чанка пагинации в element-режиме. Из трёх мест отрисовки его передавали два. Кастомный чанк со ссылками вида?page=2выдавал там?=2. Параметр задаёт имя GET-параметра, а не сегмента ЧПУ: имя сегмента — всегдаpage. - Пример шаблона каталога переведён на вызов сниппета в переменную (
{set $mfilterOutput = '!mFilter' | snippet : [...]}) с выводом ниже по разметке. Плейсхолдеры сниппета появляются только после того, как он отработал, поэтому шаблон, читающийmfilter.seo.h1илиmfilter.seo.textвыше вызова, получал пустоту. Обёртку результатов пример больше не дублирует — её рисует чанкtplOuter.
Внимание при обновлении: чанки не перезаписываются
Стандартные чанки при обновлении компонента не затираются — правки в mfilter.pagination и mfilter.outer дойдут только до новых установок. Сайтам со своей копией их нужно обновить вручную, иначе:
- в
mfilter.paginationостанется зашитыйpage_, и ссылки пагинации продолжат отдавать 404 при прямом открытии; - в
mfilter.outerостанется собственное{var $currentSort = $_pls['mfilter.sort'] ?: 'pagetitle-asc'}, которое перекроет переданную переменную своим же значением по умолчанию — молча, без ошибок.
Симптом в обоих случаях выглядит как поломка компонента, а причина — в устаревшем чанке.
Внимание при обновлении: $_pls в шаблоне и в чанке — разные массивы
Это не изменение поведения, а причина, по которой разметка, перенесённая из чанка в шаблон ресурса, ломается. {$_pls['hash']} работает в чанке mfilter.outer (ключ hash есть в его данных) и не работает в шаблоне: там $_pls — глобальные плейсхолдеры, и нужный называется mfilter.hash.
Практическое следствие: не дублируйте обёртку data-mfilter-results в шаблоне. Получатся два вложенных контейнера, JS привяжется к внешнему, а data-mfilter-hash в нём будет пуст. AJAX без хэша не находит сохранённую конфигурацию вызова и уходит в native-режим — в выдачу попадают категории и прочие ресурсы, которых не было при первой загрузке. Молчаливость этого отката вынесена в отдельную задачу.
Внимание при обновлении: подписи над слайдерами изменятся
Там, где в чанке слайдера стоит {$label}, вместо ключа фильтра появится его название — price сменится на «Цена». Это и есть исправление, но подписи на существующих страницах поменяются сами собой, без правок в вёрстке.
Отдельно про $hex: он теперь приходит всегда, пустой строкой вместо отсутствия. Чанк с проверкой {if isset($hex)} пойдёт по истинной ветке в любом случае — проверять надо {if $hex}.
1.5.0-beta1
Исправления
-
SEO-шаблон не срабатывал на страницах с диапазоном. Шаблон подбирается по ключам фильтров, а SEO-адрес отдаёт диапазон двумя записями —
price|minиprice|max. Шаблон, настроенный наprice, не совпадал ни с одной, и страница уходила на генерацию по умолчанию: вместо «Категория ценой от 10600» получалось «Категория - 10600, 15500». Теперь границы сворачиваются к базовому ключу перед подбором.Свёртка применяется только к именованию — подбору шаблона, плейсхолдерам и тексту по умолчанию. Правила индексации и canonical читают исходный набор границ: для
mfilter.seo_max_valuesсвёрнутый диапазон выглядел бы двумя значениями и при значении настройки 1 закрывал бы от индексации каждую такую страницу, аUrlBuilderопознаёт диапазон именно по суффиксам и собрал бы адрес видаprice_10600-or-15500— многозначный, с другим смыслом. -
Диапазон в заголовке читается по-человечески. Раньше границы перечислялись как отдельные значения — «Категория - 10600, 15500», а односторонний диапазон давал «Категория - 10600» без указания, что это минимум. Теперь: «10600 — 15500», «от 10600», «до 15500» — через новые лексиконы
mfl_seo_range_from,mfl_seo_range_to,mfl_seo_range_separator.Это часть свёртки из предыдущего пункта: при ней недостающая граница заменяется служебным числом
9223372036854775807, пригодным для условия в запросе и негодным для заголовка. До свёртки такая подстановка на этом пути не выполнялась вовсе. -
Сортировка каталога при AJAX работала только внутри страницы. В element-режиме контроллер не передавал текущую сортировку элементу: тот отдавал ID в порядке по умолчанию, нарезка шла в нём, и сортировал только пагинатор — внутри полученного среза. Тот же дефект, что закрыт для серверной отрисовки в 1.4.7; здесь он жил на пути, которым сортировку и меняют.
Заодно ключ сессионного кэша
baseIdsстал учитывать сортировку. Без этого исправление не доезжало: второе переключение сортировки без перезагрузки попадало в кэш и получало прежний порядок. Формат ключа изменился — после обновления первый запрос каждой сортировки пересчитает выборку. -
Кнопка «Сбросить всё» не работала на странице, отфильтрованной только диапазоном. Такая страница рендерится с кнопкой и без чипов — снять диапазон по одному значению нельзя. JS определял серверный рендер по наличию чипов, не находил их, считал что рендера не было и перерисовывал блок своей стандартной разметкой: кастомные чанки заменялись, а обработчик кнопки не навешивался. Признаком теперь служит атрибут
data-mfilter-selected-hash. -
Параметр
&searchVarсниппетаmFilterзадаёт имя параметра запроса с поисковой фразой; раньше было жёсткоmse_query, и сайт, переименовавший его вmSearchForm, получал каталог, который запроса не видел. Работает в element-режиме. Имя намеренно отличается отqueryVar: тот документирован как параметр элемента mSearch и пробрасывается ему — чтение того же имени запускало бы второй полный поиск на каждый запрос. -
Кнопку сброса формы можно помечать атрибутом
data-mfilter-resetнаравне с классомmfilter-reset-btn. Оба маркера управляют и видимостью, и самим сбросом — раньше класс отвечал только за видимость, а сброс навешивался наtype="reset"/.mfilter-reset, поэтому кнопка безtype="reset"появлялась и пряталась, ничего не делая. Класс поддерживается по-прежнему. -
Неразобранный сегмент URL влиял на SEO. Служебный ключ
_hidden, куда JS складывает сегменты адреса, которые не удалось разобрать, доходил до заголовка страницы, участвовал в подсчёте лимитов индексации и попадал в canonical — тот собирался в виде/категория/_hidden_мусор/, а для мусорного значения ещё и создавалась запись слага. Ключ отбрасывается на входе в генерацию SEO. -
Дублирование класса
mfilter-pagination. Класс стоял и на обёртке вmfilter.outer, и навнутри `mfilter.pagination`. Снят с: контрактом объявлена обёртка — именно её ищет JS, чтобы заменить содержимое. - Переустановка пакета ломала все SEO-шаблоны. Колонка
text_templateдобавлялась только при обновлении. Удаление компонента таблицы не трогает — они сохраняются намеренно, — аcreateObjectContainer()досыпает только отсутствующие таблицы, но не колонки в существующие. После цикла «снести и поставить заново» таблица оставалась со старым набором колонок под моделью, которая новое поле уже объявляет: xPDO подставлял его в каждый SELECT, все запросы к шаблонам падали сUnknown column, список шаблонов приходил пустым, и любая отфильтрованная страница уходила на дефолтную генерацию. Снаружи — «шаблоны перестали работать», в админке пустая вкладка, причина видна только в журнале. Проверка колонки теперь выполняется и при установке. - Приоритет SEO-шаблонов не работал. Сортировка шла по полю
priority, которого у шаблонов нет — это колонка паттернов. Оба значения всегда были нулевыми, порядок перебора совпадал с порядком выдачи MySQL, и при двух подходящих шаблонах выбор был по сути случайным. Теперь сортировка идёт поsort_order— тому самому «Порядку» из интерфейса, где меньше значит выше. На сайтах с несколькими подходящими шаблонами выбор может измениться — в сторону задокументированного поведения. - При пустой выдаче AJAX-ответ не нёс SEO и адреса. Ранний возврат для случая «ничего не найдено» собирался без ключей
seoиurls. JS трогает элементы только когда ключ пришёл, поэтому на пустом разделе оставались заголовок, описание и текст предыдущей подборки, а адресная строка — прежний URL. - Отсутствующий ресурс больше не стирает мета-теги. При запросе SEO для несуществующего ресурса возвращалась полная форма с пустыми строками, а пустая строка для JS — команда удалить `` и canonical. Теперь такой запрос не отвечает ничем, и документ остаётся как был.
-
SEO-текст не очищался при снятии фильтров.
SeoBuilder::build()возвращал ключtextтолько из ветки с подобранным шаблоном. При снятии всех фильтров срабатывал ранний возврат, а при комбинации без подходящего шаблона —buildDefault(), и обе эти ветки ключа не содержали. JS обновляет элемент только когда ключ пришёл, поэтому на странице оставался текст от предыдущей подборки. Теперь все ветки возвращают полную форму ответа — недостающий ключ больше не пропустить. -
Поле «Шаблон текста» в SEO-шаблонах не сохранялось. Поле было проведено через весь стек — редактор его отправлял,
TemplateControllerзаписывал при создании и обновлении,SeoBuilderчитал, — но отсутствовало в карте полей модели xPDO, и колонки в таблице не существовало. xPDO молча отбрасывает поле, которого не знает:save()возвращал успех, в журнал ничего не писалось, значение исчезало.toArray()его тоже не отдавал, поэтому при повторном открытии редактор показывал пустое поле. Колонка добавляется миграцией при обновлении; на новых установках она создаётся из модели. -
Блок «Выбрано» сбрасывался на дефолтные чанки при фильтрации.
SelectedFilters.jsсодержал захардкоженную копию четырёх стандартных чанков и пересобирал блок из неё при каждом AJAX-ответе — поэтому кастомная разметка жила ровно до первого клика по фильтру, после чего заменялась стандартной. Без ошибок и без возможности отключить.Причина в том, что разметка была продублирована на двух языках — в чанках и в JS. Поэтому дублирование убрано: блок теперь рендерится на сервере теми же чанками, что и при первой загрузке, а JS просто вставляет полученную разметку — так же, как это давно работает для списка товаров.
Логика рендера вынесена из сниппета в сервис
SelectedRenderer, сниппет сохраняет свой конфиг (чанки и флаги) и выводит его хэш вdata-mfilter-selected-hash, контроллер возвращает готовый HTML в полеselectedAJAX-ответа.Обратная совместимость полная: если в вашем
tplOuterнет атрибутаdata-mfilter-selected-hash, сервер не отдаётselected, и работает прежний клиентский рендер. Чтобы включить — добавьте атрибут (в стандартном чанке он уже есть): - В блок «Выбрано» при AJAX попадали посторонние ключи. Сниппет при разборе запроса пропускал только настроенные фильтры, а AJAX-ветка рендерила всё, что прислал браузер — включая служебный
_hidden, куда JS складывает неразобранные сегменты URL. Теперь ключи, которых нет в наборе фильтров страницы, чипами не становятся. Заодно добавлено экранированиеdata-keyиdata-group/data-labelв чанках — рядом с ними|escуже стоял на значениях. -
Блок «Выбрано» мог отрендериться «непустым» без единого чипа. Проверка на пустоту стояла до отсева служебных ключей: если в фильтрах оставались только ключи, которых нет в наборе страницы, контейнер получал
empty => false— без чипов, но с рабочей кнопкой сброса и без учётаhideWhenEmpty. Теперь пустым считается состояние, когда не применён ни один фильтр.Диапазон при этом чипом не показывается — снять «от 1000 до 5000» одним значением нельзя, а два чипа «1000» и «5000» вводили бы в заблуждение. Но он считается применённым фильтром: блок остаётся на месте с кнопкой сброса, а
{$count}учитывает его как один фильтр — независимо от того, пришёл он какprice(query-URL) или какprice|min+price|max(SEO-URL, роутер отдаёт границы раздельно). {$count}вtplOuterблока «Выбрано» расходился с числом чипов. Считался входной массив, а не отрисованные значения: диапазон давал 2, плюс в счёт входили пропущенные ключи. Теперь это число применённых фильтров — совпадает с$activeFiltersCountформы. С числом чипов оно не совпадает ни в одном режиме: чипов столько, сколько значений, и фильтр «Цвет: красный, синий» даёт две кнопки и приgrouped=1(внутри одной группы), и приgrouped=0. Диапазон считается один раз и чипа не даёт вовсе.- Подписи значений в блоке «Выбрано» для категорий MS3 и производителей. Раньше человекочитаемое название подставлялось только для ключей
parentиvendor_id— чипы категорий MS3 (ms3_category,ms3_categories) и производителей (vendor,vendors) показывали сырой ID. Теперь распознаются все эти ключи. - С параметром
elementкаталог рендерился пустым.mFilterбезусловно записывал в параметры элемента свои дефолтыshowHidden/showUnpublished/showDeleted=false, даже когда вызывающий их не задавал.msProductsобъявляетshowHidden => trueнамеренно — товары почти всегдаhidemenu = 1, их прячут из навигации; получив нашfalse, он добавлял в запросhidemenu = 0и возвращал пустой список ID. Теперь флаги видимости пробрасываются только когда заданы явно, и элемент сохраняет свои дефолты. Выявлено на боевом каталоге. - При AJAX сбрасывались чанки, лимит и scope (native mode). После применения фильтра карточки рендерились дефолтным
mfilter.rowвместо кастомного чанка, размер страницы становился 20, аparents/depth/whereтерялись целиком. Причина: element mode сохранял конфиг вызова и восстанавливал его на AJAX, а native mode не сохранял ничего —FilterController::applyLegacy()добивал пробелы захардкоженными дефолтами. Теперь оба режима используют общее хранилище конфига, аFilter::ajaxApplyFilters()пробрасывает scope-параметры вFilter::apply(). Побочно это чинитwhereв native mode: до сих пор он применялся только на первом рендере, а после фильтрации отваливался. - Дублирование фильтров в URL и в блоке «Выбрано». Мультизначные фильтры (
param_5[]) показывались дважды — один раз слагами из URL, второй раз значениями из формы — и накапливались в адресной строке. Четыре места в JS парсили фильтры, и только одно нормализовало суффикс[]; теперь нормализация вынесена в общий хелпер. ДополнительноparseFromForm()заменяет, а не дополняет данные из URL (сервер уже отрендерил инпуты отмеченными с реальными значениями), а сторонние query-параметры (utm_*,gclid) больше не попадают в состояние фильтров и не превращаются в чипы. В query-режиме мультизначные фильтры теперь пишутся какkey[]=a&key[]=b— иначе PHP собирал из них строку с единственным значением, и по прямой ссылке выбор терялся. data-totalиdata-page-countпротухали после AJAX. Атрибуты обёртки результатов — часть контракта разметки (SSR их пишет, JS читает при инициализации), но после фильтрации никто их не обновлял: на выборке 81 → 35 пагинация показывала верные 3 страницы, а атрибуты продолжали заявлять 81 и 7. Теперь синхронизируются на каждом обновлении. Для native mode в ответ добавленыpageCountиpage— без них не обновлялось и внутреннее состояние, из-за чего «Показать ещё» считал страницы по первому рендеру.- Warmup мог вернуть пустой каталог даже после исправления сниппета. Авто-созданные конфиги прогрева хранят параметры вызова, но
WarmupKeyBuilderне включает в хэш значения, равные дефолтам — поэтому набор сshowHidden = falseи набор без него дают одинаковый хэш. Конфиг находился по хэшу, его параметры никогда не обновлялись, прогрев запускал элемент со старыми параметрами, получал пустой список и кэшировал его под тем самым хэшем, который читает страница. Теперь параметры авто-конфигов обновляются при расхождении, пустой результат прогрева не кэшируется вовсе (пустой список почти всегда означает сломанный конфиг, а не пустой раздел), а миграция при обновлении вычищает устаревшие флаги из существующих авто-конфигов и сбрасывает связанный кэш baseIds.
Новые возможности
-
Индивидуальные SEO для подборок. Новая вкладка задаёт собственные title, h1, description и текст для конкретной комбинации фильтров — например, только для страницы одного цвета. Раньше такое можно было получить лишь сторонним плагином со своей таблицей.
Заполненное поле перекрывает SEO-шаблон, незаполненное — оставляет его значение. Каждое поле проходит цепочку «индивидуальная запись → шаблон → значение по умолчанию» самостоятельно, поэтому чтобы поменять только заголовок, достаточно заполнить один H1: при правке шаблона такие страницы обновятся вместе со всеми.
Записи создаются по требованию. Страница с одним фильтром и сорока значениями даёт сорок адресов, и заводить под них пустые строки значило бы засорить базу. Список подборок строится на лету из фильтров страницы, строка попадает в базу при первом сохранении, а очистка всех полей её удаляет.
Запись привязана к значению фильтра, а не к URL. Переименование слага, смена
mfilter.url_separatorили режимаmfilter.slug_parent_prefixменяют адрес страницы, но запись продолжает работать — в отличие от решений, которые ключуют такие данные по адресу.Список перечисляет подборки по одному значению одного фильтра — их пишут руками, и просматривать их списком осмысленно. Диапазоны и сочетания нескольких значений не перечисляются: между границами диапазона адресов бесконечно много, а сочетания растут мультипликативно.
Запись снимает
noindex, навешенныйmfilter.seo_max_filtersилиmfilter.seo_max_values, и восстанавливает canonical на саму отфильтрованную страницу. Оговорка: подборку по одному значению эти настройки и так не закрывают, поэтому на страницах из списка снимать нечего — правило работает для записей, охватывающих сочетания нескольких значений. Настройкаmfilter.seo_noindex_filteredсильнее в любом случае: если владелец закрыл все фильтрованные страницы, текст в поле этого не отменяет.Если значение исчезло из каталога, запись не удаляется — помечается в списке и остаётся: текст писали руками.
-
Чанк формы знает о состоянии фильтров. В
tplOuterсниппетаmFilterFormдобавлены переменные$hasFilters,$activeFiltersCountи$appliedFilters— теперь кнопку сброса (бейдж, сводку) можно показывать только когда что-то реально выбрано:Сбросить ({$activeFiltersCount})Раньше штатного способа не было: плейсхолдер
mfilter.activeCountвыставляется после рендера чанка и внутри него недоступен, аmfilter.filtersзаполняется только при разборе SEO-URL — фильтры из обычной query-строки в него не попадали. Новые переменные собираются из обоих источников.Элемент с атрибутом
data-mfilter-resetили классомmfilter-reset-btnскрывается и показывается автоматически при AJAX-фильтрации, вложенный[data-mfilter-reset-count]получает количество. Оба маркера равноправны; класс поддерживается и дальше, стандартный чанк перешёл на атрибут. Важно: кнопку нужно рендерить всегда и скрывать атрибутомhidden— обёрнутую в{if $hasFilters}кнопку JS не найдёт в DOM и показать не сможет.Счётчик считает диапазон за один фильтр — так же, как сервер:
price|minиprice|maxсхлопываются вprice. -
Разрешение конфликтов слагов и опциональный префикс родителя. Две категории с одинаковым названием в разных ветках (например «Axis» в «Печах» и в «Топках») давали один и тот же слаг
axis. Второй INSERT падал на уникальном индексеuk_filter_slug_cultureсDuplicate entry, запись не создавалась, иUrlBuilderподставлял в URL сырое значение — числовой ID категории вместо человекочитаемого адреса. Причина:SlugManager::save()проверял существование только по паре(filter_key, value), но не по(filter_key, slug).Теперь конфликт разрешается до записи. Поведением управляет новая настройка
mfilter.slug_parent_prefix:Режим Поведение on_conflict(по умолчанию)Обычный слаг; при конфликте добавляется родитель — topki-axis. Существующие URL не меняютсяalwaysРодитель добавляется всегда — pechi-axis,topki-axis. Меняет существующие URL, потребуются 301-редиректыneverТолько числовой суффикс — axis-2Префикс родителя доступен только там, где значение фильтра — ID ресурса. Раньше это решалось по имени ключа: два захардкоженных списка (
SlugManager::getOrCreate()и логика префикса) должны были совпадать сsupports()каждого типа — и разъехались. Из-за этого на MS3-каталогах слаги категорий писались в таблицу, ноUrlBuilderвсё равно подставлял в URL числовой ID, потому что ключейms3_category/ms3_categoriesне было в списке.Теперь тип фильтра сам сообщает, с чем работает, — новый метод
FilterTypeInterface::getValueKind():Вид значения Слаг для числового Префикс родителя Типы resourceда да parents,ms3_categoriesentityда нет vendorsscalar(по умолчанию)нет нет все остальные MS3CategoriesFilterTypeнаследуетresourceотParentsFilterType— новые типы-наследники получают корректное поведение автоматически. Для сторонних типов ничего не ломается: значение по умолчаниюscalarобъявлено вAbstractFilterType, от которого предписывает наследоваться документация. -
Понятная ошибка при ручном вводе занятого слага. Раньше вкладка «Алиасы» отвечала безликой «Ошибкой сохранения» с кодом 500, а в лог падал
Duplicate entry— было неясно, что слаг занят и каким значением. Теперь возвращается 409 с текстом «Слаг «axis» уже занят значением «124»». Автоподстановка суффикса при ручном вводе намеренно не делается: молча переименовывать введённое человеком хуже, чем отказать. - Фильтр и сортировка по источнику во вкладке «Алиасы». Добавлен выпадающий список «Все источники» рядом с фильтром по ключу и сортировка по колонке «Источник».
Внимание при обновлении: заголовки страниц с диапазоном изменятся
Страницы, отфильтрованные по диапазону, раньше не подбирали SEO-шаблон вовсе и генерировали заголовок по умолчанию. Теперь шаблон, настроенный на базовый ключ (price), к ним применяется — h1, title и description таких страниц изменятся, в том числе у уже проиндексированных.
Правила индексации изменились в одну сторону: диапазон теперь считается одним фильтром, а не двумя. Раньше страница «цена от–до плюс бренд» давала три ключа при дефолтном mfilter.seo_max_filters = 2 и закрывалась от индексации; теперь это два фильтра, и страница открыта. Служебный сегмент URL, который не удалось разобрать, тоже перестал считаться фильтром.
Вместе с noindex переезжает и canonical: у закрытой страницы он указывал на раздел без фильтров, у открытой указывает на неё саму. Для затронутых страниц это смена цели canonical — сам вид адресов при этом не менялся.
Подсчёт значений внутри фильтра по-прежнему идёт по исходным границам: свёрнутый диапазон выглядел бы двумя значениями и при mfilter.seo_max_values = 1 закрывал бы каждую такую страницу.
Внимание при обновлении: класс mfilter-pagination — на обёртке
Класс объявлен контрактом контейнера, в который вставляется {$pagination}, и снят с ` внутри стандартного чанка пагинации. Затрагивает сайты со своимtplOuter` без этого класса, полагавшиеся на класс из стандартного чанка: после обновления AJAX перестанет обновлять блок пагинации, ссылки продолжат работать обычной перезагрузкой. Лечится переносом класса на контейнер.
Стандартные чанки при обновлении не перезаписываются, поэтому правки mfilter.form и mfilter.pagination доходят только до новых установок. Существующим сайтам делать ничего не нужно — прежняя разметка поддержана.
Отдельно про блок «Выбрано»: исправление, из-за которого он сбрасывался на стандартные чанки на странице с одним диапазоном, опирается на атрибут data-mfilter-selected-hash в tplOuter. У сайта со своим чанком без этого атрибута дефект сохранится — атрибут нужно добавить вручную, как описано в разделе про серверный рендер блока.
Внимание при обновлении: изменятся URL категорий MS3 и производителей
До этой версии слаги для фильтров «Категории товаров (MS3)» (ms3_category, ms3_categories) и «Производители» (vendor, vendors, ms|vendor) не подставлялись в адрес: UrlBuilder видел числовое значение и отдавал его как есть. Адреса выглядели так:
/catalog/ms3_categories--61/
/catalog/vendor--17/
Теперь эти типы объявляют, что их значения — идентификаторы, слаги подхватываются, и те же страницы получают человекочитаемые адреса:




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