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

SEO шаблоны ​

SEO-шаблон — правило, по которому собираются title, H1, description и текст для подборки с применённым фильтром. Одно правило работает на всех значениях фильтра: SEO-шаблон для ключа made_in даёт заголовок и для «Германии», и для любой другой страны.

Создание SEO-шаблона ​

mFilter → SEO шаблоны → Добавить.

ПолеЧто задаёт
НазваниеТолько для списка в админке
СтраницаSEO-шаблон действует на этой странице. Пустое поле — глобальный SEO-шаблон, на всех страницах
Ключи фильтровОбязательное. Ключи, при которых SEO-шаблон срабатывает: made_in, color. Вводятся по одному, через Enter
Шаблон H1Заголовок страницы
Шаблон TitleТег <title>
Шаблон DescriptionМета-описание
Шаблон текстаSEO-текст под выдачей
ПриоритетРазрешает ничью между SEO-шаблонами. Меньше — раньше. От 0 до 100
АктивенВыключенный SEO-шаблон не участвует в подборе

SEO-шаблон без ключей фильтров не сохранится. Запись, попавшая в базу в обход админки, не сработает никогда. «SEO-шаблона на всё» не существует: роль запасного варианта играет поведение без SEO-шаблона.

Как подбирается SEO-шаблон ​

SEO-шаблоны делятся на два вида. С заполненным полем «Страница» шаблон страничный — он срабатывает только на ней. С пустым — глобальный, годится для любой страницы каталога; в списке такие помечены меткой «Глобальный».

Ключи выбранных фильтров сравниваются с полем «Ключи фильтров» в четыре прохода. Первый подошедший SEO-шаблон и применяется:

  1. SEO-шаблоны этой страницы, у которых набор ключей совпал точно;
  2. SEO-шаблоны этой страницы, у которых совпал хотя бы один ключ;
  3. глобальные SEO-шаблоны с точным совпадением;
  4. глобальные SEO-шаблоны с совпадением хотя бы одного ключа.

Порядок проходов важнее приоритета: страничный SEO-шаблон обойдёт глобальный, а точное совпадение — частичное. Приоритет решает только, какой из SEO-шаблонов взять, когда в одном проходе подошли несколько.

Из-за частичного совпадения SEO-шаблон для made_in применится и к странице, где выбраны made_in и color. Чтобы у такой пары был свой заголовок, заведите SEO-шаблон с обоими ключами — он выиграет на первом проходе.

Если SEO-шаблон не подобран ​

Заголовки собираются из названия страницы и выбранных значений:

  • H1 — «Название страницы - Значения»;
  • Title — то же плюс « | Название сайта»;
  • Description — описание страницы плюс те же значения.

Значения подставляются подписями: раздел каталога — своим названием, производитель MiniShop3 — именем, числовое значение TV — подписью из индекса.

Плейсхолдеры ​

Значения фильтров ​

Значение подставляется по ключу фильтра, без префикса. Именно по ключу, а не по полю, из которого фильтр берёт данные: у фильтра {"brand": {"field": "product_brand"}} в SEO-шаблоне пишется {$brand}.

ПлейсхолдерЧто подставит
{$made_in}Все выбранные значения через запятую
{$made_in_first}Только первое значение
{$made_in_count}Сколько значений выбрано

Диапазон приходит одним значением, а не двумя границами: {$price} даст «1000 — 5000», а при одной границе — «от 1000» или «до 5000». Слова и тире берутся из лексикона mfl_seo_range_from, mfl_seo_range_to, mfl_seo_range_separator.

Производители и разделы подставятся числом

Плейсхолдер выводит то значение, которое хранит фильтр. У цвета, размера, страны производства это текст. А у производителей MiniShop3, разделов каталога, категорий товаров и TV со списком ресурсов значение — идентификатор: {$vendor_id} поставит в заголовок 12, а не «Acme».

Заголовок, который mFilter собирает без SEO-шаблона, те же значения подставляет названиями. Поэтому для таких ключей SEO-шаблон пока даёт результат хуже стандартного — оставьте их без SEO-шаблона или напишите индивидуальную запись.

Поля страницы и сайта ​

