WordPress как на ладони
rgbcode is looking for WordPress developers. Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

Альтернатива плагину 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 запрос.

GitHub
/**
 * A wp_pagenavi alternative. Creates pagination links on archive pages.
 *
 * @param array    $args      Function arguments.
 * @param WP_Query $wp_query  WP_Query object on which pagination is based. Defaults to global variable $wp_query.
 *
 * @return string Pagination HTML code.
 *
 * @link     https://wp-kama.ru/8
 * @author   Timur Kamaev
 * @require  WP 5.9
 * @version  3.0
 */
function kama_pagenavi( $args = [], $wp_query = null ){

	$default = [
		'before'          => '',           // Text before the navigation.
		'after'           => '',           // Text after the navigation.
		'echo'            => true,         // Return or output the result.
		'text_num_page'   => '',           // Text before the pagination.
										   // {current} - current.
										   // {last} - last (eg: 'Page {current} of {last}' will result in: "Page 4 of 60").
		'num_pages'       => 10,           // How many links to show.
		'step_link'       => 10,           // Links with step (if 10, then: 1,2,3...10,20,30. Use 0 if such links are not needed.
		'dotright_text'   => '…',          // Intermediate text "before".
		'dotright_text2'  => '…',          // Intermediate text "after".
		'back_text'       => '« back',     // Text "go to the previous page". Use 0 if this link is not needed.
		'next_text'       => 'forward »',  // Text "go to the next page". Use 0 if this link is not needed.
		'first_page_text' => '« to start', // Text "to the first page". Use 0 if the page number should be shown instead of the text.
		'last_page_text'  => 'to end »',   // Text "to the last page". Use 0 if the page number should be shown instead of the text.
	];

	// Compat with v2.5: kama_pagenavi( $before = '', $after = '', $echo = true, $args = [] )
	$fargs = func_get_args();
	if( $fargs && is_string( $fargs[0] ) ){
		$default['before'] = $fargs[0] ?? '';
		$default['after']  = $fargs[1] ?? '';
		$default['echo']   = $fargs[2] ?? true;
		$args              = $fargs[3] ?? [];
		$wp_query = $GLOBALS['wp_query']; // !!! after $default
	}

	if( ! $wp_query ){
		wp_reset_query();
		global $wp_query;
	}

	if( ! $args ){
		$args = [];
	}

	/**
	 * Allows you to set default parameters.
	 *
	 * @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 = (int) $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 = (int) floor( $pages_to_show_minus_1 / 2 ); // how many links before the current page
	$half_page_end   = (int) ceil(  $pages_to_show_minus_1 / 2 ); // how many links after the current page

	$start_page = $paged - $half_page_start; // first page
	$end_page   = $paged + $half_page_end;   // last page (conventionally)

	if( $start_page <= 0 ){
		$start_page = 1;
	}
	if( (int) ( $end_page - $start_page ) !== (int) $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 =  $max_page;
	}

	if( $start_page <= 0 ){
		$start_page = 1;
	}

	// create a base to call get_pagenum_link once
	$link_base = str_replace( PHP_INT_MAX, '___', get_pagenum_link( PHP_INT_MAX ) );
	$first_url = get_pagenum_link( 1 );
	if( ! str_contains( $first_url, '?' ) ){
		$first_url = user_trailingslashit( $first_url );
	}

	// gather elements
	$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 );
	}
	// back
	if( $rg->back_text && $paged !== 1 ){
		$els['prev'] = sprintf( '<a class="prev" href="%s">%s</a>',
			( ( $paged - 1 ) === 1 ? $first_url : str_replace( '___', ( $paged - 1 ), $link_base ) ),
			$rg->back_text
		);
	}
	// to the beginning
	if( $start_page >= 2 && $pages_to_show < $max_page ){
		$els['first'] = sprintf( '<a class="first" href="%s">%s</a>', $first_url, ( $rg->first_page_text ?: 1 ) );
		if( $rg->dotright_text && $start_page !== 2 ){
			$els[] = '<span class="extend">' . $rg->dotright_text . '</span>';
		}
	}

	// pagination
	for( $i = $start_page; $i <= $end_page; $i++ ){
		if( $i === $paged ){
			$els['current'] = '<span class="current">' . $i . '</span>';
		}
		elseif( $i === 1 ){
			$els[] = sprintf( '<a href="%s">1</a>', $first_url );
		}
		else{
			$els[] = sprintf( '<a href="%s">%s</a>', str_replace( '___', (string) $i, $link_base ), $i );
		}
	}

	// links with step
	$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[] = sprintf( '<a href="%s">%s</a>', str_replace( '___', (string) $i, $link_base ), $i );
			}
		}
	}
	// to the end
	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
		);
	}
	// forward
	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 string $html
	 */
	$html = apply_filters( 'kama_pagenavi', $html );

	if( $rg->echo ){
		echo $html;
	}

	return $html;
}

/**
 * CHANGELOG:
 *
 * 3.0 (14.12.2023)
 *   - Requires at least PHP 7.0.
 *   - Requires at least WP 5.9.
 *   - PHP 8.1 support. Typehint improvements.
 *   - Removed capability to pass $wp_query in first parameter.
 * 2.8 (14.02.2022)
 *   - Minor improvements.
 * 2.7 (02.11.2018)
 *   - In $args you can specify the second parameter $wp_query, when $args can be left empty.
 *   - Code edits - fixed bugs, rebuilt the collection of elements into an array.
 *   - New hook `kama_pagenavi_elements`.
 * 2.6 (20.10.2018)
 *   - Removed extract().
 *   - Moved parameters $before, $after, $echo to $args (old version will work).
 * 2.5 - 2.5.1
 *   - Automatic reset of the main query.
 */

Настройки описаны прямо в коде и они идентичны настройкам 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

  1. Добавлены ссылки назад/вперед, пример:
    «**к началу «назад ... 11 12 13 14 15 16 17 18 ... вперед» в конец**»
    Их можно отключить (см. настройки).

  2. Убран баг такого типа:
    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;
	}

	return $out;
}
211 комментариев
Полезные 8Вопросы 2 Все
    Войти