Альтернатива плагіну WP-pagenavi (пагінація для WordPress)
З версії 4.1 у WordPress з’явилася рідна аналогічна функція: the_posts_pagination()
Попалася мені якось тема, що найпопулярніший плагін WordPress wp-pagenavi навантажує сервер не в міру власної потреби. Проаналізувавши його код з’ясував, що це лише міф, хоча його все ж таки можна трохи оптимізувати, власне цьому і присвячений пост.
Якщо інші плагіни складно уявити без можливості їх налаштування в адмін-панелі, wp-pagenavi мені представляється легко. Достатньо один раз налаштувати навігацію та забути про неї. І мабуть є ті, хто думає так само? Тому я вирішив відмовитися від wp-pagenavi та замінити його на свою функцію. Функцію я написав, попередньо вивчивши код wp-pagenavi, частково код узяли від туди. Всі CSS класи wp-pagenavi збережені і, як наслідок, замінити wp-pagenavi на мій варіант зовсім не важко.
Для заміни потрібно скопіювати нижченаведену функцію у файл шаблону functions.php. Також потрібно скопіювати CSS стилі wp-pagenavi у ваш файл стилів (зазвичай це style.css). Перенесення стилів має корисний характер, тому що більше не буде необхідності підключати файл стилів, а це мінус один http запит.
/**
* Альтернатива wp_pagenavi. Створює посилання на пагінацію на сторінках архівів.
*
* @version 2.8
* @author Тимур Камаєв
* @ link https://wp-doc.com/8
*
* @param array $args Аргументи функції.
* @param WP_Query $wp_query Об'єкт WP_Query на основі якого будується пагінація. За промовчанням глобальна змінна $wp_query.
*
* @return string Pagination HTML code.
*/
function kama_pagenavi( $args = [], $wp_query = null ){
// Параметри за замовчуванням
$default = [
'before' => '', // Текст до навігації.
'after' => '', // Текст після навігації.
'echo' => true, // Повертати чи виводити результат.
'text_num_page' => '', // Текст перед пагінацією.
//{current} – поточна.
// {last} - остання (пр: 'Сторінка {current} з {last}' отримаємо: "Сторінка 4 із 60").
'num_pages' => 10 // Скільки посилань показувати.
'step_link' => 10, // Посилання з кроком (якщо 10, то: 1,2,3 ... 10,20, 30. Ставимо 0, якщо такі посилання не потрібні.
'dotright_text' => '…', // Проміжний текст "до".
'dotright_text2' => '…', // Проміжний текст "після".
'back_text' => '« назад', // Текст "перейти на попередню сторінку". Ставимо 0, якщо це посилання не потрібне.
'next_text' => 'вперед», // Текст "перейти на наступну сторінку". Ставимо 0, якщо це посилання не потрібне.
'first_page_text' => '« на початок', // Текст "до першої сторінки". Ставимо 0, якщо замість тексту потрібно показати номер сторінки.
'last_page_text' => 'наприкінці »', // Текст "до останньої сторінки". Ставимо 0, якщо замість тексту потрібно показати номер сторінки.
];
// Сумісність з v2.5: kama_pagenavi( $before = '', $after = '', $echo = true, $args = array() )
$fargs = func_get_args();
if( $fargs && is_string( $fargs[0] ) ){
$default['before'] = isset($fargs[0]) ? $fargs[0] : '';
$default['after'] = isset($fargs[1]) ? $fargs[1] : '';
$default['echo'] = isset($fargs[2]) ? $ fargs [2] : true;
$args = isset($fargs[3]) ? $fargs[3] : array();
$wp_query = $GLOBALS['wp_query']; // Після визначення $ default!
}
if( ! $wp_query ){
wp_reset_query();
global $wp_query;
}
if( ! $args ){
$args = [];
}
if( $args instanceof WP_Query ){
$wp_query = $args;
$args = [];
}
/**
* Дозволяє встановити параметри за замовчуванням.
*
* @param array $default_args
*/
$default = apply_filters( 'kama_pagenavi_args', $default );
$ rg = (object) array_merge ($ default, $ args);
$paged = (int) $wp_query->get( 'paged' )?: 1;
$max_page = $wp_query->max_num_pages;
// navigation no needed
if( $max_page < 2 ){
return '';
}
$pages_to_show = (int) $rg->num_pages;
$pages_to_show_minus_1 = $pages_to_show-1;
$half_page_start = floor( $pages_to_show_minus_1 / 2 ); // скільки посилань до поточної сторінки
$half_page_end = ceil($pages_to_show_minus_1/2); // скільки посилань після поточної сторінки
$start_page = $paged - $half_page_start; // перша сторінка
$end_page = $paged + $half_page_end; // остання сторінка (умовно)
if( $start_page <= 0 ){
$start_page = 1;
}
if( ( $end_page - $start_page ) != $pages_to_show_minus_1 ){
$end_page = $start_page + $pages_to_show_minus_1;
}
if( $end_page > $max_page ){
$start_page = $max_page - $pages_to_show_minus_1;
$ end_page = (int) $ max_page;
}
if( $start_page <= 0 ){
$start_page = 1;
}
// створюємо базу, щоб викликати get_pagenum_link один раз
$link_base = str_replace( PHP_INT_MAX, '___', get_pagenum_link( PHP_INT_MAX ) );
$first_url = get_pagenum_link(1);
if( false === strpos( $first_url, '?' ) ){
$first_url = user_trailingslashit( $first_url );
}
// збираємо елементи
$els = [];
if( $rg->text_num_page ){
$rg->text_num_page = preg_replace( '!{current}|{last}!', '%s', $rg->text_num_page );
$els['pages'] = sprintf( '<span class="pages">' . $rg->text_num_page . '</span>', $paged, $max_page );
}
// назад
if( $rg->back_text && $paged !== 1 ){
$els['prev'] = '<a class="prev" href="' ( $paged - 1 ) == 1 ? $first_url : str_replace( '___', ) ) . $rg->back_text . '</a>';
}
// на початок
if( $start_page >= 2 && $pages_to_show < $max_page ){
$els['first'] = '<a class="first" href="' . $first_url . '">' . ($rg->first_page_text?: 1). '</a>';
if( $rg->dotright_text && $start_page !== 2 ){
$els[] = '<span class="extend">' . $rg->dotright_text . '</span>';
}
}
// пагінація
for( $i = $start_page; $i <= $end_page; $i++ ){
if( $i === $paged ){
$els['current'] = '<span class="current">' . $i . '</span>';
}
elseif( $i === 1 ){
$els[] = '<a href="' . $first_url . '">1</a>';
}
else {
$els[] = '<a href="' . str_replace( '___', $i, $link_base ) . '">' . $i . '</a>';
}
}
// Посилання з кроком
$dd = 0;
if( $rg->step_link && $end_page < $max_page ){
for( $i = $end_page + 1; $i <= $max_page; $i++ ){
if( 0 === ( $i % $rg->step_link) && $i !== $rg->num_pages ){
if( ++$dd === 1 ){
$els[] = '<span class="extend">' . $rg->dotright_text2 . '</span>';
}
$els[] = '<a href="' . str_replace( '___', $i, $link_base ) . '">' . $i . '</a>';
}
}
}
// в кінець
if( $end_page < $max_page ){
if( $rg->dotright_text && $end_page !== ( $max_page - 1 ) ){
$els[] = '<span class="extend">' . $rg->dotright_text2 . '</span>';
}
$els['last'] = sprintf( '<a class="last" href="%s">%s</a>',
str_replace( '___', $max_page, $link_base ),
$rg->last_page_text?: $max_page
);
}
// Вперед
if( $rg->next_text && $paged !== $end_page ){
$els['next'] = sprintf( '<a class="next" href="%s">%s</a>',
str_replace( '___', ( $paged + 1 ), $link_base ),
$rg->next_text
);
}
/**
* Allow to change pagenavi elements.
*
* @param array $elements
*/
$els = apply_filters( 'kama_pagenavi_elements', $els );
$html = $rg->before . '<div class="wp-pagenavi">' . implode('', $els). '</div>'. $rg->after;
/**
* Allow to change final output HTML code of pagenavi.
*
* @param array $html
*/
$html = apply_filters( 'kama_pagenavi', $html);
if( ! $rg->echo ){
return $html;
}
echo $html;
}
/**
* CHANGELOG:
*
* 2.8 (14.02.2022)
* - Minor improvements.
* 2.7 (02.11.2018)
* - У $args можна вказати другий параметр $wp_query, коли $args можна залишити порожнім.
* - Виправлення коду - виправив баги, переробив збирання елементів у масив.
* - Новий хук `kama_pagenavi_elements`.
* 2.6 (20.10.2018)
* - Прибрав extract().
* - Переніс параметри $before, $after, $echo у $args (старий варіант буде працювати).
* 2.5 - 2.5.1
* - Автоматичне скидання основного запиту.
*/
Налаштування описані прямо в коді і вони ідентичні налаштуванням wp-pagenavi, з тією різницею, що замість тексту “до останньої сторінки” можна вивести номер останньої сторінки.
Після того, як функція встановлена та css стилі перенесені, змінюємо в шаблоні код wp_pagenavi на цей:
<?php kama_pagenavi(); ?>
Якщо у вас в коді щось подібне до цього, то потрібно поміняти все wp_pagenavi на kama_pagenavi :
if(function_exists('wp_pagenavi')) {
wp_pagenavi( '<center>', '</center>' );
}CSS стилі для коду
Вище я вже сказав. що класи CSS збігаються з wp-pagenavi. Для зручності викладаю тут всі CSS правила:
.wp-pagenavi{ margin:2em auto; text-align:center; }
.wp-pagenavi > *{ display:inline-block; padding:.0em .5em; margin:.1em; border:1px solid #93a8bc; border-radius:3px; color:#465366; }
.wp-pagenavi a,
.wp-pagenavi a:hover{ text-decoration:none; }
.wp-pagenavi a {background-color: #FFFFFF; }
.wp-pagenavi a:hover{ border-color:#7d95ac; }
.wp-pagenavi .pages{ }
. wp-pagenavi . current { border-color: # 465366; color: #465366; }
.wp-pagenavi .extend{ color: #465366; }
.wp-pagenavi .first{ }
.wp-pagenavi .last{ }
.wp-pagenavi .prev{ border-color:rgba(0,0,0,0); }
.wp-pagenavi .next { border-color: rgba (0,0,0,0); }У моєму коді є 4 нових класи: first (на початок), last (на кінець), prev (назад), next (вперед).
Непогану добірку стилів можна взяти тут .
Якщо навігація виводиться 2 рази
Також хочу звернути увагу тих, у кого навігація виводиться 2 рази на сторінці (згори і знизу циклу). Щоб 2 рази не виконувати одні й самі операції зі складання навігації, логічніше зробити так: один раз зібрати навігацію (використовувати функцію), потім записати результат у змінну і вдруге просто вивести цю змінну. Виглядає це так:
// Місце, де вперше потрібно вивести навігацію
// Отримуємо навігацію і записуємо її в змінну
$navigation = kama_pagenavi('', '', false);
// Виводимо змінну на екран
echo $navigation;
/* Тут йде висновок постів - цикл Loop */
// Місце, де вдруге необхідно вивести навігацію.
/ / Оскільки навігація вже записана в змінну $ get_navigation, її можна просто вивести на екран.
echo $navigation;Оновлення
17 грудня 2013
Версія 2.0. Підправив код, прибрав зайві, непотрібні виклики функції get_pagenum_link(), за рахунок чого код почав працювати набагато швидше без втрати якості.
11 травня 2010
Переніс посилання назад/вперед , тепер так: «назад « ** на початок … 11 12 13 14 15 16 17 18 … в кінець ** » вперед»
Останній варіант функції нагорі .
2 травня 2010
Додані посилання назад/вперед, приклад:
« ** на початок “назад… 11 12 13 14 15 16 17 18 … вперед» в кінець ** » Їх можна вимкнути (див. налаштування).- Прибрано баг такого типу:
1 … 2 3 4 5 6 7 8 … 50 або 1 … 21 22 23 24 25 26 27 28 … 29
Тобто, де не потрібно прибрано тексти ” до ” і ” після ” навігації (в даному прикладі це трикрапка).
Реверсивна пагінація для WordPress
Ідея реверсивної (зворотної) пагінації належить sholo , який висловив її на відомому нам форумі – mywordpress.ru . Мені стало цікаво подивитися, як це виглядатиме і я трохи переробив код.
Цей код базується на старій версії основного коду.
/* Альтернатива wp_pagenavi - реверсивна пагінація
-------------------------------------------------- ------------------------------- */
function kama_pagenavi($before='', $after='', $echo=true) {
/* ================ Налаштування ================ */
$text_num_page = ''; // Текст кількості сторінок. {current} заміниться поточною, а {last} останньою. Приклад: 'Сторінка {current} з {last}' = Сторінка 4 з 60
$num_pages = 10; // скільки посилань показувати
$stepLink = 10; // після навігації посилання з певним кроком (значення = число (який крок) або '', якщо потрібно показувати). Приклад: 1,2,3...10,20,30
$ dotright_text = '…'; / / Проміжний текст "до".
$dotright_text2 = '...'; / / Проміжний текст "після".
$backtext = '<<<'; // Текст "перейти на попередню сторінку". Ставимо '', якщо це посилання не потрібне.
$nexttext = '>>>'; // Текст "перейти на наступну сторінку". Ставимо '', якщо це посилання не потрібне.
$first_page_text = '« остання'; // текст "першій сторінці" чи ставимо '', якщо замість тексту потрібно показати номер сторінки.
$last_page_text = 'перша»; // текст "до останньої сторінки" або пишемо '', якщо замість тексту потрібно показати номер сторінки.
/* ================ Кінець Налаштувань ================ */
global $wp_query;
$posts_per_page = (int) $wp_query->query_vars['posts_per_page'];
$paged = (int) $wp_query->query_vars['paged'];
$max_page = $wp_query->max_num_pages;
if($max_page <= 1 ) return false; //Перевірка на потребу в навігації
if(empty($paged) || $paged == 0) $paged = 1;
$pages_to_show = intval($num_pages);
$pages_to_show_minus_1 = $pages_to_show-1;
$half_page_start = floor($pages_to_show_minus_1/2); //скільки посилань до поточної сторінки
$half_page_end = ceil($pages_to_show_minus_1/2); //скільки посилань після поточної сторінки
$start_page = $paged - $half_page_start; //перша сторінка
$end_page = $paged + $half_page_end; //Остання сторінка (умовно)
if($start_page <= 0) $start_page = 1;
if(($end_page - $start_page) != $pages_to_show_minus_1) $end_page = $start_page + $pages_to_show_minus_1;
if($end_page > $max_page) {
$start_page = $max_page - $pages_to_show_minus_1;
$ end_page = (int) $ max_page;
}
if($start_page <= 0) $start_page = 1;
$out='';//виводимо навігацію
$out.= $before."<div class='wp-pagenavi'>n";
if ($text_num_page) {
$text_num_page = preg_replace ('!{current}|{last}!','%s',$text_num_page);
$out.= sprintf ("<span class='pages'>$text_num_page</span>",$paged,$max_page);
}
if ($backtext && $paged!=1) $out.= '<a href="'.get_pagenum_link(($paged-1)).'">'.$backtext.'</a>';
if ($start_page >= 2 && $pages_to_show < $max_page) {
$out.= '<a href="'.get_pagenum_link().'">'. ($first_page_text?$first_page_text:$max_page) .'</a>';
if($dotright_text && $start_page!=2) $out.= '<span class="extend">'.$dotright_text.'</span>';
}
for($i = $start_page; $i <= $end_page; $i++) {
if($i == $paged) {
$out.= '<span class="current">'.($max_page-$i+1).'</span>';
} else {
$out.= '<a href="'.get_pagenum_link($i).'">'.($max_page-$i+1).'</a>';
}
}
//Посилання з кроком
if ($stepLink && $end_page < $max_page){
for($i=$end_page+1; $i<=$max_page; $i++) {
if($i % $stepLink == 0 && $i!==$num_pages) {
if (++$dd == 1) $out.= '<span class="extend">'.$dotright_text2.'</span>';
$out.= '<a href="'.get_pagenum_link($i).'">'.($max_page-$i+1).'</a>';
}
}
}
if ($end_page < $max_page) {
if($dotright_text && $end_page!=($max_page-1)) $out.= '<span class="extend">'.$dotright_text2.'</span>';
$out.= '<a href="'.get_pagenum_link($max_page).'">'. ($last_page_text?$last_page_text:1) .'</a>';
}
if ($nexttext && $paged!=$end_page) $out.= '<a href="'.get_pagenum_link(($paged+1)).'">'.$nexttext.'</a>';
$out.= "</div>".$after."n";
if ($echo) echo $out;
else return $out;
}