Альтернатива плагину WP-pagenavi (пагинация для WordPress)
C версии 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-kama.ru/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, если вместо текста нужно показать номер страницы. ]; // Cовместимость с 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( '___', ( $paged - 1 ), $link_base ) ) . '">' . $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; }