WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

Как использовать параметр offset не ломая пагинацию

Эта статья объясняет как правильно использовать параметр offset в запросах.

Подразумевается, что вы уже знакомы с тем, как использовать фильтры WordPress и хорошо представляете работу с классом wpdb.

Частый случай, когда использование параметра offset приводит к неправильной работе пагинации (разбиение информации на страницы). WP использует offset для построения пагинации и неправильное его использование обязательно повлияет на вывод. Чтобы обойти эту проблему, нужно в ручную внедрится в пагинацию: нужно определить имеет ли цикл дополнительные страницы пагинации и динамически определить параметр offset для текущей страницы. Делается это через фильтр pre_get_posts. Также, нужно отрегулировать вычисление пагинации самим WP, чтобы исключить посты которые мы хотим "пропустить" параметром offset. Это можно сделать, используя фильтр found_posts, который поможет нам "отминусовать" нужное количество постов.

Суть проблемы

offset полезен тем, что позволяет разработчикам пропускать указанное количество постов перед тем как начать их выводить. Но многие начинающие разработчики сталкиваются с проблемой, когда при использовании offset параметра в запросе ломается пагинация на сайте.

Такое поведение логично, если понять что происходит. Аргумент offset используется WP при построении пагинации и когда разработчики устанавливают его вручную, пагинация перестает работать, потому что этот аргумент переписан, а WP меняет его динамически на каждой странице пагинации.

Решение проблемы

Чтобы вы могли использовать параметр offset в запросах WP и при этом пагинация работала как надо, нужно указывать offset динамически для каждой страницы, с учетом начальной "сдвижки" постов. Также нужно пересчитать количество страниц в пагинации. Сделать это можно, используя 2 хука:

pre_get_posts - позволят внедрятся в запрос до того как он запускается. Тут мы должны убедиться, что наш offset применяется только на первой странице.

found_posts - позволяет скорректировать подсчет результата запроса. Тут мы должны убедиться, что наш offset применяется при подсчете на всех других страницах, кроме первой.

offset и корректировка пагинации

Первый шаг.

Использование хука pre_get_posts. Так как этот хук является действием, а не фильтром (фильтр подразумевает обработку и возврат обработанных данных) нам нужно передать объект $query в нашу произвольную функцию по ссылке, это позволит нам изменять объект напрямую внутри класса, не возвращая никаких данных.

Чтобы убедиться, что мы изменяем нужный нам запрос, нам нужна небольшая предварительная проверка в начале $query->is_posts_page. В этом примере мы хотим, чтобы на главной странице сайта было пропущено 10 первых постов:

add_action('pre_get_posts', 'myprefix_query_offset', 1 );
function myprefix_query_offset(&$query) {
	// проверим что это нужный нам запрос...
	if ( ! $query->is_posts_page ) {
		return;
	}

	// определим нужный нам отступ...
	$offset = 10;

	// определим сколько постов на странице мы будет выводить (получим данные из настроек)
	$ppp = get_option('posts_per_page');

	// если это страница пагинации...
	if ( $query->is_paged ) {

		// вычислим отступ на странице пагинации (offset + текущая страница (минус один) x количество постов на странице)
		$page_offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );

		// применим вычисленный отступ (offset)
		$query->set('offset', $page_offset );

	}
	else // если это не страница пагинации (первая страница)
	{

		// используем только отступ (offset)...
		$query->set('offset',$offset);

	}
}

Второй шаг.

WP не учтет наш отступ, когда будет подсчитывать количество постов в запросе. Теперь, посты будут выводиться как надо, но когда WP будет строить номера пагинации, он будет считать что постов на 10 больше и добавит одну лишнюю страницу пагинации, если предположить, что на странице выводится 10 постов. Последняя страница пагинации будет существовать, но перейдя по ссылке наш измененный запрос вернет пустой результат. Упс!

Эта маленькая проблема пагинации решается с помощью фильтра found_posts:

add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
function myprefix_adjust_offset_pagination($found_posts, $query) {

	// опять определяем наш отступ...
	$offset = 10;

	// опять убедимся, что мы редактируем нужный нам запрос (на главной)...
	if ( $query->is_posts_page ) {
		// изменим количество найденных постов, уменьшим на наш отступ (10)...
		return $found_posts - $offset;
	}
}

Теперь, все готово! Пагинация и нужный нам отступ должны работать корректно.

16 комментов
Полезные 1 Вопросы 1 Все