Когда использовать WP_Query, query_posts() или get_posts()?

13 сент. 2010 г., 15:58:39
Просмотры: 197K
Голосов: 465

Кажется, что половина руководств в Кодексе и блогах использует query_posts(), а другая половина — WP_Query.

Все они делают похожие вещи, так когда же стоит использовать один метод вместо других?

1
Комментарии

Также ознакомьтесь с этим подробным анализом

prosti prosti
25 дек. 2016 г. 23:26:16
Все ответы на вопрос 7
22
748
  • query_posts() — это чрезмерно упрощенный и проблематичный способ изменить основной запрос страницы, заменяя его новым экземпляром запроса. Он неэффективен (повторно выполняет SQL-запросы) и может полностью отказать в некоторых случаях (особенно часто при работе с пагинацией записей). Любой современный код WordPress должен использовать более надежные методы, такие как pre_get_posts, для этой цели. TL;DR: никогда не используйте query_posts().

  • get_posts() очень похож по использованию и принимает те же аргументы (с некоторыми нюансами, такими как разные значения по умолчанию), но возвращает массив записей, не изменяет глобальные переменные и безопасен для использования в любом месте.

  • WP_Query — это класс, который лежит в основе обоих методов, но вы также можете создать и работать с собственным экземпляром этого класса. Немного сложнее, меньше ограничений, также безопасен для использования в любом месте.

Диаграмма сравнения WP_Query, query_posts и get_posts Источник изображения: https://www.rarst.net/images/query_functions.png

13 сент. 2010 г. 16:10:20
Комментарии

(1) "и безопасен для использования где угодно" --> но не используйте это для ОСНОВНОГО цикла. (2) не забудьте использовать global $query_string; перед строкой с query_posts();

edelwater edelwater
19 февр. 2011 г. 10:05:19

@scribu однако 'get_posts' будет работать, хотя и не рекомендуется: http://core.trac.wordpress.org/ticket/16545

edelwater edelwater
19 февр. 2011 г. 10:27:18

Я считаю, что query_posts также менее эффективен, так как он выполняет дополнительные запросы, тогда как если вы используете только WP_Query для основного цикла, будет выполнен только выбранный вами запрос в WP_Query.

jjeaton jjeaton
8 авг. 2011 г. 14:15:09

@jjeaton query_posts() — это небольшая функция-обёртка для WP_Query, единственное дополнительное действие, которое она выполняет (согласно блок-схеме) — это перезапись глобальной переменной $wp_query

Rarst Rarst
8 авг. 2011 г. 15:39:23

@Rarst Я имел в виду этот раздел в Codex для query_posts, однако, возможно, я ошибаюсь насчёт влияния на производительность. Если только использование WP_Query в вашем шаблоне не даст тот же результат (т.е. отбрасывание вашего запроса и его повторное выполнение)

jjeaton jjeaton
8 авг. 2011 г. 16:33:13

@jjeaton Замена query_posts() на WP_Query не повлияет на производительность, исходный запрос страницы всё равно выполнится, так как это часть загрузки ядра. Эти запросы выполнятся, даже если в вашем файле шаблона вообще нет цикла.

Rarst Rarst
8 авг. 2011 г. 17:15:17

Не могу избавиться от ощущения, что это самый гениальный и популярный пост на WPSE. Должен быть и в Codex тоже.

kaiser kaiser
16 сент. 2011 г. 00:03:07

Ладно, после долгого изучения, думаю, что в query_posts() не хватает статической переменной, которая устанавливается в true после первого использования и - если используется дважды - должна вызывать _doing_it_wrong();. Пожалуй, я сообщу об этом ребятам из wp-hacker или trac.

kaiser kaiser
16 сент. 2011 г. 00:06:12

@kaiser ну... использование query_posts() дважды примерно так же плохо, как и один раз, для меня не имеет особого значения. :) кстати, Эндрю Нацин собирается делать презентацию о запросах и сказал, что может предложить некоторые улучшения к блок-схеме, так что вторая версия может появиться в будущем.

Rarst Rarst
16 сент. 2011 г. 09:41:04

Добавлю самое понятное объяснение проблемы "производительности query_posts()": Использование query_posts() или WP_Query в файле шаблона будет иметь одинаковую стоимость производительности: запрос, который вы только что выполнили. Проблема, обсуждаемая в статье кодекса, заключается в том, что если вы действительно хотите заменить запрос, вам следует сделать это, отфильтровав исходный query_posts() с помощью фильтра 'parse_query'. Таким образом, у вас будет только один, исходный, желаемый запрос, вместо выполнения второго запроса для его неуклюжей замены. query_posts() — ЭТО НИКОГДА НЕ ПРАВИЛЬНОЕ РЕШЕНИЕ!! НИКОГДА!

jerclarke jerclarke
19 апр. 2012 г. 22:24:25

