Проблема
По умолчанию в любом данном контексте 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()
.
paged
не обновляется (OBV - то делать с Администраторский окружение ajax.php) поэтому я добавил это:global $paged; $paged = $custom_query_args['paged'];
и это сработало :)Я использую этот код для пользовательского цикла с нумерацией страниц:
Источник:
источник
Круто как всегда Чип. В качестве дополнения к этому рассмотрим ситуацию, когда вы используете глобальный шаблон страницы, прикрепленный к странице для некоторого «вводного текста», и за ним следует подзапрос, который вы хотите поместить на страницу.
Используя paginate_links (), как вы упомянули выше, в основном с настройками по умолчанию (и при условии, что у вас включены довольно постоянные ссылки), ваши ссылки на страницы будут по умолчанию
mysite.ca/page-slug/page/#
милыми, но будут выдавать404
ошибки, потому что WordPress не знает об этой конкретной структуре URL и фактически будет ищите дочернюю страницу "page", которая является дочерней для "page-slug".Хитрость заключается в том, чтобы вставить изящное правило перезаписи, которое применяется только к тому конкретному слагу страницы «страница псевдоархива», который принимает
/page/#/
структуру и переписывает ее в строку запроса, которую понимает WordPress CAN, а именноmysite.ca/?pagename=page-slug&paged=#
. Обратите внимание,pagename
аpaged
неname
иpage
(что вызвало у меня буквально ЧАСЫ скорби, мотивируя этот ответ здесь!).Вот правило перенаправления:
Как всегда, при изменении правил перезаписи не забудьте очистить свои постоянные ссылки , зайдя в Настройки> Постоянные ссылки в административной части.
Если у вас есть несколько страниц, которые будут вести себя таким образом (например, при работе с несколькими пользовательскими типами записей), вы можете избежать создания нового правила перезаписи для каждого блока страниц. Мы можем написать более общее регулярное выражение, которое будет работать для любого идентифицируемого фрагмента страницы.
Один подход ниже:
Недостатки / предостережения
Одним из недостатков этого подхода, который заставляет меня немного рвать, является жесткое кодирование слага Пейджа. Если администратор когда-либо изменит плагин этой страницы псевдоархива, вы будете тостом - правило перезаписи больше не будет совпадать, и вы получите страшный 404.
Я не уверен, что могу придумать обходной путь для этого метода, но было бы неплохо, если бы это был глобальный шаблон страницы, который каким-то образом вызвал правило перезаписи. Когда-нибудь я могу вернуться к этому ответу, если никто не сломал этот конкретный орех.
источник
_wp_page_template
, а затем добавить еще одно правило перезаписи и очистки.Отличный ответ Чип должен быть изменен сегодня.
В течение некоторого времени у нас есть
$wp_the_query
переменная, которая должна быть равна$wp_query
глобальной сразу после выполнения основного запроса.Вот почему эта часть из ответа Чипа:
больше не нужен. Мы можем забыть эту часть, создав временную переменную.
Итак, теперь мы можем позвонить:
или даже лучше мы можем позвонить:
Все остальное, обрисованное в общих чертах, остается неизменным. После этой части запроса-сброса вы можете вызывать функции нумерации страниц, которые
f($wp_query)
зависят от$wp_query
глобальных.Чтобы дополнительно улучшить механику разбиения на страницы и дать больше свободы
query_posts
функции, я создал это возможное улучшение:https://core.trac.wordpress.org/ticket/39483
источник
источник