Проблема
По умолчанию в любом данном контексте WordPress использует основной запрос для определения нумерации страниц. Основной объект запроса хранится в $wp_query
глобальном, который также используется для вывода основного цикла запроса:
if ( have_posts() ) : while ( have_posts() ) : the_post();
Когда вы используете пользовательский запрос , вы создаете совершенно отдельный объект запроса:
$custom_query = new WP_Query( $custom_query_args );
И этот запрос выводится через совершенно отдельный цикл:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
Но шаблон разбиения на страницы теги, в том числе previous_posts_link()
, next_posts_link()
, posts_nav_link()
, и paginate_links()
, основывают свой вывод на основной объект запроса , $wp_query
. Этот основной запрос может быть или не быть разбит на страницы. Например, если текущий контекст представляет собой пользовательский шаблон страницы, основной $wp_query
объект будет состоять только из одного сообщения - идентификатора страницы, которой назначен пользовательский шаблон страницы.
Если текущий контекст представляет собой некоторый архивный индекс, основной $wp_query
может состоять из достаточного количества сообщений, чтобы вызвать разбиение на страницы, что приводит к следующей части проблемы: для основного $wp_query
объекта WordPress передаст paged
параметр в запрос на основе paged
Переменная запроса URL. Когда запрос извлекается, этот paged
параметр будет использоваться для определения того, какой набор постраничных постов должен возвращаться. Если щелкнуть отображаемую ссылку нумерации страниц и загрузить следующую страницу, ваш пользовательский запрос не сможет узнать, что нумерация страниц изменилась .
Решение
Передача правильного постраничного параметра в пользовательский запрос
Предполагая, что пользовательский запрос использует массив args:
$custom_query_args = array(
// Custom query parameters go here
);
Вам нужно будет передать правильный paged
параметр в массив. Вы можете сделать это, выбрав переменную URL-запроса, используемую для определения текущей страницы, с помощью get_query_var()
:
get_query_var( 'paged' );
Затем вы можете добавить этот параметр в ваш собственный массив args запроса:
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
Примечание: Если страница является статической первой страницей , убедитесь , что использовать page
вместо paged
как статический титульный лист использует page
и не paged
. Это то, что вы должны иметь для статической главной страницы
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
Теперь при получении пользовательского запроса будет возвращен правильный набор постраничных постов.
Использование пользовательского объекта запроса для функций разбиения на страницы
Чтобы функции разбиения на страницы могли выдавать правильный вывод - т.е. ссылки на предыдущую / следующую / страницу относительно пользовательского запроса - необходимо заставить WordPress распознавать пользовательский запрос. Это требует некоторого «взлома»: замена основного $wp_query
объекта пользовательским объектом запроса $custom_query
:
Взломать основной объект запроса
- Резервное копирование основного объекта запроса:
$temp_query = $wp_query
- Обнулить основной объект запроса:
$wp_query = NULL;
Поменяйте пользовательский запрос на основной объект запроса: $wp_query = $custom_query;
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
Этот «взлом» должен быть сделан перед вызовом любых функций нумерации страниц
Сбросить основной объект запроса
После того, как функции пагинации были выведены, сбросьте основной объект запроса:
$wp_query = NULL;
$wp_query = $temp_query;
Исправления функции пагинации
previous_posts_link()
Функция будет работать в обычном режиме, независимо от пагинации. Он просто определяет текущую страницу, а затем выводит ссылку для page - 1
. Однако для next_posts_link()
правильного вывода требуется исправление . Это потому, что next_posts_link()
использует max_num_pages
параметр:
<?php next_posts_link( $label , $max_pages ); ?>
Как и с другими параметрами запроса, по умолчанию функция будет использоваться max_num_pages
для основного $wp_query
объекта. Для того, чтобы заставить next_posts_link()
учитывать $custom_query
объект, вам нужно будет передать max_num_pages
функцию. Вы можете получить это значение из $custom_query
объекта $custom_query->max_num_pages
:
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
Собираем все вместе
Ниже приведена базовая конструкция пользовательского цикла запроса с правильно функционирующими функциями нумерации страниц:
// Define custom query parameters
$custom_query_args = array( /* Parameters go here */ );
// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );
// Pagination fix
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
// Output custom query loop
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
// Loop output goes here
endwhile;
endif;
// Reset postdata
wp_reset_postdata();
// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );
// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;
Приложение: Как насчет query_posts()
?
query_posts()
для вторичных циклов
Если вы используете query_posts()
для вывода пользовательского цикла, а не создания экземпляра отдельного объекта для пользовательского запроса через WP_Query()
, тогда вы _doing_it_wrong()
столкнетесь с несколькими проблемами (не в последнюю очередь из-за проблем с разбиением на страницы). Первым шагом к решению этих проблем будет преобразование неправильного использования query_posts()
в надлежащий WP_Query()
вызов.
Использование query_posts()
для изменения основного цикла
Если вы просто хотите изменить параметры для основного запроса петли - например, изменения сообщения на страницу, или за исключением категории - вы можете захотеть использовать query_posts()
. Но ты все равно не должен. Когда вы используете query_posts()
, вы заставляете WordPress заменить основной объект запроса. (WordPress фактически делает второй запрос и перезаписывает $wp_query
.) Проблема, однако, заключается в том, что он выполняет эту замену слишком поздно, чтобы обновить нумерацию страниц.
Решение состоит в том, чтобы отфильтровать основной запрос до того, как сообщения будут получены , с помощью pre_get_posts
ловушки.
Вместо добавления этого в файл шаблона категории ( category.php
):
query_posts( array(
'posts_per_page' => 5
) );
Добавьте следующее к functions.php
:
function wpse120407_pre_get_posts( $query ) {
// Test for category archive index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_category() && $query->is_main_query() ) {
// Modify posts per page
$query->set( 'posts_per_page', 5 );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
Вместо добавления этого в файл шаблона индекса постов блога ( home.php
):
query_posts( array(
'cat' => '-5'
) );
Добавьте следующее к functions.php
:
function wpse120407_pre_get_posts( $query ) {
// Test for main blog posts index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_home() && $query->is_main_query() ) {
// Exclude category ID 5
$query->set( 'category__not_in', array( 5 ) );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
Таким образом, WordPress будет использовать уже измененный $wp_query
объект при определении нумерации страниц, без необходимости изменения шаблона.
Когда использовать какую функцию
Исследования на этот вопрос и ответ и на этот вопрос и ответ , чтобы понять , как и когда использовать WP_Query
, pre_get_posts
и query_posts()
.