$GLOBALS['wp_the_query'] против global $wp_query в WordPress

14 мар. 2016 г., 10:12:16
Просмотры: 30.4K
Голосов: 23

В чем разница между $GLOBALS['wp_the_query'] и global $wp_query?

Почему следует предпочесть один вариант другому?

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

Я бы сказал global $wp_query, просто чтобы ответить на ваш вопрос в одной строке!

Sumit Sumit
14 мар. 2016 г. 10:17:40

Какая разница?

Nathan Powell Nathan Powell
14 мар. 2016 г. 10:23:59
Все ответы на вопрос 3
6
34

Вы упустили один момент, $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.

14 мар. 2016 г. 11:31:15
Комментарии

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

Evan Mattson Evan Mattson
15 мар. 2016 г. 21:06:01

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

Evan Mattson Evan Mattson
16 мар. 2016 г. 02:37:20

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

Pieter Goosen Pieter Goosen
16 мар. 2016 г. 06:18:22

Отличный ответ! @EvanMattson Это должно было быть [редактированием].

kaiser kaiser
7 апр. 2016 г. 00:49:58

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

Nathan Powell Nathan Powell
18 мар. 2017 г. 02:50:17

Просто отмечу, что global $name и $GLOBALS['name'] — это синонимы. Они всегда указывают на один и тот же объект. Таким образом, существует только два объекта: global $wp_query и global $wp_the_query

Philipp Philipp
3 сент. 2021 г. 21:58:34
Показать остальные 1 комментариев
1

Ключевое слово 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']

14 мар. 2016 г. 10:27:55
Комментарии

Пожалуйста, оформите это как [правку], так как это не является ответом на исходный вопрос. Для справки: $GLOBALS['foo'] позволяет не только переопределять, но и сбрасывать переменные. Так что это немного больше, чем описано здесь.

kaiser kaiser
7 апр. 2016 г. 00:52:37
0

По сути, один является копией другого.

14 мар. 2016 г. 10:29:21