Алфавитный указатель WordPress

Алфавитная пагинация в категориях WordPress

Для удобного поиска постов по категориям решено создать алфавитную навигацию. К сожалению, WordPress изначально не имеет такого функционала, но поскольку я являюсь разработчиком тем и плагинов, то напишу подробно, как был создан этот полезный элемент.

Приведённые примеры будут совместимы со стандартной структурой WP, которой соответствует популярная стартовая тема Underscores. Вёрстка стилей подходит под Фреймворк Twitter Bootstrap 4. Как подключить Bootstrap к сайту на WordPress через CDN смотрите здесь.

Суть работы модуля заключается в добавлении к URL параметра GET при помощи функции add_query_arg(), значением которого является буква латинского алфавита. Когда параметр установлен, его можно использовать для фильтрации основного потока записей main_query, что позволит сохранить работоспособность постраничной навигации. На данном сайте это применимо ко всем рубрикам главной страницы. Навигация с алфавитом будет вверху каждой категории.

Рассмотрим более детально каждый этап в примерах.

Создадим функцию, которая отвечает за фильтрацию каждой отдельной буквы.
Можно добавить данный код в самый конец файла functions.php вашей темы WP:

// Функция для изменения части WHERE запроса SQL (WP_Query)
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 ", $_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="a-z" class="mb-4">
		<ul class="pagination pagination-sm flex-wrap justify-content-center">
			<?php

			// Определяем текущую категорию.
			$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( $cat_ID ) ) ); ?>"><?php echo $letter; ?></a></li>
			<?php
			endforeach; ?>

			<li class="page-item"><a class="page-link text-uppercase" href="<?php echo get_category_link( $cat_ID ); ?>">Все</a></li>
		</ul>
	</nav>
<?php
endif; ?>

 

Подсветка активных и неактивных кнопок навигации.

Рассмотрим пример с неактивными буквами, которые отсутствуют в данной рубрике. Активная буква списка будет подсвечена:

<?php
if ( ! is_tag() && ! is_date() ) : ?>
	<nav aria-label="a-z" class="mb-4">
		<ul class="pagination pagination-sm flex-wrap justify-content-center">
			<?php

			// Определяем текущую категорию.
			$cat_ID = get_queried_object_id();

			// Задаём массив параметров для пользовательского запроса WP_Query.
			$args_az = array(
				'post_type'   => 'post',
				'post_status' => 'publish',
				'category'    => $cat_ID,
				'numberposts' => -1
			);

			// Запрос WP_Query функцией get_posts().
			$query_az = get_posts( $args_az );

			// Перебираем каждый заголовок записи, отобрав первую букву в массив '$all_titles_arr'.
			$all_titles_arr = [];
			foreach ( $query_az as $post_az ) :
				setup_postdata( $post_az );
				$title            = get_the_title( $post_az->ID );
				$all_titles_arr[] = mb_strtolower( mb_substr( $title, 0, 1, 'UTF-8' ) );
			endforeach;
			wp_reset_postdata();

			// Формируем массив из списка букв от 'a' до 'z'.
			$az_range_arr = range( 'a', 'z' );

			// Подготовка различных классов для подсветки кнопок навигации.
			foreach ( $az_range_arr as $letter ) :
				$disabled = '';
				$active   = '';

				// Существует ли данная буква в массиве 'all_titles_arr'.
				if ( ! in_array( $letter, $all_titles_arr ) ) :
					$disabled = ' disabled';

				// Совпадает ли буква с текущим параметром GET массива.
				elseif ( isset( $_GET['az'] ) && $_GET['az'] == $letter ) :
					$active = ' active';
				endif; ?>

				<li class="page-item<?php echo $disabled . $active; ?>"><a class="page-link text-uppercase" href="<?php echo esc_url( add_query_arg( 'az', $letter, get_category_link( $cat_ID ) ) ); ?>"><?php echo $letter; ?></a></li>
			<?php
			endforeach;

			$all = '';

			// Если отсутствует параметр $_GET['az'], деактивировать кнопку "Все".
			if ( ! isset( $_GET['az'] ) ) :
				$all = ' disabled';
			endif; ?>

			<li class="page-item<?php echo $all; ?>"><a class="page-link text-uppercase" href="<?php echo get_category_link( $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',
				'category'    => $cat_ID,
				'numberposts' => -1
			);

Заменим на этот:

			// Задаём массив параметров для пользовательского запроса 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'    => $cat_ID
				) )
			);

Не забудьте изменить 'post_type' и название таксономии 'news_cat' на свои типы постов.

 

Кириллица и кодировка UTF-8.

Приведённые выше функции будут работать с кодировкой UTF-8. Необходимо лишь сгенерировать русский алфавитный список, для этого используйте следующие доработки.

Замените эти строки:

			// Формируем массив из списка букв от 'a' до 'z'.
			$az_range_arr = range( 'a', 'z' );

На код с поддержкой Кириллицы:

			$az_range_arr = [];

			// Диапазон символов 'а' до 'я' в 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 );
			}

Итоговый результат будет выглядеть таким образом:

Как сделать пагинацию для сайта на WordPress в стиле Bootstrap 4 смотрите здесь.