Здесь не упоминается фильтр 'request', который является отличным способом изменить основной запрос. Преимущество перед query_posts заключается в том, что эта функция стирает исходный запрос и создает новый — так же, как если бы вы использовали WP_Query. Используя фильтр request, вы изменяете исходный запрос до того, как он будет отправлен. Думаю, это то, о чем говорил @JeremyClarke выше.

eddiemoya eddiemoya
2 мая 2012 г. 19:32:59

Есть потрясающее объяснение query_posts, написанное Джоном Джеймсом Джейкоби в блоге developer.wordpress.com, которое превосходит все эти ответы. Основная мысль: query_posts не изменяет основной цикл, а заменяет его после того, как он уже выполнен. Лучший способ изменить основной цикл — использовать фильтр pre_get_posts.

http://developer.wordpress.com/2012/05/14/querying-posts-without-query_posts/

Dan Gayle Dan Gayle
9 июн. 2012 г. 23:10:48

@Dan ты путаешь техническую реализацию и предназначение. query_posts() действительно заменяет объект основного цикла, но его цель - модифицировать основной цикл. Я также очень люблю фильтры циклов, но вопрос был не об этом. Есть уточняющий вопрос от другого человека на эту тему.

Rarst Rarst
10 июн. 2012 г. 10:44:50

Вопрос звучал: "Когда следует использовать... query_posts()", и согласно логике, представленной в том блог-посте и комментариях выше, ответ, вероятно, - никогда.

Dan Gayle Dan Gayle
11 июн. 2012 г. 20:04:17

если это так плохо, почему тогда query_posts существует?

Manny Fleurmond Manny Fleurmond
10 сент. 2012 г. 17:33:49

@Manny Fleurmond концептуально query_posts() — это попытка упростить концепции основного цикла до уровня тегов шаблонов тем (простота которых является одним из ключевых факторов популярности WP). Однако задача оказалась слишком сложной для тега шаблона. Разработчики ядра действительно высказывали возможность устаревания этой функции, но пока никакого решения по этому поводу не принято.

Rarst Rarst
10 сент. 2012 г. 18:04:30

На самом деле нельзя "использовать где угодно" WP_Query(), я только что попробовал, и она все равно выдает ошибку на $thequery->have_posts(), бесконечная рекурсия, см. http://wordpress.stackexchange.com/questions/34270

NoBugs NoBugs
21 окт. 2014 г. 07:16:37

@NoBugs цикл в том вопросе неправильный, и есть ответ, объясняющий почему.

Rarst Rarst
21 окт. 2014 г. 07:54:12

Аааа, спасибо за это. Наконец-то что-то обрело смысл. Серьёзно, WordPress и их отвратительная документация. Не понимаю, как такое запутанное ПО с плохими стандартами кодирования стало настолько популярным.

racl101 racl101
16 апр. 2015 г. 23:32:31

Нашёл тест скорости между wp_query и get_posts http://www.wpclocked.com/

Anagio Anagio
18 июл. 2015 г. 20:36:53

Я бы доверял такому тесту... ровно на ноль. :) Функция - это очень тонкая обёртка, любые различия будут вызваны небольшими различиями в аргументах и/или хуках.

Rarst Rarst
19 июл. 2015 г. 16:50:45

Нет необходимости в эмоциях, query_posts() — это функция с побочными эффектами: она изменяет глобальную переменную. WordPress переполнен функциями с побочными эффектами. Это не проблема производительности, а вопрос качества кода. Посмотрите https://developer.wordpress.org/reference/functions/query_posts/ и узнайте, что делает query_posts. Используйте WP_Query, если не хотите испортить глобальные переменные.

th00ht th00ht
14 мар. 2020 г. 17:22:07
Показать остальные 17 комментариев
3
96

query_posts — никогда и ни при каких обстоятельствах не используйте query_posts. Помимо того, что сказал @Rarst, главная проблема query_posts заключается в том, что он ломает основной объект запроса (хранится в $wp_query). Множество плагинов и пользовательского кода полагаются на основной объект запроса, поэтому его повреждение означает нарушение функциональности плагинов и пользовательского кода. Одна из таких функций — критически важная функция пагинации, так что, сломав основной запрос, вы сломаете пагинацию.

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

var_dump( $wp_query );
query_posts( '&posts_per_page=-1' );
var_dump( $wp_query );

get_posts и WP_Query — правильные способы создания вторичных запросов (таких как связанные записи, слайдеры, избранный контент и контент на статических главных страницах). Стоит отметить, что не следует использовать ни один из них вместо основного запроса на главной странице, странице записи или любой архивной странице, так как это нарушит работу пагинации. Если нужно изменить основной запрос, используйте pre_get_posts, а не пользовательский запрос. (ОБНОВЛЕНИЕ: для статических главных страниц и обычных страниц см. Использование pre_get_posts на обычных страницах и статических главных страницах*)

