Для удобного поиска постов по категориям решено создать алфавитную навигацию. К сожалению, 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 смотрите здесь.
Здравствуйте, все работает отлично, но есть вопрос.
Если сделать пагинацию через Load More wp_ajax фильтр не срабатывает, как можно обойти данный момент? В функции используется WP_Query с suppress_filters = false
Так же добавил posts_where_paged, дополнительно передаю букву в запрос и обновил функцию
Здравствуйте. А можете пожалуйста подсказать. Туплю)
Как объединить две буквы? Например И и Й, или Е и Ё
Что бы в алфавите стояла одна только буква, но в поиске выводился и и тот и тот вариант
формат кода:
<li><a href="<?php echo esc_url(add_query_arg( 'letter', 'Е', $my_url )); ?>">Е</a></li>
при добавлении через запятую - ругается на ситаксис
Здравствуйте. Необходимо доработать данную функцию следующим образом:
Спасибо. Но не помогло. Если не справлюсь, можете написать на почту (вам её же видно?) стоимость вашей помощи?
Напишите что именно не получается, постараюсь помочь.