FacetWP: полное руководство по фильтрам для WordPress — установка, листинги, мобильная версия
Полная практическая инструкция по FacetWP: от установки плагина до мобильных фильтров, индексации и диагностики. Годится как регламент для сотрудников на любом проекте.

Для кого: для владельца проекта и для сотрудников, которые будут ставить фильтры на новых сайтах. Что даёт: после прочтения человек с нуля ставит рабочие фильтры (каталог товаров, курсов, статей, объектов) на любом WordPress-сайте, включая мобильную версию, и понимает, почему фильтры иногда «слетают» и как это лечить.
Версия материала: FacetWP 4.5, WordPress 6.8, проверено на живом проекте (каталог курсов Tutor LMS).
1. Что такое FacetWP и когда он нужен
FacetWP — плагин фильтрации контента для WordPress. Он не «ищет» по сайту, а пересобирает уже существующий список записей по выбранным условиям: рубрика, метка, цена, произвольное поле, дата, автор, наличие.
Он нужен, когда:
- есть каталог (товары, курсы, объекты, вакансии, статьи) от 30 позиций;
- нужно фильтровать без перезагрузки страницы;
- нужны счётчики («Вебинары (52)») и понятная пагинация.
Он не нужен, когда:
- список короткий и достаточно рубрик;
- нужен полнотекстовый поиск по всему сайту (это задача поискового плагина, хотя у FacetWP есть фасет типа Search для поиска внутри листинга).
Главное преимущество: FacetWP работает через свой индекс в базе, поэтому фильтрация быстрая даже на нескольких тысячах записей.
2. Ключевые понятия
Запомнить три слова — дальше всё логично.
Фасет (Facet) — один фильтр. Например «Рубрики», «Цена», «Город», «Поиск». Каждый фасет имеет свой шорткод: .
Листинг (Listing) — сам список карточек, который фильтруется. Создаётся в конструкторе FacetWP и выводится шорткодом . Вместо листинга можно использовать существующий цикл темы, но это сложнее и ломается при обновлениях темы — на новых проектах всегда делайте листинг в конструкторе FacetWP.
Индекс (Index) — таблица wp_facetwp_index, куда плагин заранее складывает все значения всех фасетов для всех записей. Если индекс пустой или устарел — фильтры показывают ноль результатов или неверные счётчики. 90% проблем с FacetWP — это проблемы индекса.
Логика работы: пользователь щёлкает фасет → JS отправляет AJAX-запрос → FacetWP берёт из индекса ID подходящих записей → подставляет их в запрос листинга → возвращает готовый HTML карточек и новые счётчики.
3. Установка и лицензия
- Купить лицензию на facetwp.com (плагин платный, бесплатной версии нет).
- Скачать zip в личном кабинете, поставить: Плагины → Добавить новый → Загрузить плагин, активировать.
- Ввести ключ: Настройки → FacetWP → Settings → License.
- Дополнения (Add-ons) устанавливаются отдельными zip-файлами с того же кабинета. Полезные: — Flyout — выезжающая панель фильтров для мобильной версии (обязательно берите); — Conditional Logic — показывать фасет только при определённом выборе; — Range List — готовые диапазоны цен; — Map Facet — фильтр по карте.
Важно про лицензию: если ключ не активен, уже установленные дополнения продолжают работать, но обновления и поддержка недоступны. Не оставляйте проект на просроченной лицензии дольше, чем нужно — при обновлении WordPress несовместимость придётся лечить руками.
4. Шаг 1. Создаём листинг
FacetWP → Listings (Листинги) → Add new.
- Name — техническое имя, латиницей:
courses,products,articles. Оно попадёт в шорткод. - Переключатель режима: Visual (визуальный конструктор) или Dev/Advanced (PHP-шаблон). Всегда начинайте с Visual. PHP-режим берите только если карточку невозможно собрать блоками.
- Query — что выводим: —
Post type— тип записей (post,product,courses, свой CPT); —Status—publish; —Posts per page— сколько карточек на страницу (например 24 или 42); —Order by— сортировка (post_date DESC,menu_order ASC,meta_value_num); — дополнительные фильтры (только определённая рубрика, только с картинкой и т.д.). - Layout — собираем карточку. Структура: строка (row) → колонки (col) → элементы (item). Типовая карточка каталога: — Featured image — размер
medium_large, включитьLink to post, CSS-классcard-thumb; — Post title — включитьLink to post, классcard-title; — Post excerpt — ограничение по числу слов, классcard-desc; — при необходимости Custom field (cf/price) с префиксом/суффиксом («от », « ₽»); — кнопка: элемент Post title с текстом-заменой или элемент типа Button со ссылкой на запись. - Настройки строки (row settings) — здесь живёт сетка: —
Number of grid columns— количество колонок (3 для каталога курсов/товаров); —Grid gap— отступ между карточками (например 24px). - Сохранить.
Проверка: на этом этапе листинг уже можно вывести шорткодом и увидеть карточки без фильтров.
5. Шаг 2. Создаём фасеты
FacetWP → Facets → Add new. Для каждого фильтра — свой фасет.
Общие поля: Label (что видит пользователь), Name (латиницей, попадёт в шорткод), Facet type (тип), Data source (откуда брать значения).
Основные типы и когда их брать
| Тип | Что делает | Где применять |
|---|---|---|
| Checkboxes | галочки, множественный выбор | рубрики, метки, бренды |
| Radio | один вариант | «кому подходит», статус |
| Dropdown | список | города, категории с длинным списком |
| Search | поиск внутри листинга | строка «Поиск по каталогу» |
| Slider / Number range | диапазон | цена, площадь, длительность |
| Date range | период | события, архив |
| Pager | пагинация | всегда в каталоге |
| Sort | смена сортировки | «сначала новые / дешевле» |
| Reset | сброс всех фильтров | всегда |
| Hierarchy | вложенные рубрики | большие каталоги |
Важные настройки фасета
- Data source —
Taxonomies / Категории,Custom fields / cf/price,Posts / post_title. Для ACF-поля выбирайте его в спискеcf/имя_поля. - Behavior (AND / OR) — как складываются галочки внутри одного фасета.
OR— «или то, или то» (обычно нужен для рубрик),AND— «и то, и то» (для характеристик). - Show counts — показывать число результатов у каждого варианта. Включайте: это резко повышает удобство.
- Hide when empty — скрывать варианты, по которым ничего не найдено.
- Soft limit — показать 5–8 значений и ссылку «Показать все».
- Ghosts — показывать недоступные варианты серым (обычно выключено).
- Sort by — порядок значений: по количеству, по алфавиту, по порядку в таксономии.
Пример реального набора для каталога обучающих продуктов:
course_search— Search, «Поиск по программам»;course_category— Checkboxes по рубрикам, OR, счётчики включены;course_tag— Checkboxes по метке «кому подходит», OR;course_pager— Pager, режимNumbers, по 12 страниц в блоке;course_reset— Reset, текст «Сбросить фильтры».
6. Шаг 3. Выводим всё на страницу
Создайте страницу каталога (например «Программы») и вставьте шорткоды.
[facetwp facet="course_search"]
[facetwp facet="course_category"]
[facetwp facet="course_tag"]
[facetwp facet="course_reset"]
[facetwp template="courses"]
[facetwp facet="course_pager"] Правила, которые нарушают чаще всего:
- Шорткод листинга обязателен на странице. Без
фасеты «не знают», что фильтровать, и молча ничего не делают. - Один листинг на страницу. Два листинга FacetWP на одной странице конфликтуют.
- Фасеты можно ставить и до, и после листинга — порядок в вёрстке не важен для логики.
- Для горизонтальной панели фильтров сверху просто оберните фасеты в блок-колонки темы; отдельный сайдбар не нужен.
Если нужно фильтровать существующий цикл темы
Тогда в листинге выбирается режим Dev и в шаблоне темы у WP_Query добавляется:
$args['facetwp'] = true; а сам цикл оборачивается в <div class="facetwp-template">. Это рабочий, но хрупкий путь: при обновлении темы или плагина каталога разметка меняется и фильтры перестают находить список. Именно так фильтры «слетают» на многих проектах. Штатный листинг FacetWP от таких обновлений не зависит — используйте его.
7. Шаг 4. Индекс
Настройки → FacetWP → Indexer → Re-index.
Как он работает:
- индекс пересобирается автоматически при сохранении записи;
- полная переиндексация запускается вручную кнопкой или через WP-CLI:
wp facetwp index; - прогресс виден в панели; на больших каталогах процесс идёт частями.
Когда переиндексация обязательна:
- после создания или изменения фасета;
- после массового импорта записей;
- после смены источника данных (Data source);
- после переноса сайта на другой домен/сервер.
Полезные настройки индекса:
Enable indexer— должно быть включено;Index all post statuses— обычно выключено (индексируем только published);- увеличить
Indexer chunk size, если процесс падает по таймауту на shared-хостинге.
Признаки сломанного индекса: фасеты показывают «(0)» у всех значений, фильтр даёт пустой результат, счётчики не совпадают с реальностью. Лечение: Re-index, затем сброс кэша.
Страховка для больших проектов — ежедневная задача по расписанию, которая проверяет, что индекс не пустой, и при необходимости запускает переиндексацию.
8. Сетка карточек: три колонки штатно
Не пишите CSS для сетки. Это делается настройкой:
- FacetWP → Listings → ваш листинг;
- режим Visual;
- настройки строки:
Number of grid columns = 3,Grid gap = 24.
По умолчанию конструктор добавляет один брейкпоинт: при ширине экрана 480px и меньше сетка становится одноколоночной. Если нужны промежуточные шаги (2 колонки на планшете) — только тогда добавляется CSS:
@media (max-width: 1024px) and (min-width: 481px) {
.facetwp-template .fwpl-row { grid-template-columns: repeat(2, 1fr); }
} Почему именно так: если сетка собрана вручную в CSS темы или в сниппете, любое отключение этого сниппета (или переезд на другую тему) ломает вид каталога, и никто потом не может найти причину. Настройка внутри листинга переживает и обновления темы, и чистку сниппетов.
Ограничение описания по строкам
Единственный уместный CSS для карточки — обрезка описания, чтобы карточки были одной высоты:
.card-desc {
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
} Класс card-desc задаётся элементу в конструкторе (поле CSS class).
9. Мобильная версия
Три штатных варианта — по возрастанию удобства.
Вариант A. Просто скрыть часть фасетов
В CSS скрываете на мобильных второстепенные фасеты. Быстро, но пользователь теряет фильтры. Не рекомендуется.
Вариант B. Своя кнопка «Фильтры» со сворачиванием
Обёртка фасетов получает класс, кнопка переключает его:
<button class="filters-toggle" aria-expanded="false">Фильтры <span class="filters-count"></span></button>
<div class="filters-panel">
[facetwp facet="course_category"]
[facetwp facet="course_tag"]
</div> @media (max-width: 780px) {
.filters-panel { display: none; }
.filters-panel.is-open { display: block; }
}
@media (min-width: 781px) { .filters-toggle { display: none; } } Счётчик выбранных фильтров берётся из состояния FacetWP:
document.addEventListener('facetwp-loaded', function () {
var n = 0;
Object.values(FWP.facets || {}).forEach(function (v) { if (v && v.length) n += v.length; });
document.querySelector('.filters-count').textContent = n ? '(' + n + ')' : '';
}); Вариант C (рекомендуемый). Дополнение Flyout
Официальное дополнение FacetWP: фильтры уезжают в выезжающую панель, на странице остаётся одна кнопка.
- Установить и активировать плагин FacetWP – Flyout.
- Настроить: Настройки → FacetWP → Flyout — какие фасеты попадают в панель, ширина, позиция (слева/справа), точка включения по ширине экрана.
- Кнопку открытия можно вывести своей вёрсткой, добавив класс
facetwp-flyout-open:
<button class="facetwp-flyout-open" aria-haspopup="dialog">Фильтры</button> Тонкая настройка через хуки (в дочерней теме или сниппете):
// какие фасеты показывать внутри выезжающей панели
add_filter('facetwp/flyout/facets', function ($facets) {
unset($facets['course_search']); // поиск оставляем на самой странице
return $facets;
}); Практические рекомендации:
- поиск не прячьте в панель — он нужен сразу;
- внутрь панели добавьте кнопку сброса;
- на десктопе кнопку «Фильтры» скрывайте, панель фильтров показывайте обычным блоком.
10. Кнопка «Сбросить фильтры»
Два способа.
Штатный фасет Reset — создать фасет типа Reset и вывести шорткодом. Работает всегда, ничего программировать не нужно.
Своя кнопка — обязательно через API FacetWP, а не «очисткой URL»:
document.addEventListener('click', function (e) {
if (!e.target.closest('.my-reset')) return;
e.preventDefault();
FWP.reset(); // снимает выбор и перезагружает листинг
}); Частая ошибка: обработчик кнопки живёт в сниппете/скрипте, который потом отключают, — кнопка остаётся на странице, но перестаёт работать. Держите обработчик там же, где вёрстка кнопки, или используйте штатный фасет Reset.
11. Нестандартные типы записей
Свой CPT (курсы, объекты, вакансии)
В листинге в Post type выберите свой тип. Если типа нет в списке — он зарегистрирован с public => false или exclude_from_search => true; поправьте регистрацию типа.
WooCommerce
- Post type:
product; - фасеты по атрибутам: Data source →
Taxonomies → pa_размери т.п.; - цена: фасет Slider, Data source →
cf/_price; - наличие: фасет Checkboxes по
cf/_stock_status; - в настройках FacetWP включите
WooCommerce support.
ACF
Поля доступны как cf/имя_поля. Для repeater и flexible content индексируются вложенные ключи — при необходимости используйте хук facetwp_index_row для нормализации значений.
LMS-плагины (Tutor LMS, LearnDash)
Здесь чаще всего и возникают «слетающие фильтры»: плагин курса выводит свой цикл и свою разметку. Правильное решение — не цепляться к циклу плагина, а собрать свой листинг FacetWP по типу записей курсов. Тогда обновление LMS-плагина на фильтры не влияет.
12. Кэш, CDN и почему фильтры «слетают»
FacetWP работает через AJAX, а значит конфликтует с агрессивным кэшем и оптимизаторами.
Обязательные меры:
- Не кэшировать AJAX-запросы FacetWP. В кэш-плагине исключите
/?fwpи админский AJAX. - Не объединять и не откладывать скрипты FacetWP. В оптимизаторах (Autoptimize, LiteSpeed, WP Rocket, Perfmatters) добавьте
facetwpв исключения для combine/defer/delay JS. Симптом нарушения: в консоли браузераInvalid or unexpected token, фильтры визуально есть, но не работают. - Ассеты грузить всегда на странице каталога. Если тема подключает скрипты условно, добавьте:
add_filter('facetwp_load_assets', function ($load) {
if (is_page('programs')) $load = true;
return $load;
}); - Сбрасывать кэш после правок каталога и фасетов. Иначе пользователь видит старую разметку с новым JS — и ничего не работает.
- Осторожно с CDN-оптимизацией HTML (Cloudflare Rocket Loader, Mirage): Rocket Loader ломает FacetWP, отключайте.
Чек-лист «фильтры перестали работать после обновления»:
- листинг в режиме Dev и зацепился за разметку темы/плагина → перевести на визуальный листинг;
- оптимизатор снова включил объединение JS → вернуть исключение;
- индекс пустой → Re-index;
- сетка/кнопки жили в отключённом сниппете → перенести настройку в листинг FacetWP.
13. Диагностика: 10 проверок по порядку
- На странице есть шорткод листинга
? Один, а не два? - Фасеты выведены правильными именами (Name, не Label)?
- Настройки → FacetWP → Indexer: индекс не пустой? Дата последней индексации свежая?
- Консоль браузера: есть ошибки JS?
Invalid or unexpected token= оптимизатор портит скрипт. - Вкладка Network: при клике по фильтру уходит запрос
admin-ajax.php?action=facetwp_refreshи возвращает 200 с JSON? - В ответе JSON есть
templateс карточками иsettingsсо счётчиками? - Число карточек меняется при фильтрации? Если нет — листинг не связан с запросом (режим Dev, разметка сломана).
- Кэш сброшен? Проверьте в приватном окне.
- Плагины кэша/оптимизации отключены на время теста — стало работать? Значит дело в исключениях.
- Мобильная версия: панель Flyout активна, кнопка открытия имеет класс
facetwp-flyout-open?
Полезные хуки для отладки:
// посмотреть итоговый запрос
add_action('facetwp_query_args', function ($args) { error_log(print_r($args, true)); return $args; }); 14. Чего делать нельзя
- Нельзя строить сетку карточек и логику фильтров в CSS темы или в случайных сниппетах: при чистке проекта это исчезает, и никто не найдёт причину.
- Нельзя дублировать листинги: два листинга на странице = неработающие фильтры.
- Нельзя привязываться к разметке чужого плагина/темы, если можно собрать свой листинг.
- Нельзя оставлять кастомный JS, который дублирует штатное поведение (сброс, поиск, пагинация) — используйте фасеты Reset, Search, Pager.
- Нельзя править файлы плагина FacetWP: всё настраивается через фасеты, листинг и хуки.
15. Порядок внедрения на новом проекте
Печатный чек-лист для сотрудника.
- Поставить плагин, активировать лицензию.
- Поставить дополнение Flyout (для мобильных фильтров).
- Создать листинг: имя латиницей, режим Visual, тип записей, сортировка, число на странице.
- Собрать карточку: обложка со ссылкой, заголовок со ссылкой, описание, при необходимости цена/кнопка.
- В настройках строки задать
Number of grid columnsиGrid gap. - Создать фасеты: Search, рубрики (Checkboxes, OR, счётчики), доп. признак, Pager, Reset.
- Создать страницу каталога и вставить шорткоды фасетов и листинга.
- Запустить полную переиндексацию.
- Настроить Flyout: какие фасеты в панели, ширина, точка включения; кнопка с классом
facetwp-flyout-open. - Добавить исключения в кэш и оптимизатор JS (
facetwp,/?fwp), при необходимостиfacetwp_load_assets. - Добавить CSS только на обрезку описания и оформление кнопок-фильтров.
- Проверить: десктоп (фильтр, поиск, сброс, пагинация), мобильный (панель, фильтр, сброс), приватное окно после сброса кэша, консоль без ошибок.
- Зафиксировать в документации проекта: имя листинга, имена фасетов, где лежит CSS, какие исключения добавлены в кэш.
Приложение. Шпаргалка по шорткодам и хукам
[facetwp facet="имя_фасета"] вывод фильтра
[facetwp template="имя_листинга"] вывод списка карточек
[facetwp counts] «Показано 1–12 из 99»
[facetwp selections] плашки выбранных фильтров
[facetwp sort="имя_фасета"] сортировка facetwp_load_assets // принудительно грузить скрипты
facetwp_query_args // изменить запрос листинга
facetwp_index_row // изменить значение при индексации
facetwp_facet_display_value// изменить подпись значения
facetwp/flyout/facets // состав выезжающей панели
facetwp/flyout/open // добавить своё содержимое в панель FWP.facets // текущее состояние фильтров
FWP.refresh() // перезагрузить результаты
FWP.reset() // сбросить все фильтры
document.addEventListener('facetwp-loaded', fn) // после каждой загрузки wp facetwp index # полная переиндексация из консоли 
