Istotne pytanie
Dig w trio Powiedzmy: ::query_posts
, ::get_posts
i class WP_Query
zrozumieć ::query_posts
lepiej.
Podstawą do uzyskania danych w WordPress jest WP_Query
klasa. Obie metody ::query_posts
i ::get_posts
użyj tej klasy.
Zauważ, że klasa WP_Query
zawiera również metody o tej samej nazwie: WP_Query::query_posts
i WP_Query::get_posts
, ale w rzeczywistości rozważamy tylko metody globalne, więc nie daj się zwieść.
Zrozumienie WP_Query
WP_Query
Nazwana klasa została wprowadzona w 2004 roku. Wszystkie pola oznaczone znakiem umbrella (parasol) były obecne w 2004 roku. Dodatkowe pola zostały dodane później.
Oto WP_Query
struktura:
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
to szwajcarski scyzoryk.
Niektóre rzeczy na temat WP_Query
:
- można to kontrolować za pomocą przekazywanych argumentów
- domyślnie jest chciwy
- zawiera substancję do zapętlenia
- jest zapisany w globalnej przestrzeni x2
- może być pierwotny lub wtórny
- wykorzystuje klasy pomocnicze
- ma poręczny
pre_get_posts
haczyk
- obsługuje nawet zagnieżdżone pętle
- przechowuje ciąg zapytania SQL
- zawiera liczbę wyników
- trzyma wyniki
- przechowuje listę wszystkich możliwych argumentów zapytania
- zawiera flagi szablonu
- ...
Nie potrafię tego wyjaśnić, ale niektóre z nich są trudne, więc podajmy krótkie wskazówki.
WP_Query
możesz kontrolować za pomocą przekazywanych argumentów
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
Ta lista z WordPress w wersji 4.7 z pewnością zmieni się w przyszłości.
Byłby to minimalny przykład tworzenia WP_Query
obiektu na podstawie argumentów:
// 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
jest chciwy
Stworzony na podstawie pomysłu, że get all you can
programiści WordPress postanowili uzyskać wszystkie możliwe dane wcześniej, ponieważ jest to dobre dla wydajności . Dlatego domyślnie, gdy zapytanie pobiera 10 postów z bazy danych, będzie również otrzymywać warunki i metadane dla tych postów za pośrednictwem oddzielnych zapytań. Warunki i metadane będą buforowane (wstępnie pobierane).
Uwaga: buforowanie dotyczy tylko jednego życia żądania.
Można wyłączyć buforowanie po ustawieniu update_post_meta_cache
i update_post_term_cache
aby false
podczas ustawiania WP_Query
argumenty. Gdy buforowanie jest wyłączone, dane będą pobierane z bazy danych tylko na żądanie.
W przypadku większości blogów WordPress buforowanie działa dobrze, ale w niektórych przypadkach możesz wyłączyć buforowanie.
WP_Query
używa klas pomocniczych
Jeśli WP_Query
zaznaczyłeś tam pola, masz te trzy:
public $tax_query;
public $meta_query;
public $date_query;
Możesz sobie wyobrazić dodawanie nowych w przyszłości.
WP_Query
zatrzymuje substancję do zapętlenia
W tym kodzie:
$query = new WP_Query( $args )
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
możesz zauważyć, że WP_Query
ma substancję, którą możesz iterować. Istnieją również metody pomocnicze. Właśnie ustawiłeś while
pętlę.
Uwaga. for
a while
pętle są semantycznie równoważne.
WP_Query
Pierwszy i drugi
W WordPress masz jedno podstawowe i zero lub więcej wtórnych zapytań.
Możliwe, że nie ma podstawowego zapytania, ale wykracza to poza zakres tego artykułu.
Zapytanie podstawowe znane jako zapytanie główne lub zapytanie zwykłe . Drugie zapytanie nazywane jest również niestandardowym .
WordPress używa WP_Rewrite
klasy wcześnie, aby utworzyć argumenty zapytania na podstawie adresu URL. Na podstawie tych argumentów przechowuje dwa identyczne obiekty w przestrzeni globalnej. Oba będą zawierać główne zapytanie.
global $wp_query @since WordPress 1.5
global $wp_the_query @since WordPress 2.1
Kiedy mówimy główne zapytanie , myślimy o tych zmiennych. Inne zapytania można nazwać drugorzędnymi lub niestandardowymi.
Używanie jednego global $wp_query
lub $GLOBALS['wp_query']
drugiego jest całkowicie legalne , ale użycie drugiej notacji jest znacznie bardziej zauważalne i pozwala zaoszczędzić wpisywanie dodatkowej linii w zakresie funkcji.
$GLOBALS['wp_query']
i $GLOBALS['wp_the_query']
są osobnymi obiektami. $GLOBALS['wp_the_query']
powinien pozostać zamrożony.
WP_Query
ma poręczny pre_get_posts
haczyk.
To jest hak akcji. Będzie miało zastosowanie do dowolnej WP_Query
instancji. Nazywasz to tak:
add_action( 'pre_get_posts', function($query){
if ( is_category() && $query->is_main_query() ) {
// set your improved arguments
$query->set( ... );
...
}
return $query;
});
Ten haczyk jest świetny i może zmieniać dowolne argumenty zapytania.
Oto, co możesz przeczytać :
Uruchamia się po utworzeniu obiektu zmiennej zapytania, ale przed uruchomieniem rzeczywistego zapytania.
Ten hak jest menedżerem argumentów, ale nie może tworzyć nowych WP_Query
obiektów. Jeśli masz jedno zapytanie podstawowe i jedno dodatkowe, pre_get_posts
nie możesz utworzyć trzeciego. Lub jeśli masz tylko jeden element główny, nie może utworzyć elementu dodatkowego.
Uwaga: w przypadku potrzeby zmiany głównego zapytania tylko Ty możesz użyć request
haka.
WP_Query
obsługuje zagnieżdżone pętle
Ten scenariusz może się zdarzyć, jeśli korzystasz z wtyczek i wywołujesz funkcje wtyczek z szablonu.
Oto przykładowy przykład WordPress ma funkcje pomocnicze nawet dla zagnieżdżonych pętli:
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;
Wynik będzie taki, ponieważ zainstalowałem dane testu jednostki tematycznej :
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!
Mimo że poprosiłem o 5 postów w niestandardowym zapytaniu $, zwróci mi sześć, ponieważ post przyklei się. Jeśli nie ma wp_reset_postdata
w poprzednim przykładzie, wynik będzie taki, ponieważ $GLOBALS['post']
będzie nieprawidłowy.
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
ma wp_reset_query
funkcję
To jest jak przycisk resetowania. $GLOBALS['wp_the_query']
powinien być cały czas zamrożony, a wtyczki lub motywy nigdy nie powinny go zmieniać.
Oto co wp_reset_query
robią:
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
Uwagi na temat get_posts
get_posts
wygląda jak
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);
Numery linii mogą ulec zmianie w przyszłości.
To jest po prostu otoki wokół WP_Query
, że wraca zapytaniu posty obiektu.
ignore_sticky_posts
Ustawiona na true oznacza lepkie wpisy mogą pojawić się tylko w naturalnej pozycji. Z przodu nie będzie lepkich słupków. Drugi no_found_rows
zestaw wartości true oznacza, że interfejs API bazy danych WordPress nie będzie używany SQL_CALC_FOUND_ROWS
do implementacji paginacji, co zmniejszy obciążenie bazy danych w celu wykonania liczby znalezionych wierszy .
Jest to przydatne, gdy nie potrzebujesz stronicowania. Rozumiemy teraz, że możemy naśladować tę funkcję za pomocą tego zapytania:
$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );
Oto odpowiednie zapytanie 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
Porównaj to, co mamy teraz, z poprzednim żądaniem SQL, o ile SQL_CALC_FOUND_ROWS
istnieje.
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
Żądanie bez SQL_CALC_FOUND_ROWS
będzie szybsze.
Uwagi na temat query_posts
Wskazówka: na początku w 2004 roku było tylko global $wp_query
. Od wersji WordPress 2.1 $wp_the_query
przyszła. Wskazówka: $GLOBALS['wp_query']
i $GLOBALS['wp_the_query']
są osobnymi obiektami.
query_posts()
jest WP_Query
opakowaniem. Zwraca referencję do głównego WP_Query
obiektu i jednocześnie ustawi global $wp_query
.
File: /wp-includes/query.php
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
W PHP4 wszystko, łącznie z obiektami, przechodziło przez wartość. query_posts
było tak:
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);
}
Uwaga: w typowym scenariuszu z jednym zapytaniem podstawowym i jednym zapytaniem dodatkowym mamy trzy zmienne:
$GLOBALS['wp_the_query']
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary
Powiedzmy, że każda z tych trzech zajmuje 1M pamięci. Łącznie byłoby 3 mln pamięci. Jeśli użyjemy query_posts
, $GLOBALS['wp_query']
zostanie rozbrojony i ponownie utworzony.
PHP5 + powinno być inteligentnie opróżniające $GLOBALS['wp_query']
obiekt, tak jak w PHP4 zrobiliśmy to zunset($GLOBALS['wp_query']);
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
W rezultacie query_posts
zużywa ogółem 2 mln pamięci, a get_posts
zużywa 3 mln pamięci.
Uwaga: query_posts
nie zwracamy rzeczywistego obiektu, ale odniesienie do obiektu.
Od php.net : Odwołanie do PHP jest aliasem, który umożliwia zapisywanie dwóch różnych zmiennych do tej samej wartości. Od PHP 5 zmienna obiektowa nie zawiera już samego obiektu jako wartości. Zawiera tylko identyfikator obiektu, który umożliwia akcesoriom obiektowym znalezienie rzeczywistego obiektu. Gdy obiekt jest wysyłany przez argument, zwracany lub przypisywany do innej zmiennej, różne zmienne nie są aliasami: przechowują kopię identyfikatora, która wskazuje na ten sam obiekt.
Również w PHP5 + operator przypisania (=) jest inteligentny. Używa płytkiej kopii, a nie twardej kopii obiektu. Kiedy piszemy w ten sposób, $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
tylko dane zostaną skopiowane, a nie cały obiekt, ponieważ mają one ten sam typ obiektu.
Oto jeden przykład
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'] ) ) );
Skutkuje:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
d6db1c6bfddac328442e91b6059210b5
Spróbuj zresetować zapytanie:
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'] ) ) );
Skutkuje:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
Możesz tworzyć problemy, nawet jeśli używasz 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'] ) ) );
Oczywiście rozwiązaniem byłoby wp_reset_query
ponowne użycie funkcji.
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'] ) ) );
Dlatego myślę, że query_posts
może być lepiej z punktu widzenia pamięci. Ale zawsze powinieneś robić wp_reset_query
sztuczki.