По сути, WP_Query используется основным запросом, а также get_posts, но хотя get_posts() использует WP_Query, есть несколько различий:

  • get_posts быстрее, чем WP_Query. Разница зависит от общего количества записей на сайте. Причина в том, что get_posts по умолчанию передаёт 'no_found_rows' => true в WP_Query, что пропускает/законно ломает пагинацию. С 'no_found_rows' => true WP_Query получает количество запрошенных записей и завершает работу, тогда как по умолчанию он продолжает искать все записи, соответствующие запросу, для расчёта пагинации.

    По этой причине get_posts() следует использовать только для запросов без пагинации. Пагинация с get_posts — это настоящий бардак. WP_Query следует использовать для всех запросов с пагинацией.

  • get_posts() не подвержены фильтрам posts_*, тогда как WP_Query подвержен. Причина в том, что get_posts по умолчанию передаёт 'suppress_filters' => true в WP_Query.

  • get_posts имеет несколько дополнительных параметров, таких как include, exclude, numberposts и category. Эти параметры преобразуются в валидные параметры для WP_Query перед передачей. include преобразуется в post__in, exclude — в post__not_in, category — в cat, а numberposts — в posts_per_page. Важно отметить, что все параметры, которые можно передать в WP_Query, работают с get_posts, и вы можете игнорировать стандартные параметры get_posts.

  • get_posts возвращает только свойство $posts объекта WP_Query, тогда как WP_Query возвращает полный объект. Этот объект очень полезен для условных операторов, пагинации и другой полезной информации, которую можно использовать внутри цикла.

  • get_posts не использует стандартный цикл, а цикл foreach для отображения записей. Также по умолчанию недоступны шаблонные теги. Для их использования необходимо вызвать setup_postdata( $post ). WP_Query использует стандартный цикл, и шаблонные теги доступны по умолчанию.

  • get_posts передаёт 'ignore_sticky_posts' => 1 в WP_Query, поэтому по умолчанию игнорирует sticky-записи.

Исходя из вышесказанного, выбор между get_posts и WP_Query зависит от вас и ваших потребностей. Приведённая информация должна помочь вам сделать правильный выбор.

18 июн. 2015 г. 17:46:01
Комментарии

Хотел бы я иметь возможность добавлять ответы в избранное. Это так многое объясняет.

InanisAtheos InanisAtheos
12 июн. 2017 г. 07:17:52

Отличное объяснение!

"get_posts() следует использовать только для запросов без пагинации. Пагинация в get_posts - это сплошная головная боль. WP_Query следует использовать для всех запросов с пагинацией" - по сути, это все, что нужно знать, на мой взгляд.

Bullyen Bullyen
19 апр. 2018 г. 19:27:06

@pieter-goosen, знаешь ли ты, справедливо ли то же самое для WP User Query в сравнении с get_users? Имею в виду часть про производительность.

User User
5 авг. 2021 г. 06:34:29
0
35

Основное различие заключается в том, что query_posts() действительно предназначен только для модификации текущего цикла (Loop). После завершения необходимо сбросить цикл и продолжить работу. Этот метод также немного проще для понимания, просто потому что ваш "запрос" — это, по сути, строка URL, которую вы передаёте функции, например:

query_posts('meta_key=color&meta_value=blue'); 

С другой стороны, WP_Query — это более универсальный инструмент, который больше похож на прямое написание MySQL-запросов, чем query_posts(). Вы также можете использовать его где угодно (не только в цикле), и он не мешает другим выполняемым запросам.

Лично я чаще использую WP_Query. Всё зависит от конкретной ситуации.

13 сент. 2010 г. 16:09:13
0
17

Просто нет необходимости использовать query_posts(). Всё, что делает эта функция — создаёт новый объект WP_Query и перезаписывает им global wp_query.

Для справки, вот фактический код функции query_posts():

 function query_posts($query) {
        $GLOBALS['wp_query'] = new WP_Query();
        return $GLOBALS['wp_query']->query($query);
    }

Создавайте свой собственный объект WP_Query, если вам нужно реализовать сложный пользовательский запрос. Или используйте get_posts(), если вам требуется лишь небольшая модификация запросов.

В любом случае, я настоятельно рекомендую открыть wp_includes/query.php и изучить класс WP_Query.

13 июл. 2013 г. 16:38:02
0
16

Убедитесь, что вы используете wp_reset_query() после query_posts(), так как это может повлиять на другие результаты запросов.

8 июл. 2013 г. 04:50:45
0
12

Если я правильно помню прочитанное, по сути "цикл" выполняет WP_Query в основных файлах, но в более понятной форме.

23 сент. 2010 г. 20:21:34
0
  • query_posts(): может использоваться только в одном случае — если вам нужно изменить основной запрос. Устанавливает множество глобальных переменных;
  • get_posts(): работает очень похоже и принимает те же аргументы, но возвращает массив записей
  • WP_Query: вы можете создавать и работать с собственным объектом этого класса. Немного сложнее, меньше ограничений, безопасно использовать где угодно.
19 июл. 2017 г. 14:28:38