ПлейсхолдерЧто подставит
{$pagetitle}, {$longtitle}, {$menutitle}, {$introtext}, {$id}, {$alias}…Любое поле ресурса под своим именем
{$<имя TV>}Значение TV этой страницы
{$site_name}Название сайта — единственная системная настройка, доступная в SEO-шаблоне

Запись через точку

SEO-шаблоны, написанные по прежней версии документации, обращались к полям через точку: {$resource.pagetitle}, {$filters.vendor_id}. Такая запись работает и даёт то же, что {$pagetitle} и {$vendor_id}. Уровень вложенности — один: {$filters.vendor_id.gen} останется в заголовке как текст, падеж пишется как {$vendor_id.gen}. {$resource} и {$filters} целиком подставляются пустым местом.

Имена берутся в таком порядке: сначала поля ресурса, затем TV, затем значения фильтров. Последние записываются поверх, поэтому ключ фильтра, совпадающий с именем поля или TV — description, parent, id, — перекроет его.

Числа найденных товаров в SEO-шаблоне нет

SEO собирается в самом начале запроса, когда выборка ещё не сделана, поэтому подставить в заголовок количество найденного нечем. Число появляется позже: его выставляет сниппет mFilter, а выводит чанк обёртки — строкой «Найдено: N». В шаблоне ресурса оно доступно как {$_pls['mfilter.total']}, но только ниже вызова сниппета.

Модификаторы ​

Модификатор пишется через точку после ключа: {$made_in.gen}.

Падежи ​

МодификаторПадеж
.nomИменительный
.genРодительный
.datДательный
.accВинительный
.insТворительный
.preПредложный

Множественное число — те же имена с суффиксом: .gen_plural, .dat_plural и так далее.

Формы берутся из Словоформ. Если слова там нет, подставится исходное значение — без ошибки и без записи в лог.

Склоняется одно значение. Если выбрано несколько, {$color} — это строка «красный, синий», словоформы для неё нет, и {$color.gen} выведет её в именительном падеже. Для падежа берите первое значение: {$color_first.gen}.

Обработка текста ​

МодификаторЧто делает
.lower, .upperНижний и верхний регистр
.ucfirst, .lcfirstПервая буква заглавная или строчная
.stripУбирает HTML-теги
.trimУбирает пробелы по краям
.escapeЭкранирует кавычки и угловые скобки

Неизвестный модификатор ошибки не вызывает — значение подставится как есть. Поэтому опечатка в {$made_in.gne} выглядит как «падеж не применился».

Условия ​

Блок {if $ключ}…{/if} выводит содержимое, только когда значение непустое:

{$pagetitle} {if $color}цвета {$color.gen}{/if}

Ветка {else} выводится, когда значение пустое. Она нужна SEO-шаблону, который подобран по частичному совпадению ключей: SEO-шаблон для color и made_in применится и к странице, где выбрана только страна.

{$pagetitle} {if $color}цвета {$color.gen}{else}всех цветов{/if}

Внутри блока работают те же плейсхолдеры и модификаторы, блоки можно вкладывать друг в друга. Незакрытый блок или второй {else} в одном блоке выводятся как текст — так ошибку видно в заголовке.

Пробелы

Перед сборкой парсер заменяет подряд идущие пробелы и переносы строк одним пробелом, а края всего текста обрезает. Пробелы внутри ветки остаются как написаны: {$pagetitle}{if $color} — {$color}{/if} даст «Диваны — синий». Разметку многострочного SEO-текста это не портит, но пустые строки между абзацами исчезнут — разделяйте абзацы тегами.

Примеры SEO-шаблонов ​

Страна производства ​

Ключи фильтров: made_in

Title: Товары из {$made_in.gen} — купить в {$site_name}
H1: Товары из {$made_in.gen}
Description: Товары из {$made_in.gen} в наличии. Доставка по всей России.

Страна и цвет ​

Ключи фильтров: made_in, color

Title: Товары из {$made_in.gen} {$color.gen} цвета | {$site_name}
H1: Товары из {$made_in.gen}, {$color.gen} цвета

Диапазон цен ​

Ключи фильтров: price

Title: {$pagetitle} {$price} рублей
H1: {$pagetitle}, {$price}

Индексация ​

