Содержание
Для удобного поиска постов по категориям решено создать алфавитную навигацию. К сожалению, WordPress изначально не имеет такого функционала, но поскольку я являюсь разработчиком тем и плагинов, то напишу подробно, как был создан этот полезный элемент.
Статья обновлена, код приведён в соответствие со стандартами WordPress Codex, проходит проверку плагинами Theme Sniffer и Theme Check.
Приведённые примеры будут совместимы со стандартной структурой шаблонов WP, которой соответствует популярная стартовая тема Underscores. Вёрстка стилей подходит под Фреймворк Twitter Bootstrap 4. Как подключить Bootstrap к сайту на WordPress через CDN смотрите здесь.
Суть работы модуля заключается в добавлении к URL параметра GET при помощи функции add_query_arg()
, значением которого является буква латинского алфавита. Когда параметр установлен, его можно использовать для фильтрации основного потока записей main_query
, что позволит сохранить работоспособность постраничной навигации. На данном сайте это применимо ко всем рубрикам главной страницы. Навигация с алфавитом будет вверху каждой категории.
Каждый этап в примерах
Создадим функцию, которая отвечает за фильтрацию каждой отдельной буквы.
Можно добавить данный код в самый конец файла functions.php вашей темы WP:
/**
* Функция для изменения части WHERE запроса SQL.
*
* @param string $where Предложение WHERE запроса.
* @return string Изменённый WHERE запрос.
*/
function os_restrict_by_first_letter( $where ) {
// Условие проверяет наличие GET запроса с параметром 'az'.
if ( isset( $_GET['az'] ) ) {
// Глобализация переменной $wpdb.
global $wpdb;
// Изменения касаются только страниц архива.
if ( ! is_tag() && ! is_date() && is_archive() && is_main_query() ) {
// Устанавливается значение из параметра 'az'.
$where .= $wpdb->prepare( " AND SUBSTRING( {$wpdb->posts}.post_title, 1, 1 ) = %s ", sanitize_text_field( wp_unslash( $_GET['az'] ) ) );
}
}
// Возвращаются изменённые данные.
return $where;
}
// Установка фильтра для хука 'posts_where'.
add_filter( 'posts_where', 'os_restrict_by_first_letter' );
Первым делом необходимо проверить наличие параметра $_GET['az']
в глобальном массиве. Из него мы получаем букву, которую добавляем в SQL запрос. Этот запрос фильтрует записи по первой букве каждого заголовка и тем самым изменяет main_query
на страницах архивов. Метод prepare
выполняет защиту запроса от SQL инъекций. Отфильтрованные данные функция возвращает в специальный хук posts_where
.
Теперь на страницах категорий к URL можно добавить значение такого вида, как по ссылке ниже:
https://onstartup.ru/gnome/?az=n
«n» – это та буква, по которой фильтруются записи. Нужно отметить, что пагинация при этом остаётся работоспособной с учётом применённого фильтра, а количество страниц будет соответствовать выборке.
Осталось только сформировать эти параметры и их значения. Для начала приведу упрощённый рабочий вариант, думаю, многим его будет достаточно.
В файл archive.php добавим следующий код:
<?php if ( ! is_tag() && ! is_date() ) : ?>
<nav aria-label="Alphabet" class="mb-4">
<ul class="pagination pagination-sm flex-wrap justify-content-center">
<?php
// Определяем текущую категорию.
$the_cat_id = get_queried_object_id();
// Формируем массив из списка букв от 'a' до 'z'.
$az_range_arr = range( 'a', 'z' );
foreach ( $az_range_arr as $letter ) :
?>
<li class="page-item"><a class="page-link text-uppercase" href="<?php echo esc_url( add_query_arg( 'az', $letter, get_category_link( $the_cat_id ) ) ); ?>"><?php echo esc_html( $letter ); ?></a></li>
<?php
endforeach;
?>
<li class="page-item"><a class="page-link text-uppercase" href="<?php echo esc_url( get_category_link( $the_cat_id ) ); ?>">Все</a></li>
</ul>
</nav>
<?php endif; ?>
Подсветка активных и неактивных кнопок навигации
Рассмотрим пример с неактивными буквами, которые отсутствуют в данной рубрике. Активная буква списка будет подсвечена:
<?php if ( ! is_tag() && ! is_date() ) : ?>
<nav aria-label="Alphabet" class="mb-4">
<ul class="pagination pagination-sm flex-wrap justify-content-center">
<?php
// Определяем текущую категорию.
$the_cat_id = get_queried_object_id();
// Задаём массив параметров для пользовательского запроса WP_Query.
$args_az = array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1,
'category' => $the_cat_id,
);
// Запрос WP_Query функцией get_posts().
$query_az = get_posts( $args_az );
// Перебираем каждый заголовок записи, отобрав первую букву в массив '$all_titles_arr'.
$all_titles_arr = array();
foreach ( $query_az as $post_az ) :
setup_postdata( $post_az );
$the_title = get_the_title( $post_az->ID );
$all_titles_arr[] = mb_strtolower( mb_substr( $the_title, 0, 1, 'UTF-8' ) );
endforeach;
wp_reset_postdata();
// Формируем массив из списка букв от 'a' до 'z'.
$az_range_arr = range( 'a', 'z' );
// Подготовка различных классов для подсветки кнопок навигации.
foreach ( $az_range_arr as $letter ) :
$letter_status = '';
// Существует ли данная буква в массиве 'all_titles_arr'.
if ( ! in_array( $letter, $all_titles_arr, true ) ) :
$letter_status .= ' disabled';
endif;
// Совпадает ли буква с текущим параметром GET массива.
if ( isset( $_GET['az'] ) && $letter === $_GET['az'] ) :
$letter_status .= ' active';
endif;
?>
<li class="page-item<?php echo esc_attr( $letter_status ); ?>"><a class="page-link text-uppercase" href="<?php echo esc_url( add_query_arg( 'az', $letter, get_category_link( $the_cat_id ) ) ); ?>"><?php echo esc_html( $letter ); ?></a></li>
<?php
endforeach;
$all = '';
// Если отсутствует параметр $_GET['az'], деактивировать кнопку "Все".
if ( ! isset( $_GET['az'] ) ) :
$all = ' disabled';
endif;
?>
<li class="page-item<?php echo esc_attr( $all ); ?>"><a class="page-link text-uppercase" href="<?php echo esc_url( get_category_link( $the_cat_id ) ); ?>">Все</a></li>
</ul>
</nav>
<?php endif; ?>
Как это работает
Вначале нужно проверить, не открыта ли страница с тегами. Теги – это тоже архивы, но поскольку в них может быть огромное количество записей, то навигацию там лучше не выводить. Это отрицательно скажется на скорости загрузки страниц.
Далее по коду происходит получение всех записей, а затем первых букв их заголовков. Это необходимо для последующего сравнения и добавления CSS класса, который сделает недоступными отсутствующие буквы. Буква, в разделе которой пользователь сейчас находится, будет подсвечена как активная.
В конце формируется список из букв с добавлением переменных соответствующих классов для стилей Bootstrap Pagination.
Произвольные таксономии
Упрощённый вариант без подсветки кнопок навигации будет работать и в произвольных таксономиях. Теперь рассмотрим, как адаптировать второй вариант.
К примеру, есть кастомный тип записи под названием 'news'
. К этому типу записи относится произвольная таксономия 'news_cat'
. Создаём в ней рубрики, за вывод которых будет отвечать файл taxonomy-news_cat.php. В этот файл нужно добавить код варианта с подсветкой, но с небольшими изменениями.
Данный участок:
// Задаём массив параметров для пользовательского запроса WP_Query.
$args_az = array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1,
'category' => $the_cat_id,
);
Заменим на этот:
// Задаём массив параметров для пользовательского запроса WP_Query.
$args_az = array(
'post_type' => 'news',
'post_status' => 'publish',
'numberposts' => -1,
'tax_query' => array(
array(
// Таксономия 'news_cat'.
'taxonomy' => 'news_cat',
'field' => 'id',
'terms' => $the_cat_id,
),
),
);
Не забудьте изменить 'post_type'
и название таксономии 'news_cat'
на свои типы постов.
Кириллица и кодировка UTF-8
Приведённые выше функции будут работать с кодировкой UTF-8. Необходимо лишь сгенерировать русский алфавитный список, для этого используйте следующие доработки.
Замените эти строки:
// Формируем массив из списка букв от 'a' до 'z'.
$az_range_arr = range( 'a', 'z' );
На код с поддержкой Кириллицы:
$az_range_arr = array();
// Диапазон символов 'а' до 'я' в ASCII Win-1251.
$az_letters_arr = range( chr( 0xE0 ), chr( 0xFF ) );
foreach ( $az_letters_arr as $az_letters ) :
// Формируем массив из списка букв с преобразованием в UTF-8.
$az_range_arr[ $az_letters ] = iconv( 'CP1251', 'UTF-8', $az_letters );
endforeach;
Итоговый результат будет выглядеть таким образом:
Если нужно сделать крупные буквы, просто удалите CSS класс pagination-sm
из кода.
Как сделать пагинацию для сайта на WordPress в стиле Bootstrap 4 смотрите здесь.
Здравствуйте. Попробовал сделать пагинацию по заданному алгоритму из Вашей статьи. Работает, но, почему-то, список букв отображает не горизонтально, а вертикально. Можете помочь с решением?
https://fly-sales.ru/category/bilet/?az=%D0%B0
Здравствуйте. В вашем примере отсутствуют стили Bootstrap 4, но вы можете добавить необходимый CSS вручную. Например:
Прописал функции Bootstrap в файл functions.php своей темы, список стал горизонтальным - это хорошо, но весь шрифт по сайту стал маленьким.
https://fly-sales.ru/category/bilet/?az=%D0%B0 или https://fly-sales.ru/bilet/from/almaty/
Если убрать функции с functions.php - все опять становится на свои места, шрифт - нормальный, а список отбора по буквах - вертикальный.
Фреймворк «Bootstrap 4» вносит изменения в стили сайта. Если не планируете его использовать в своей теме, то можно обойтись кодом CSS (из моего первого ответа).
Если хотите оставить Bootstrap и применить все классы CSS к алфавитному указателю из данной инструкции, то лучше подключите его выше, чем основной файл стилей вашей темы. То есть стиль
bootstrap.min.css
нужно подключать до стиляstyle.css
, а не после. Чтобы у последнего был приоритет.Как это можно сделать:
Откройте
functions.php
и найдите там первое совпадение в поиске по запросу:wp_enqueue_scripts
. Это хук, на котором по правилам WP нужно подключать стили и скрипты.Теперь переместите код «Bootstrap 4» из данной инструкции выше, чем функция с предыдущими стилями
wp_enqueue_scripts
.Огромнейшее Вам Спасибо! Все работает!!
Рад помочь 🙂
Добрый день.
Спасибо за данную статью, сэкономила кучу времени)
Есть вопрос по подсветке активных и неактивных букв. Макс выше уже писал про проблему, что ко всем пунктам применяется стиль disabled, у меня также. Но опишу более детально суть проблемы:
При обычной выборке постов, без get запросов список отрабатывать нормально: у букв без постов есть класс disabled.
Но при выборке уже с get запросом, у всех букв (кроме активной) появляется класс disabled.
Пытался понять причину, смотрел что лежит в $all_titles_arr во время вывода с get запросом. Там лишь активная буква. Я так понимаю, что это не правильное поведение.
Подскажите в правильном направлении копаю или подскажите, где правильное направление?)
Вывожу алфавит в шаблоне category.php, посты выводятся обычным
"if (have_posts()) : while ( have_posts()) : the_post();"
Привет! Класс
disabled
добавляется к неактивным буквам, это не правильно. Могу предположить, что дело в применении GET запроса к не совсем стандартной структуре шаблона. Дополнительно оставлю шаблон темы с настроенным алфавитным указателем для примера. Это чистый скелет основанный на Underscores и добавленным Bootstrap 4. В качестве меню применяется модуль из Foundation 6.Обратите внимание на файлы
functions.php
иarchive.php
, в них находятся коды из данной статьи:https://onstartup.ru/wp-content/uploads/bs4.zip
Спасибо за шаблон. Убедился, что реализация цикла вывода постов одинаковые.
С bs4 шаблоном проблема не исчезла. Отсюда стало ясно, что виноват плагин. В моем случае, "Post Types Order" - https://ru.wordpress.org/plugins/post-types-order/
Попробую для него как-то проверку добавить с алфавитом, а не получится - снесу его, не так уж он и важен.
Спасибо за помощь!
Добрый день! Всё работает, спасибо. Диапазон символов А до Я - как вывести украинский алфавит, словацкий?
Здравствуйте, Роман! Если кодировка отличается от стандартной Кириллицы, то можно выборочно перечислить в списке необходимые символы:
Прописал алфавит - выводит мой алфавит А...Я, потом существующий, т.е. получается А...ЯА...Я
Код предыдущего списка должен быть удалён:
спасибо, работает
У меня все таксономии в одном файле archive.php
Как их там перечислить?
Первый вариант (без подсветки) должен работать. Но желательно уточнить какой функцией выводится список произвольных постов. Для подсветки активных букв алфавита вся задача будет сводиться к определению текущей категории — переменная $the_cat_id.
Я не программист и в этом не понимаю, но в вашем примере:
А у меня везде добавляется disabled:
По этому если применять стили к disabled, то они применяются ко всем буквам.
С тэгами не вставилось.
class="page-item"
class="page-item disabled"
class="page-item active"
А у меня везде добавляется disabled:
class="page-item disabled"
class="page-item disabled"
class="page-item disabled active"
А что делать если произвольных таксономии и типов записей более ста штук?
Может есть более универсальный способ?
А можно пример для чего нужно такое количество таксономий? Чтобы выводить код более универсально лучше упаковать всё в плагин, а затем использовать шорткод с параметрами.
Это справочник, примерно с 3 000 000 записей.
Что бы не грузить все записи в одно место, было создано 4 таксономии и около 100 типов записей в них.
Получается такой способ не подойдёт?
Сейчас этот способ работает, но без подсветки кнопок.
Посмотрите что возвращает функция
get_queried_object_id()
В данном участке кода присваивается ID для произвольной категории. Всё зависит от структуры сайта, я привёл пример для иерархии WordPress по схеме файлов шаблона.Посмотрел, функция get_queried_object_id возвращает ID.
В общем, для моих типов записей где содержится очень много записей такой указатель не подойдёт, так как очень сильно грузит страницу.
Вывел для некоторых типов записей где содержится не очень много записей с помощью шорткодов, под каждый тип записей отдельный шорткод.
Соглашусь, что грузит очень сильно. Я по этой причине исключаю алфавит в тегах на данном сайте.