Основне питання
Рити Давайте в тріо: ::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
:
- це те, що ви можете контролювати за допомогою аргументів, які ви передаєте
- за замовчуванням воно жадібне
- вона містить речовину для циклічного циклу
- вона зберігається в глобальному просторі x2
- він може бути первинним або вторинним
- він використовує допоміжні класи
- він має зручний
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
Цей список з версії 4.7 WordPress, безумовно, зміниться в майбутньому.
Це був би мінімальний приклад створення 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 + оператор назначення (=) розумний. Він буде використовувати дрібну копію, а не важку копію об'єкта. Коли ми пишемо так, $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
хитрість.