Поля «не индексировать» у SEO-шаблона нет: страницы закрываются системными настройками.

НастройкаПо умолчаниюЧто делает
mfilter.seo_noindex_filteredНетЗакрывает все отфильтрованные страницы разом
mfilter.seo_max_filters2Закрывает страницу, где выбрано больше указанного числа фильтров
mfilter.seo_max_values1Закрывает страницу, где у одного фильтра выбрано больше указанного числа значений

Диапазон считается одним фильтром, хотя в адрес попадает двумя границами. Значения же считаются внутри каждого ключа отдельно, а у границы значение одно — поэтому seo_max_values диапазон не закрывает даже при лимите в единицу.

Индивидуальная запись снимает закрытие: страница, для которой её написали, индексируется, даже если попала под лимиты. Настройка mfilter.seo_noindex_filtered сильнее — она закрывает страницу и при заполненной записи.

Canonical ​

Адрес вычисляется, в SEO-шаблоне его не задают.

  • Открытая для индексации страница получает canonical на саму себя — отфильтрованный адрес без номера страницы, сортировки и лимита;
  • закрытая — canonical на страницу без фильтров.

Адрес всегда абсолютный.

Программный доступ ​

php
$mfilter = $modx->services->get('mfilter');
$seoBuilder = $mfilter->getSeoBuilder();

$seoData = $seoBuilder->build($resourceId, $filters);
// [
//     'h1' => 'Товары из Германии',
//     'title' => 'Товары из Германии — купить в Название сайта',
//     'description' => 'Товары из Германии в наличии...',
//     'text' => '<p>SEO текст...</p>',
//     'canonical' => 'https://site.ru/catalog/made_in--germaniya/',
//     'noindex' => false
// ]

Для несуществующего ресурса build() вернёт пустой массив.

МетодЧто делает
shouldNoindex(array $filters): boolПопадает ли набор фильтров под лимиты индексации
getCanonical(int $resourceId, array $filters): stringCanonical для набора фильтров
clearCache(): voidСбрасывает кэш загруженных SEO-шаблонов

Вывод на фронтенде ​

Плейсхолдеры mfilter.seo.* расставляет плагин на каждой странице фильтрации; в Fenom они доступны через массив $_pls. Вне фильтрации значения пустые, у noindex — false.

Вставьте в шаблон ресурса каталога (<head> и <body>):

html
<title>{$_pls['mfilter.seo.title'] ?: $_modx->resource.pagetitle}</title>
<meta name="description" content="{$_pls['mfilter.seo.description'] ?: $_modx->resource.description}">

{if $_pls['mfilter.seo.canonical']}
    <link rel="canonical" href="{$_pls['mfilter.seo.canonical']}">
{/if}

{if $_pls['mfilter.seo.noindex']}
    <meta name="robots" content="noindex, follow">
{/if}

<h1 data-mfilter-h1>{$_pls['mfilter.seo.h1'] ?: $_modx->resource.pagetitle}</h1>

<div data-mfilter-seo-text{if !$_pls['mfilter.seo.text']} style="display:none"{/if}>
    {$_pls['mfilter.seo.text']}
</div>

Маркеры для AJAX

Атрибуты data-mfilter-h1 и data-mfilter-seo-text (или классы h1.mfilter-h1 и .mfilter-seo-text) обязательны: без них JS не найдёт элементы при AJAX-фильтрации, и они обновятся только после F5. Класс mfilter-h1 срабатывает только на теге <h1> — на другом теге нужен атрибут. Меты title, description, canonical, robots в <head> JS обновляет по стандартным селекторам — маркеры не нужны.

После обновления JS вызывает событие mfilter:seoUpdate — его можно слушать, если на странице есть свои элементы с SEO-данными.

Когда SEO-шаблон не нужен ​

SEO-шаблон описывает правило для всех значений сразу. Если текст нужен под одну конкретную подборку — свой заголовок и описание для определённого бренда, — правило заводить не обязательно: такая страница настраивается поштучно на вкладке Индивидуальные SEO.

Одно другому не мешает. Заполненные поля индивидуальной записи перекрывают SEO-шаблон, незаполненные берутся из него: правило закрывает массу страниц, а руками пишется то, ради чего стоит сесть за текст.