Как исправить разбиение на страницы для пользовательских циклов?

Я добавил пользовательский /вторичный запрос к шаблону шаблона /настраиваемому шаблону страницы; как я могу заставить WordPress использовать свой пользовательский запрос для разбивки на страницы, вместо того, чтобы использовать разбиение на страницы основного запроса?

Добавление

Я изменил основной запрос цикла с помощью query_posts () . Почему не работает pagination, и как я могу исправить это?

108 голосов | спросил Chip Bennett 28 +04002013-10-28T23:00:53+04:00312013bEurope/MoscowMon, 28 Oct 2013 23:00:53 +0400 2013, 23:00:53

5 ответов


185

Проблема

По умолчанию в любом контексте WordPress использует основной запрос для определения разбивки на страницы. Основной объект запроса хранится в глобальном файле $ wp_query, который также используется для вывода основного цикла запроса:

if (has_posts ()): while (has_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 () , < a href = "http://codex.wordpress.org/Function_Reference/next_posts_link" rel = "noreferrer"> next_posts_link () , posts_nav_link () и paginate_links () , основывайте свой вывод на главном объекте , $ wp_query. Этот основной запрос может быть или не быть разбит на страницы. Если текущий контекст является настраиваемым шаблоном страницы, например, основной объект $ wp_query будет состоять только из одиночного сообщения - идентификатора идентификатора страницы, на который настраивается шаблон настраиваемой страницы.

Если текущий контекст является некоторым архивным индексом, основной $ wp_query может состоять из достаточно сообщений, чтобы вызвать разбиение на страницы, что приводит к следующей части проблемы: для основного <кода > $ wp_query, WordPress передаст запрос paged, на основе переменной запроса URL-кода paged. Когда запрос будет извлечен, этот параметр paged будет использоваться для определения того, какой набор paginated posts для возврата. Если щелкнуть отображаемую ссылку на страницы и загрузить следующую страницу, , ваш пользовательский запрос не сможет каким-либо образом узнать, что постраничная страница изменилась .

Решение

Передача правильного выгружаемого параметра в пользовательский запрос

Предполагая, что пользовательский запрос использует массив args:

$ custom_query_args = array (
    //Параметры пользовательского запроса идут здесь
);

Вам нужно будет передать правильный массив 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:

Взломать основной объект запроса

  1. Резервное копирование основного объекта запроса: $ temp_query = $ wp_query
  2. Null главный объект запроса: $ wp_query = NULL;
  3. Сменить пользовательский запрос в основной объект запроса: $ 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 ('Старые сообщения', $ custom_query-> max_num_pages); ? >

Объединяя все это

Ниже приведена базовая конструкция настраиваемого цикла запросов с правильно функционирующими функциями разбиения на страницы:

//Определение пользовательских параметров запроса
$ custom_query_args = array (/* Параметры идут сюда * /);

//Получить текущую страницу и добавить к настраиваемому массиву параметров запроса
$ custom_query_args ['paged'] = get_query_var ('paged')? get_query_var ('paged'): 1;

//Создание пользовательского запроса
$ custom_query = новый WP_Query ($ custom_query_args);

//Фиксация пагинации
$ temp_query = $ wp_query;
$ wp_query = NULL;
$ wp_query = $ custom_query;

//Вывод настраиваемого цикла запроса
if ($ custom_query-> have_posts ()):
    while ($ custom_query-> have_posts ()):
        $ Custom_query- > the_post ();
        //Выход цикла происходит здесь
    ENDWHILE;
ENDIF;
//Сброс postdata
wp_reset_postdata ();

//Пользовательская разбивка цепочки запросов
previous_posts_link («Старые записи»);
next_posts_link ('Новые сообщения', $ custom_query-> max_num_pages);

//Сброс основного объекта запроса
$ 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 (массив (
    'posts_per_page' => 5
));

Добавьте следующий код в functions.php:

функция wpse120407_pre_get_posts ($ query) {
    //Тест индекса индекса категории
    //и убедитесь, что запрос является основным запросом
    //а не вторичный запрос (например, навигационное меню
    //или последние выпуски виджетов сообщений и т. д.
    if (is_category () & & $ query-> is_main_query ()) {
        //Изменить сообщения на страницу
        $ query-> set ('posts_per_page', 5);
    }
}
add_action ('pre_get_posts', 'wpse120407_pre_get_posts');

Вместо добавления этого в файл шаблона индекса сообщений блога (home.php):

query_posts (массив (
    'cat' => '-5'
));

Добавьте следующий код в functions.php:

функцияwpse120407_pre_get_posts ($ query) {
    //Тест для основного индекса сообщений блога
    //и убедитесь, что запрос является основным запросом
    //а не вторичный запрос (например, навигационное меню
    //или последние выпуски виджетов сообщений и т. д.
    if (is_home () & & $ query-> is_main_query ()) {
        //Исключить категорию 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 () .

ответил Chip Bennett 28 +04002013-10-28T23:00:53+04:00312013bEurope/MoscowMon, 28 Oct 2013 23:00:53 +0400 2013, 23:00:53
19

Я использую этот код для настраиваемого цикла с разбивкой на страницы:

& л;? PHP
if (get_query_var ('paged')) {
    $ paged = get_query_var ('paged');
} elseif (get_query_var ('page')) {//'page' используется вместо 'paged' на странице Static Front
    $ paged = get_query_var ('page');
} else {
    $ paged = 1;
}

$ custom_query_args = массив (
    'post_type' => 'после',
    'posts_per_page' => get_option ( 'posts_per_page'),
    'paged' => $ Выгружаемого,
    'post_status' => 'публиковать',
    'ignore_sticky_posts' => правда,
    //'category_name' => 'Заказ кота,
    'order' => 'DESC', //'ASC'
    'orderby' => 'date' //изменено | название | имя | ID | рант
);
$ custom_query = новый WP_Query ($ custom_query_args);

if ($ custom_query-> have_posts ()):
    while ($ custom_query-> have_posts ()): $ custom_query-> the_post (); ? >

        <article <? php post_class (); ? > >
            <h3> <a href = "<php the_permalink ();> & quot; <& phis; the_title (); ? > & Lt; /а > & Lt; /h3 >
            <small> <php the_time ('F jS, Y')?> по <php the_author_posts_link ()?> </small>
            <div> <php the_excerpt (); ? > & Lt; /дел >
        & Lt; /& статья GT;

    & Lt;? PHP
    ENDWHILE;
    ? >

    <? php if ($ custom_query-> max_num_pages> 1): //пользовательская разбивка на страницы>
        & Lt;? PHP
        $ orig_query = $ wp_query; //исправление для разбивки на страницы
        $ wp_query = $ custom_query;
        ? >
        <nav class = "prev-next-posts">
            <div class = "prev-posts-link">
                <? php echo get_next_posts_link («Старые записи», $ custom_query-> max_num_pages); ? >
            & Lt; /дел >
            <div class = "next-posts-link">
                <? php echo get_previous_posts_link («Новые записи»); ? >
            & Lt; /дел >
        & Lt; /нав >
        & Lt;? PHP
        $ wp_query = $ orig_query; //исправление для разбивки на страницы
        ? >
    <? php endif; ? >

& Lt;? PHP
    wp_reset_postdata (); //сброс запроса
еще:
    echo '<p>' .__ ('Извините, никакие сообщения не соответствовали вашим критериям.'). '</p>';
ENDIF;
? >

Источник:

ответил webvitaly 9 12015vEurope/Moscow11bEurope/MoscowMon, 09 Nov 2015 19:27:40 +0300 2015, 19:27:40
4

Удивительный, как всегда, Чип. В качестве дополнения к этому рассмотрите ситуацию, когда вы используете шаблон глобальной страницы, прикрепленный к странице, для некоторого «вводного текста», а за ним следует подзапрос, который вы хотите выгрузить.

Используя paginate_links () , как вы упомянули выше, в основном по умолчанию, (и предполагая, что вы у вас есть довольно постоянные ссылки), ваши ссылки на страницы будут по умолчанию равны mysite.ca/page-slug/page /#, которые прекрасны, но будут бросать ошибки 404, потому что WordPress не делает знать об этой конкретной структуре URL-адреса и фактически искать дочернюю страницу «страницы», которая является дочерней страницей «page-slug».

Трюк здесь заключается в том, чтобы вставить правильное правило перезаписи, которое применяется только к этой странице «страница псевдостраничной страницы», которая принимает структуру /page /# / и переписывает ее в строку запроса, которая WordPress МОЖЕТ понять, а именно mysite.ca/?pagename=page-slug&paged = #. Примечание pagename и paged not name и page (что вызвало у меня буквально ЧАСЫ горя, мотивируя этот ответ здесь! ).

Вот правило перенаправления:

add_rewrite_rule ("page-slug /page /([0-9] {1,}) /? $", 'index.php? pagename = page-slug & paged = $ matches [1]' , "Вверх" );

Как всегда, при изменении правил перезаписи помните снимите свои постоянные ссылки , посетив Настройки> Постоянная ссылка в интерфейсе администратора.

Если у вас есть несколько страниц, которые будут вести себя таким образом (например, при работе с несколькими настраиваемыми типами сообщений), вам может потребоваться избежать создания нового правила перезаписи для каждого пула страниц. Мы можем написать более общее регулярное выражение, которое работает для любого идентификатора страницы, который вы идентифицируете.

Ниже приведен один подход:

function wpse_120407_pseudo_archive_rewrite () {
    //Добавьте пули страниц, которые используют Глобальный шаблон, чтобы имитировать страницу «Архив»
    $ pseudo_archive_pages = массив (
        «все-кино»,
        «все-актеры»
    );

    $ slug_clause = implode ("|", $ pseudo_archive_pages);
    add_rewrite_rule ("($ slug_clause) /page /([0-9] {1,}) /? $", 'index.php? pagename = $ matches [1] & paged = $ matches [2]', Вверх" );
}
add_action ('init', 'wpse_120407_pseudo_archive_rewrite');

Недостатки /Предостережения

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

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

ответил Tom Auger 17 SatEurope/Moscow2016-12-17T03:49:08+03:00Europe/Moscow12bEurope/MoscowSat, 17 Dec 2016 03:49:08 +0300 2016, 03:49:08
2
  

Я изменил основной запрос цикла с помощью query_posts (). Почему не работает постраничная разбивка, и как ее исправить?

Великий ответ Созданный чип должен быть изменен сегодня. В течение некоторого времени у нас есть переменная $ wp_the_query, которая должна быть равна глобальному $ wp_query сразу после выполнения основного запроса.

Вот почему это часть ответа Чипа:

  

Взломать основной объект запроса

больше не требуется. Мы можем забыть эту часть с созданием временной переменной.

//Фиксация пагинации
$ temp_query = $ wp_query;
$ wp_query = NULL;
$ wp_query = $ custom_query;

Итак, теперь мы можем позвонить:

$ wp_query = $ wp_the_query;

или даже лучше, мы можем позвонить:

wp_reset_query ();

Все остальные чипы указаны. После этой части запроса-сброса вы можете вызвать функции разбиения на страницы, которые являются f ($ wp_query), â € ", они зависят от глобального кода $ wp_query.


Чтобы еще больше улучшить механику разбиения на страницы и предоставить больше свободы функции query_posts, я создал это возможное улучшение:

https://core.trac.wordpress.org/ticket/39483

ответил prosti 14 Jam1000000amSat, 14 Jan 2017 00:21:24 +030017 2017, 00:21:24
1
глобальный $ wp_query;
        $ paged = get_query_var ('paged', 1);

    $ args = array (
        'post_type' => '{Your_post_type_name}',
        'meta_query' => array ('{добавить аргумент мета запроса в случае необходимости}'),
        'orderby' => «Модифицированный»,
        'order' => 'DESC',
        'posts_per_page' => 20,
        'paged' => $ выгружаемого
    );
    $ query = new WP_Query ($ args);

    если ($ query- > have_posts ()):
        while ($ query-> have_posts ()): $ query-> the_post ();
            //добавьте свой код здесь
        ENDWHILE;
        wp_reset_query ();

        //управлять разбиением на страницы на основе пользовательского запроса.
        $ GLOBALS ['wp_query'] -> max_num_pages = $ query-> max_num_pages;
        the_posts_pagination (массив (
            'mid_size' => 1,
            'prev_text' => __ ('Предыдущая страница', 'patelextensions'),
            'next_text' => __ ('Следующая страница', 'patelextensions'),
            'before_page_number' => '<span class = "meta-nav screen-reader-text">' , __ ('Страница', 'patelextensions'). '</span>',
        ));
    еще:
    ? >
        <div class = "text-center контейнера" ​​> <php echo _d ('Результат не найден', '30'); ? > & Lt; /дел >
    & Lt;? PHP
        ENDIF;
    ? >
ответил ravi patel 6 MarpmTue, 06 Mar 2018 12:39:57 +03002018-03-06T12:39:57+03:0012 2018, 12:39:57

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132