Существенный вопрос
Давайте копаться в трио ::query_posts
, ::get_posts
и лучше class WP_Query
понять ::query_posts
.
Краеугольным камнем для получения данных в WordPress является WP_Query
класс. Оба метода ::query_posts
и ::get_posts
используют этот класс.
Обратите внимание, что класс WP_Query
также содержит методы с одинаковыми именами: WP_Query::query_posts
и WP_Query::get_posts
, но на самом деле мы рассматриваем только глобальные методы, поэтому не путайтесь.
Понимание WP_Query
WP_Query
Вызванный класс был введен еще в 2004 году. Все поля, отмеченные знаком ☂ (зонтик), присутствовали еще в 2004 году. Дополнительные поля были добавлены позже.
Вот WP_Query
структура:
class WP_Query (as in WordPress v4.7)
public $query; ☂
public $query_vars = array(); ☂
public $tax_query;
public $meta_query = false;
public $date_query = false;
public $queried_object; ☂
public $queried_object_id; ☂
public $request;
public $posts; ☂
public $post_count = 0; ☂
public $current_post = -1; ☂
public $in_the_loop = false;
public $post; ☂
public $comments;
public $comment_count = 0;
public $current_comment = -1;
public $comment;
public $found_posts = 0;
public $max_num_pages = 0;
public $max_num_comment_pages = 0;
public $is_single = false; ☂
public $is_preview = false; ☂
public $is_page = false; ☂
public $is_archive = false; ☂
public $is_date = false; ☂
public $is_year = false; ☂
public $is_month = false; ☂
public $is_day = false; ☂
public $is_time = false; ☂
public $is_author = false; ☂
public $is_category = false; ☂
public $is_tag = false;
public $is_tax = false;
public $is_search = false; ☂
public $is_feed = false; ☂
public $is_comment_feed = false;
public $is_trackback = false; ☂
public $is_home = false; ☂
public $is_404 = false; ☂
public $is_embed = false;
public $is_paged = false;
public $is_admin = false; ☂
public $is_attachment = false;
public $is_singular = false;
public $is_robots = false;
public $is_posts_page = false;
public $is_post_type_archive = false;
private $query_vars_hash = false;
private $query_vars_changed = true;
public $thumbnails_cached = false;
private $stopwords;
private $compat_fields = array('query_vars_hash', 'query_vars_changed');
private $compat_methods = array('init_query_flags', 'parse_tax_query');
private function init_query_flags()
WP_Query
швейцарский армейский нож
Некоторые вещи о WP_Query
:
- это то, что вы можете контролировать с помощью аргументов, которые вы передаете
- это жадный по умолчанию
- он содержит вещество для цикла
- он сохраняется в глобальном пространстве х2
- это может быть первичным или вторичным
- он использует вспомогательные классы
- у него есть удобный
pre_get_posts
крюк
- он даже поддерживает вложенные циклы
- он содержит строку запроса SQL
- он содержит количество результатов
- это держит результаты
- он содержит список всех возможных аргументов запроса
- он содержит флаги шаблона
- ...
Я не могу объяснить все это, но некоторые из них являются хитрыми, поэтому давайте предоставим короткие советы.
WP_Query
это то, что вы можете контролировать с помощью аргументов, которые вы передаете
The list of the arguments
---
attachment
attachment_id
author
author__in
author__not_in
author_name
cache_results
cat
category__and
category__in
category__not_in
category_name
comments_per_page
day
embed
error
feed
fields
hour
ignore_sticky_posts
lazy_load_term_meta
m
menu_order
meta_key
meta_value
minute
monthnum
name
no_found_rows
nopaging
order
p
page_id
paged
pagename
post__in
post__not_in
post_name__in
post_parent
post_parent__in
post_parent__not_in
post_type
posts_per_page
preview
s
second
sentence
static
subpost
subpost_id
suppress_filters
tag
tag__and
tag__in
tag__not_in
tag_id
tag_slug__and
tag_slug__in
tb
title
update_post_meta_cache
update_post_term_cache
w
year
Этот список из WordPress версии 4.7 обязательно изменится в будущем.
Это будет минимальный пример создания WP_Query
объекта из аргументов:
// WP_Query arguments
$args = array ( /* arguments*/ );
// creating the WP_Query object
$query = new WP_Query( $args );
// print full list of arguments WP_Query can take
print ( $query->query_vars );
WP_Query
жадный
Созданные на основе идеи, get all you can
разработчики WordPress решили получить все возможные данные на ранней стадии, поскольку это хорошо для производительности . Вот почему по умолчанию, когда запрос получает 10 сообщений из базы данных, он также получает термины и метаданные для этих сообщений через отдельные запросы. Термины и метаданные будут кэшироваться (предварительно выбираться).
Обратите внимание, что кэширование только для времени жизни одного запроса.
Вы можете отключить кэширование , если вы установите update_post_meta_cache
и update_post_term_cache
в false
процессе настройки WP_Query
параметров. Когда кэширование отключено, данные будут запрашиваться из базы данных только по запросу.
Для большинства блогов WordPress кэширование работает хорошо, но в некоторых случаях вы можете отключить кэширование.
WP_Query
использует вспомогательные классы
Если вы проверили WP_Query
поля там у вас есть эти три:
public $tax_query;
public $meta_query;
public $date_query;
Вы можете представить добавление нового в будущем.
WP_Query
содержит вещество для цикла
В этом коде:
$query = new WP_Query( $args )
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
Вы можете заметить, что WP_Query
имеет субстанцию, которую вы можете повторить. Есть и вспомогательные методы. Вы просто установите while
цикл.
Заметка. for
и while
петли семантически эквивалентны.
WP_Query
первичный и вторичный
В WordPress у вас есть один первичный и ноль или более вторичных запросов.
Возможно не иметь основной запрос, но это выходит за рамки этой статьи.
Основной запрос, известный как основной запрос или обычный запрос . Вторичный запрос также называется пользовательским запросом .
WordPress WP_Rewrite
рано использует класс для создания аргументов запроса на основе URL. На основании этих аргументов он хранит два идентичных объекта в глобальном пространстве. Оба они будут содержать основной запрос.
global $wp_query @since WordPress 1.5
global $wp_the_query @since WordPress 2.1
Когда мы говорим основной запрос, мы думаем об этих переменных. Другие запросы можно назвать вторичными или заказными.
Вполне допустимо использовать либо global $wp_query
или $GLOBALS['wp_query']
, но использование второй нотации намного более заметно и экономит ввод дополнительной строки внутри области функций.
$GLOBALS['wp_query']
и $GLOBALS['wp_the_query']
являются отдельными объектами. $GLOBALS['wp_the_query']
должен оставаться замороженным.
WP_Query
имеет удобный pre_get_posts
крюк.
Это хук действия. Это будет применяться к любому WP_Query
экземпляру. Вы называете это как:
add_action( 'pre_get_posts', function($query){
if ( is_category() && $query->is_main_query() ) {
// set your improved arguments
$query->set( ... );
...
}
return $query;
});
Этот хук великолепен и может изменять любые аргументы запроса.
Вот что вы можете прочитать :
Запускается после создания объекта переменной запроса, но до запуска фактического запроса.
Так что этот хук является менеджером аргументов, но не может создавать новые WP_Query
объекты. Если у вас был один основной и один дополнительный запросы, pre_get_posts
не можете создать третий. Или, если у вас был только один основной, он не может создать дополнительный.
Обратите внимание, что если вам нужно изменить основной запрос, то вы также можете использовать request
хук.
WP_Query
поддерживает вложенные циклы
Этот сценарий может произойти, если вы используете плагины и вызываете функции плагина из шаблона.
Вот пример WordPress, демонстрирующий вспомогательные функции даже для вложенных циклов:
global $id;
while ( have_posts() ) : the_post();
// the custom $query
$query = new WP_Query( array( 'posts_per_page' => 5 ) );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) : $query->the_post();
echo '<li>Custom ' . $id . '. ' . get_the_title() . '</li>';
endwhile;
}
wp_reset_postdata();
echo '<li>Main Query ' . $id . '. ' . get_the_title() . '</li>';
endwhile;
Выходные данные будут такими, поскольку я установил данные тестового модуля темы :
Custom 100. Template: Sticky
Custom 1. Hello world!
Custom 10. Markup: HTML Tags and Formatting
Custom 11. Markup: Image Alignment
Custom 12. Markup: Text Alignment
Custom 13. Markup: Title With Special Characters
Main Query 1. Hello world!
Несмотря на то, что я запросил 5 постов в пользовательском запросе $, он вернет мне шесть, потому что липкое сообщение будет работать. Если нет wp_reset_postdata
в предыдущем примере, вывод будет таким, потому что $GLOBALS['post']
будет недействительным.
Custom 1001. Template: Sticky
Custom 1. Hello world!
Custom 10. Markup: HTML Tags and Formatting
Custom 11. Markup: Image Alignment
Custom 12. Markup: Text Alignment
Custom 13. Markup: Title With Special Characters
Main Query 13. Markup: Title With Special Characters
WP_Query
имеет wp_reset_query
функцию
Это как кнопка сброса. $GLOBALS['wp_the_query']
должны быть заморожены все время, и плагины или темы никогда не должны изменять это.
Вот что wp_reset_query
делать:
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
Замечания по get_posts
get_posts
похоже
File: /wp-includes/post.php
1661: function get_posts( $args = null ) {
1662: $defaults = array(
1663: 'numberposts' => 5,
1664: 'category' => 0, 'orderby' => 'date',
1665: 'order' => 'DESC', 'include' => array(),
1666: 'exclude' => array(), 'meta_key' => '',
1667: 'meta_value' =>'', 'post_type' => 'post',
1668: 'suppress_filters' => true
1669: );
... // do some argument parsing
1685: $r['ignore_sticky_posts'] = true;
1686: $r['no_found_rows'] = true;
1687:
1688: $get_posts = new WP_Query;
1689: return $get_posts->query($r);
Номера строк могут измениться в будущем.
Это просто обертка вокруг того, WP_Query
что возвращает на посты объекта запроса.
Значение ignore_sticky_posts
true означает, что прикрепленные сообщения могут появляться только в естественном положении. Там не будет никаких липких сообщений в передней части. Другое no_found_rows
значение true означает, что API базы данных WordPress не будет использоваться SQL_CALC_FOUND_ROWS
для реализации нумерации страниц, уменьшая нагрузку на базу данных для выполнения числа найденных строк .
Это удобно, когда вам не нужна нумерация страниц. Теперь мы понимаем, что можем подражать этой функции с помощью этого запроса:
$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );
Вот соответствующий запрос SQL:
SELECT wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 10
Сравните то, что мы имеем сейчас, с предыдущим SQL-запросом, если SQL_CALC_FOUND_ROWS
таковой существует.
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 10
Запрос без SQL_CALC_FOUND_ROWS
будет быстрее.
Замечания по query_posts
Совет: сначала в 2004 году было только global $wp_query
. Начиная с версии WordPress 2.1 $wp_the_query
пришла. Совет: $GLOBALS['wp_query']
и $GLOBALS['wp_the_query']
являются отдельными объектами.
query_posts()
это WP_Query
обертка. Возвращает ссылку на основной WP_Query
объект и одновременно устанавливает global $wp_query
.
File: /wp-includes/query.php
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
В PHP4 все, включая объекты, передавалось по значению. query_posts
было так:
File: /wp-includes/query.php (WordPress 3.1)
function &query_posts($args) {
unset($GLOBALS['wp_query']);
$GLOBALS['wp_query'] =& new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
Обратите внимание, что в типичном сценарии с одним основным и одним дополнительным запросом у нас есть эти три переменные:
$GLOBALS['wp_the_query']
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary
Допустим, каждый из этих трех занимает 1М памяти. Всего будет 3М памяти. Если мы используем query_posts
, $GLOBALS['wp_query']
будет сброшен и создан снова.
PHP5 + должен быть умным, опустошая $GLOBALS['wp_query']
объект, так же, как в PHP4 мы делали это сunset($GLOBALS['wp_query']);
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
В результате query_posts
в общей сложности потребляется 2М памяти, в то время как get_posts
потребляется 3М памяти.
Обратите внимание, что query_posts
мы не возвращаем реальный объект, а ссылку на объект.
С php.net : ссылка на PHP - это псевдоним, который позволяет двум разным переменным записывать одно и то же значение. Начиная с PHP 5, переменная объекта больше не содержит сам объект в качестве значения. Он содержит только идентификатор объекта, который позволяет методам доступа к объекту найти фактический объект. Когда объект отправляется с помощью аргумента, возвращается или присваивается другой переменной, различные переменные не являются псевдонимами: они содержат копию идентификатора, который указывает на тот же объект.
Также в PHP5 + оператор assign (=) является умным. Он будет использовать мелкую копию, а не твердую копию объекта. Когда мы пишем так, $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
копируются будут только данные, а не весь объект, поскольку они имеют один и тот же тип объекта.
Вот один пример
print( md5(serialize($GLOBALS['wp_the_query']) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
query_posts( '' );
print( md5(serialize($GLOBALS['wp_the_query']) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Приведет к:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
d6db1c6bfddac328442e91b6059210b5
Попробуйте сбросить запрос:
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
query_posts( '' );
wp_reset_query();
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Приведет к:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
Вы можете создавать проблемы, даже если вы используете WP_Query
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
global $wp_query;
$wp_query = new WP_Query( array( 'post_type' => 'post' ) );
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Конечно, решением было бы снова использовать wp_reset_query
функцию.
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
global $wp_query;
$wp_query = new WP_Query( array( 'post_type' => 'post' ) );
wp_reset_query();
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Вот почему я думаю, что query_posts
может быть лучше с точки зрения памяти. Но вы всегда должны делать wp_reset_query
трюк.