Проблема
За замовчуванням у будь-якому даному контексті 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' );
Потім ви можете додати цей параметр до власного масиву аргументів запитів:
$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()
.