$GLOBALS['wp_the_query'] против global $wp_query в WordPress
В чем разница между $GLOBALS['wp_the_query']
и global $wp_query
?
Почему следует предпочесть один вариант другому?

Вы упустили один момент, $GLOBALS['wp_query']
. По сути, $GLOBALS['wp_query'] === $wp_query
. Однако $GLOBALS['wp_query']
лучше для читаемости и должен использоваться вместо $wp_query
, НО это остается вопросом личных предпочтений.
В идеальном мире, где единороги правят миром, $GLOBALS['wp_the_query'] === $GLOBALS['wp_query'] === $wp_query
. По умолчанию это должно быть верно. Если посмотреть, где эти глобальные переменные устанавливаются (wp-settings.php
), можно увидеть, что основной объект запроса хранится в $GLOBALS['wp_the_query']
, а $GLOBALS['wp_query']
— это просто его копия.
/**
* Объект запроса WordPress
* @global WP_Query $wp_the_query
* @since 2.0.0
*/
$GLOBALS['wp_the_query'] = new WP_Query();
/**
* Содержит ссылку на @see $wp_the_query
* Используйте эту глобальную переменную для запросов WordPress
* @global WP_Query $wp_query
* @since 1.5.0
*/
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
Причина такого подхода в том, что в версии 1.5 WordPress представил функцию query_posts
.
function query_posts($query) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($query);
}
Как видно, query_posts
перезаписывает основной объект запроса текущим пользовательским запросом. Это нарушает целостность основного объекта запроса, что приводит к некорректным данным, поэтому все, что зависит от него, ломается.
Чтобы решить эту проблему, в версии 2.0.0 была добавлена новая глобальная переменная $GLOBALS['wp_the_query']
, которая хранит основной объект запроса, а $GLOBALS['wp_query']
остается его копией. Теперь с помощью wp_reset_query()
можно восстановить $GLOBALS['wp_query']
до исходного состояния.
Но это не идеальный мир, и query_posts
— настоящее зло. Несмотря на многочисленные предупреждения, люди продолжают его использовать. Помимо нарушения основного запроса, он повторно его выполняет, что делает его медленнее обычного пользовательского запроса с WP_Query
. Многие также забывают сбросить запрос с помощью wp_reset_query()
, что усугубляет проблему.
Поскольку мы не можем запретить плагинам и темам использовать query_posts
и не можем знать, был ли запрос сброшен, нам нужна более надежная копия основного объекта запроса. Здесь полезен $GLOBALS['wp_the_query']
, так как его значение не может быть изменено сторонним кодом (кроме фильтров и действий внутри WP_Query
).
Быстрая проверка:
var_dump( $GLOBALS['wp_the_query'] );
var_dump( $GLOBALS['wp_query'] );
query_posts( 's=crap' );
var_dump( $GLOBALS['wp_the_query'] );
var_dump( $GLOBALS['wp_query'] );
Результат покажет, что $GLOBALS['wp_the_query']
не изменился, а $GLOBALS['wp_query']
— изменился. Так какой вариант надежнее?
Важное замечание: $GLOBALS['wp_the_query']
НЕ заменяет wp_reset_query()
. wp_reset_query()
всегда должен использоваться с query_posts
, а query_posts
вообще никогда не должен использоваться.
ВЫВОД
Если вам нужен надежный код, который почти никогда не подведет, используйте $GLOBALS['wp_the_query']
. Если вы доверяете плагинам и темам и уверены, что никто не использует query_posts
или использует его правильно, можно использовать $GLOBALS['wp_query']
или $wp_query
.
ВАЖНОЕ ДОПОЛНЕНИЕ
Отвечая на вопросы здесь в течение нескольких лет, я видел, как многие пользователи используют $wp_query
как локальную переменную, что также ломает основной объект запроса. Это еще больше увеличивает уязвимость $wp_query
.
Например, некоторые делают так:
$wp_query = new WP_Query( $args );
что по сути то же самое, что делает query_posts
.

query_posts() изменяет global $wp_query
. global $wp_the_query
содержит ссылку на основной запрос

Мой комментарий не был поправкой, так что извините, если это так показалось. Я просто резюмировал (TL;DR, если угодно), отметив то, что считаю одним из наиболее важных аспектов $wp_the_query
в контексте метода WP_Query::is_main_query()
, который не был упомянут :D

@EvanMattson Извините, я неправильно понял ваш первый комментарий ;-). Да, is_main_query()
, который является обёрткой для WP_Query::is_main_query()
, сравнивает текущий объект запроса с основным объектом запроса, сохранённым в $GLOBALS['wp_the_query']
. Это довольно важно, когда вы запускаете действия pre_get_posts
и хотите воздействовать только на основной запрос ;-)

Можешь упомянуть функцию is_main_query
в разделе *ВАЖНОЕ РЕДАКТИРОВАНИЕ? Я сегодня использовал pre_get_posts
и нашел эту функцию чрезвычайно полезной, так как работал с $wp_query
.

Ключевое слово global импортирует переменную в локальную область видимости, тогда как $GLOBALS просто предоставляет доступ к переменной.
Если конкретнее, при использовании global $wp_the_query;
вы можете использовать $wp_the_query
внутри локальной области видимости без повторного указания слова global. По сути, global $wp_the_query
можно сравнить с $wp_the_query = $GLOBALS['wp_the_query']
ИСПРАВЛЕНИЕ
Я перепутал wp_query и wp_the_query, поэтому мой ответ не полностью отвечает на вопрос, но всё же даёт общую информацию о разнице между global $variable
и $GLOBALS['variable']
