paginate_links()
Позволяет создать ссылки пагинации для любых страниц.
Пример того как выглядит планация: « предыдущая 1 … 3 4 5 6 7 … 9 следующая »
Технически функцию можно использовать для создания пагинации где угодно. Эта функция является ядром для всех функций пагинации в WordPress.
Для построения пагинации в WordPress есть также специальные функции (обертки для этой функции):
Эта функция жестко добавляет все $_GET параметры текущего запроса (текущей страницы) в ссылки пагинации. Поэтому, например, если она используется в обработчике AJAX запроса, то все URL в ней будут содержать текущие GET параметры. Тикет по этой теме.
Немного о параметрах
Параметр total должен получить общее количество страниц пагинации, а параметр current номер текущей страницы пагинации.
Пример параметра base - http://example.com/all_posts.php%_%, где %_% будет заменено тем что указано в параметре format = '?page=%#%', здесь %#% будет заменено числом текущей страницы пагинации.
Вообще, в base можно сразу указать например так: http://example.com/all_posts.php?page=%#%, и при этом format = '' (пусто).
В ссылки можно добавить переменные запроса, для этого укажите нужные переменные и их значения в виде массива в параметр add_args. Подробнее см. функцию add_query_arg().
Чтобы добавить ссылки на предыдущую/следующую страницу, нужно включить логический параметр prev_next (указать ему true), а затем можно установить текст ссылок указав параметры prev_text / next_text (предыдущая ссылка/следующая ссылка).
Хуки из функции
Возвращает
Строку|Строку[]|null.
строку- HTML или строку ссылок пагинации. Приtype = plainилиtype = list. По умолчанию.массив- Массив данных ссылок пагинации для дальнейшей обработки в PHP. Приtype = array.null- Когда общее количество страниц пагинации меньше 2.
Шаблон использования
$args = [
'base' => '%_%',
'format' => '?page=%#%',
'total' => 1,
'current' => 0,
'show_all' => False,
'end_size' => 1,
'mid_size' => 2,
'prev_next' => True,
'prev_text' => __('« Previous'),
'next_text' => __('Next »'),
'type' => 'plain',
'add_args' => False,
'add_fragment' => '',
'before_page_number' => '',
'after_page_number' => ''
];
echo paginate_links( $args );
Использование
paginate_links( $args );
- $args(строка/массив)
- Аргументы для построения пагинации.
По умолчанию: предустановки
Аргументы параметра $args
- base(строка)
Базовый формат УРЛ, который будет использован для создания ссылки пагинации. Например:
http://example.com/all_posts.php%_%здесь%_%будет заменено значением аргумента format.В
baseможно сразу указать например так:http://example.com/all_posts.php?page=%#%, и при этом указать пустую строку вformat.По умолчанию: '%_%'
- format(строка)
- Формат замены.
По умолчанию: '?page=%#%' - total(число)
- Общее количество страниц, которые участвуют в пагинации.
По умолчанию: 1 - current(число)
- Номер текущей страницы пагинации.
- show_all(логический)
- true - будут показаны все страницы участвующие в пагинации.
false - (По умолчанию) показывается только несколько ссылок спереди и сзади номера текущей страницы. Количество ссылок регулируется параметрамиend_sizeиmid_size.
По умолчанию: false - end_size(число)
- Сколько ссылок показать с начала и конца:
"предыдущая 1 2 ... [4] ... 8 9 следующая".
По умолчанию: 1 - mid_size(число)
- Сколько номеров показывать до и после текущего номера:
1 ... 2 3 [4] 5 6 ... 99.
По умолчанию: 2 - prev_next(логический)
- Выводить боковые ссылки "предыдущая/следующая страница". По умолчанию выводятся, если НЕ нужно выводить эти ссылки пишем false.
По умолчанию: true - prev_text(строка)
- Текст ссылки "предыдущая страница".
По умолчанию: __('« Previous') - next_text(строка)
- Текст ссылки "следующая страница".
По умолчанию: __('Next »') - type(строка)
Контролирует в каком формате будет возвращен результат:
plain- просто ссылки разделенные пробелом (По умолчанию).array- в виде массива данных для дальнейшей обработки в PHP.list- <ul> список.
По умолчанию: 'plain'
- add_args(массив)
- Массив переменных запроса, которые нужно добавить к ссылкам пагинации. См. функцию add_query_arg().
По умолчанию: array() - add_fragment(строка)
- Текст который добавиться ко всем ссылкам.
По умолчанию: '' - aria_current(строка) (WP 4.9)
- Значение атрибута
aria-current. Возможные значения: 'page', 'step', 'location', 'date', 'time', 'true', 'false'.
По умолчанию: 'page'. - before_page_number(строка)
- Текст/строка перед числом пагинации.
- after_page_number(строка)
Текст/строка после числа пагинации.
Параметры before_page_number и after_page_number позволяют обернуть само число пагинации. Например в тег <span> для стилизации.
Вообще, эти параметры были созданы для того, чтобы указать текст для роботов, чтобы при просмотре кода, было понятно для чего предназначены ссылки.
Примеры
#1 Пагинация, аналог wp_pagenavi
Чтобы добавить пагинацию на страницу результатов поиска или страницу архивов, используйте такой код:
function my_pagenavi() {
global $wp_query;
$big = 999999999; // уникальное число для замены
$args = array(
'base' => str_replace( $big, '%#%', get_pagenum_link( $big ) ),
'format' => '',
'current' => max( 1, get_query_var('paged') ),
'total' => $wp_query->max_num_pages,
);
$result = paginate_links( $args );
// удаляем добавку к пагинации для первой страницы
$result = preg_replace( '~/page/1/?([\'"])~', '', $result );
echo $result;
}
// Теперь, где нужно вывести пагинацию используем
// my_pagenavi(); #2 Пагинация для произвольного запроса WP_Query
В примере ниже будем выводить продукты WooCommerce (post_type=product) на отдельной странице записи (post_type=post). Т.е. будем использовать произвольный запрос и сделаем для него пагинацию. Мы указали выводить по 5 товаров, если их, к примеру 22, то будет выведено 5 элементов пагинации, из которых 4 будут ссылками следующего вида: Обратите внимание: В параметре Для получения номера страницы пагинации вместо привычного $page = max( 1, get_query_var('page') );
$query = new WP_Query( [
'post_type' => 'product',
'posts_per_page' => 5,
'paged' => $page,
] );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
// тут ваш код
the_title();
}
wp_reset_postdata();
// Выводим пагинацию, если продуктов больше запрошенного количество
echo paginate_links( [
'base' => user_trailingslashit( wp_normalize_path( get_permalink() .'/%#%/' ) ),
'current' => $page,
'total' => $query->max_num_pages,
] );
}
Текущая страница, ссылка не выводится (5 продуктов)
http://example.com/название-записи/2/ (5 продуктов)
http://example.com/название-записи/3/ (5 продуктов)
http://example.com/название-записи/4/ (5 продуктов)
http://example.com/название-записи/5/ (2 продукта)
base где формируется вид ссылки пагинации не используются такие слова как page или paged. Потому что c page будет перенаправление со страницы пагинации на саму запись, а с paged будет 404 ошибка на странице пагинации.get_query_var( 'paged' ) используем get_query_var( 'page' ).<!--nextpage-->, подробнее см. здесь.
#3 Альтернатива этой фукнции
paginate_links() всегда возвращает HTML, даже если параметр Что выводит функция: Теперь используем эту функцию в цикле: Получим:type=array вы получите массив готовых <a> тегов. Это может не подойти когда нужно полностью изменить HTML-структуру вашей пагинации. Ниже небольшая функция, которая возвращает массив объектов вместо HTML./**
* Generates array of pagination links.
*
* @author Kama (wp-kama.com)
* @varsion 2.5
*
* @param array $args {
*
* @type int $total Maximum allowable pagination page.
* @type int $current Current page number.
* @type string $url_base URL pattern. Use `{pagenum}` placeholder.
* @type string $first_url URL to first page. Default: '' - taken automaticcaly from $url_base.
* @type int $mid_size Number of links before/after current: 1 ... 1 2 [3] 4 5 ... 99. Default: 2.
* @type int $end_size Number of links at the edges: 1 2 ... 3 4 [5] 6 7 ... 98 99. Default: 1.
* @type bool $show_all true - Show all links. Default: false.
* @type string $a_text_patt `%s` will be replaced with number of pagination page. Default: `'%s'`.
* @type bool $is_prev_next Whether to show prev/next links. « Previou 1 2 [3] 4 ... 99 Next ». Default: false.
* @type string $prev_text Default: `« Previous`.
* @type string $next_text Default: `Next »`.
* }
*
* @return array
*/
function kama_paginate_links_data( array $args ): array {
global $wp_query;
$args += [
'total' => 1,
'current' => 0,
'url_base' => '/{pagenum}',
'first_url' => '',
'mid_size' => 2,
'end_size' => 1,
'show_all' => false,
'a_text_patt' => '%s',
'is_prev_next' => false,
'prev_text' => '« Previous',
'next_text' => 'Next »',
];
$rg = (object) $args;
$total_pages = max( 1, (int) ( $rg->total ?: $wp_query->max_num_pages ) );
if( $total_pages === 1 ){
return [];
}
// fix working parameters
$rg->total = $total_pages;
$rg->current = max( 1, abs( $rg->current ?: get_query_var( 'paged', 1 ) ) );
$rg->url_base = $rg->url_base ?: str_replace( PHP_INT_MAX, '{pagenum}', get_pagenum_link( PHP_INT_MAX ) );
$rg->url_base = wp_normalize_path( $rg->url_base );
if( ! $rg->first_url ){
// /foo/page(d)/2 >>> /foo/ /foo?page(d)=2 >>> /foo/
$rg->first_url = preg_replace( '~/paged?/{pagenum}/?|[?]paged?={pagenum}|/{pagenum}/?~', '', $rg->url_base );
$rg->first_url = user_trailingslashit( $rg->first_url );
}
// core array
if( $rg->show_all ){
$active_nums = range( 1, $rg->total );
}
else {
if( $rg->end_size > 1 ){
$start_nums = range( 1, $rg->end_size );
$end_nums = range( $rg->total - ($rg->end_size - 1), $rg->total );
}
else {
$start_nums = [ 1 ];
$end_nums = [ $rg->total ];
}
$from = $rg->current - $rg->mid_size;
$to = $rg->current + $rg->mid_size;
if( $from < 1 ){
$to = min( $rg->total, $to + absint( $from ) );
$from = 1;
}
if( $to > $rg->total ){
$from = max( 1, $from - ($to - $rg->total) );
$to = $rg->total;
}
$active_nums = array_merge( $start_nums, range( $from, $to ), $end_nums );
$active_nums = array_unique( $active_nums );
$active_nums = array_values( $active_nums ); // reset keys
}
// fill by core array
$pages = [];
if( 1 === count( $active_nums ) ){
return $pages;
}
$item_data = static function( $num ) use ( $rg ){
$data = [
'is_current' => false,
'page_num' => null,
'url' => null,
'link_text' => null,
'is_prev_next' => false,
'is_dots' => false,
];
if( 'dots' === $num ){
return (object) ( [
'is_dots' => true,
'link_text' => '…',
] + $data );
}
$is_prev = 'prev' === $num && ( $num = max( 1, $rg->current - 1 ) );
$is_next = 'next' === $num && ( $num = min( $rg->total, $rg->current + 1 ) );
$data = [
'is_current' => ! ( $is_prev || $is_next ) && $num === $rg->current,
'page_num' => $num,
'url' => 1 === $num ? $rg->first_url : str_replace( '{pagenum}', $num, $rg->url_base ),
'is_prev_next' => $is_prev || $is_next,
] + $data;
if( $is_prev ){
$data['link_text'] = $rg->prev_text;
}
elseif( $is_next ) {
$data['link_text'] = $rg->next_text;
}
else {
$data['link_text'] = sprintf( $rg->a_text_patt, $num );
}
return (object) $data;
};
foreach( $active_nums as $indx => $num ){
$pages[] = $item_data( $num );
// set dots
$next = $active_nums[ $indx + 1 ] ?? null;
if( $next && ($num + 1) !== $next ){
$pages[] = $item_data( 'dots' );
}
}
if( $rg->is_prev_next ){
$rg->current !== 1 && array_unshift( $pages, $item_data( 'prev' ) );
$rg->current !== $rg->total && $pages[] = $item_data( 'next' );
}
return $pages;
}
$links_data = kama_paginate_links_data( [
'total' => 3,
'current' => 2,
'url_base' => 'http://site.com/page-name/paged/{pagenum}',
'mid_size' => 2,
] );
print_r( $links_data );
/*
Array
(
[0] => stdClass Object
(
[is_current] =>
[page_num] => 288
[url] => http://site.com/page-name/paged/288
[is_prev_next] => 1
[link_text] => « Previous
[is_dots] =>
)
[1] => stdClass Object
(
[is_current] =>
[page_num] => 1
[url] => http://site.com/page-name/
[is_prev_next] =>
[link_text] => 1
[is_dots] =>
)
[2] => stdClass Object
(
[is_dots] => 1
[link_text] => …
[is_current] =>
[page_num] =>
[url] =>
[is_prev_next] =>
)
[3] => stdClass Object
(
[is_current] =>
[page_num] => 285
[url] => http://site.com/page-name/paged/285
[is_prev_next] =>
[link_text] => 285
[is_dots] =>
)
[4] => stdClass Object
(
[is_current] =>
[page_num] => 286
[url] => http://site.com/page-name/paged/286
[is_prev_next] =>
[link_text] => 286
[is_dots] =>
)
[5] => stdClass Object
(
[is_current] => 1
[page_num] => 287
[url] => http://site.com/page-name/paged/287
[is_prev_next] =>
[link_text] => 287
[is_dots] =>
)
)
*/
<?php
$links_data = kama_paginate_links_data( [
'total' => 3,
'current' => 2,
'url_base' => 'http://site.com/page-name/paged/{pagenum}',
] );
if( $links_data ){
?>
<ul>
<?php foreach( $links_data as $link ) { ?>
<li>
<?php if ( $link->is_dots ) { ?>
<span><?= $link->link_text ?></span>
<?php } elseif ( $link->is_current ) { ?>
<strong><?= $link->link_text ?></strong>
<?php } else { ?>
<a href="<?php esc_attr_e( $link->url ) ?>"><?php _e( $link->link_text ) ?></a>
<?php } ?>
</li>
<?php } ?>
</ul>
<?php
}
<ul>
<li>
<a href="http://site.com/page-name/paged/1">1</a>
</li>
<li>
<strong>2</strong>
</li>
<li>
<a href="http://site.com/page-name/paged/3">3</a>
</li>
</ul>
#4 Пример с произвольным запросом WP_Query
Когда записи выводятся отдельным запросом с помощью new WP_Query для вывода пагинации можно установить параметр total, в котором указать свойство WP_Query::$max_num_pages. Рассмотрим пример:
Это лишь демонстрационный пример, потому что он не учитывает основной запрос, в котором может получаться 404 страница и до этого кода дело вообще не дойдет. Также он может работать неправильно на отдельной странице записи.
<?php
$paged = max( 1, (int) get_query_var('paged') );
$the_query = new WP_Query( [
'posts_per_page' => 5,
'category_name' => 'gallery',
'paged' => $paged,
] );
while( $the_query->have_posts() ){
$the_query->the_post();
?>
<!-- HTML каждой записи -->
<?php
}
wp_reset_postdata();
// пагинация для произвольного запроса
$big = 999999999; // уникальное число
echo paginate_links( array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'current' => $paged,
'total' => $the_query->max_num_pages
) );
?> #5 Добавим префикс для всех классов под БЭМ
Допустим мы изменили шаблон навигации через хук navigation_markup_template и теперь мы ходим чтобы все вложенные элементы соответствовали БЭМ классам.
Класс БЭМ блока у нас hlpagination:
<?php
/// изменим шаблон навигации (пагинации)
add_filter( 'navigation_markup_template', 'hl_navigation_template', 10, 2 );
function hl_navigation_template( $template, $class ){
ob_start();
?>
<nav class="hlpagination %1$s" role="navigation">
<div class="hlpagination__nav-links">%3$s</div>
</nav>
<?php
return ob_get_clean();
}
%3$s заменяется на то что возвращает paginate_links() и у нее всем классам также нужно добавить префикс:
/// поправим html пагинации для функции paginate_links()
add_filter( 'paginate_links_output', 'hl_fix_paginate_links' );
function hl_fix_paginate_links( $html ){
$html = preg_replace_callback( '/ class=[\'"][^\'"]+[\'"]/', static function( $mm ){
return strtr( $mm[0], [
'current' => '--current',
'prev' => 'hlpagination__prev',
'next' => 'hlpagination__next',
'dots' => 'hlpagination__dots',
'page-numbers' => 'hlpagination__numbers',
] );
}, $html );
return $html;
}
Заметки
- Global. WP_Query.
$wp_queryWordPress Query object. - Global. WP_Rewrite.
$wp_rewriteWordPress rewrite component.
Список изменений
| С версии 2.1.0 | Введена. |
| С версии 4.9.0 | Added the aria_current argument. |