Questão essencial
Vamos cavar o trio: ::query_posts
, ::get_posts
e class WP_Query
para entender ::query_posts
melhor.
A pedra angular para obter os dados no WordPress é a WP_Query
classe. Ambos os métodos ::query_posts
e ::get_posts
usam essa classe.
Observe que a classe WP_Query
também contém os métodos com o mesmo nome: WP_Query::query_posts
e WP_Query::get_posts
, mas na verdade consideramos apenas os métodos globais, portanto, não fique confuso.
Compreendendo o WP_Query
A classe chamada WP_Query
foi introduzida em 2004. Todos os campos com a marca umbrella (guarda-chuva) estavam presentes em 2004. Os campos adicionais foram adicionados posteriormente.
Aqui está a WP_Query
estrutura:
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
é o canivete suíço.
Algumas coisas sobre WP_Query
:
- é algo que você pode controlar através de argumentos que você passa
- é ganancioso por padrão
- contém a substância para loop
- ele é salvo no espaço global x2
- Pode ser primário ou secundário
- usa classes auxiliares
- tem um
pre_get_posts
gancho à mão
- ele ainda tem suporte para loops aninhados
- ele contém a string de consulta SQL
- mantém o número dos resultados
- mantém os resultados
- mantém a lista de todos os argumentos de consulta possíveis
- mantém as bandeiras do modelo
- ...
Não sei explicar tudo isso, mas alguns são complicados, então vamos fornecer dicas curtas.
WP_Query
é algo que você pode controlar através de argumentos que você passa
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
Esta lista do WordPress versão 4.7 certamente mudará no futuro.
Este seria o exemplo mínimo da criação do WP_Query
objeto a partir dos argumentos:
// 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
é ganancioso
Criado com a idéia, os get all you can
desenvolvedores do WordPress decidiram obter todos os dados possíveis o quanto antes, pois isso é bom para o desempenho . É por isso que, por padrão, quando a consulta recebe 10 postagens do banco de dados, ela também obtém os termos e os metadados para essas postagens por meio de consultas separadas. Os termos e metadados serão armazenados em cache (pré-buscados).
Observe que o armazenamento em cache é apenas para a vida útil da solicitação única.
Você pode desativar o cache de se definir update_post_meta_cache
e update_post_term_cache
para false
ao definir aWP_Query
argumentos. Quando o armazenamento em cache está desativado, os dados serão solicitados no banco de dados somente sob demanda.
Para a maioria dos blogs do WordPress, o cache funciona bem, mas há algumas ocasiões em que você pode desativar o cache.
WP_Query
usa classes auxiliares
Se você verificou os WP_Query
campos, você tem estes três:
public $tax_query;
public $meta_query;
public $date_query;
Você pode imaginar adicionando novas no futuro.
WP_Query
contém a substância para loop
Neste código:
$query = new WP_Query( $args )
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
você pode notar que WP_Query
possui a substância que pode iterar. Os métodos auxiliares também estão lá. Você acabou de definir o while
loop.
Nota. for
e while
loops são semanticamente equivalentes.
WP_Query
primário e secundário
No WordPress, você tem uma consulta primária e zero ou mais consultas secundárias .
É possível não ter a consulta principal, mas isso está além do escopo deste artigo.
Consulta primária conhecida como consulta principal ou consulta regular . Consulta secundária também chamada de consulta personalizada .
O WordPress usa a WP_Rewrite
classe mais cedo para criar os argumentos de consulta com base na URL. Com base nesses argumentos, ele armazena os dois objetos idênticos no espaço global. Ambos conterão a consulta principal.
global $wp_query @since WordPress 1.5
global $wp_the_query @since WordPress 2.1
Quando dizemos a consulta principal , pensamos nessas variáveis. Outras consultas podem ser chamadas de secundárias ou personalizadas.
É totalmente legal usar um global $wp_query
ou outro $GLOBALS['wp_query']
, mas o uso da segunda notação é muito mais notável e economiza a digitação de uma linha extra dentro do escopo das funções.
$GLOBALS['wp_query']
e $GLOBALS['wp_the_query']
são objetos separados. $GLOBALS['wp_the_query']
deve permanecer congelado.
WP_Query
tem a mão pre_get_posts
gancho .
Este é o gancho de ação. Será aplicado a qualquer WP_Query
instância. Você chama assim:
add_action( 'pre_get_posts', function($query){
if ( is_category() && $query->is_main_query() ) {
// set your improved arguments
$query->set( ... );
...
}
return $query;
});
Esse gancho é ótimo e pode alterar qualquer argumento de consulta.
Aqui está o que você pode ler :
Dispara após a criação do objeto variável de consulta, mas antes da execução da consulta real.
Portanto, este gancho é gerenciador de argumentos, mas não pode criar novos WP_Query
objetos. Se você teve uma consulta primária e uma secundária, pre_get_posts
não pode criar a terceira. Ou, se você tivesse apenas um primário, ele não poderá criar o secundário.
Observe que, caso você precise alterar a consulta principal, você também pode usar o request
gancho.
WP_Query
suporta loops aninhados
Esse cenário pode ocorrer se você usar plug-ins e chamar funções de plug-in do modelo.
Aqui está o exemplo de exemplo do WordPress com funções auxiliares, mesmo para os loops aninhados:
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;
A saída será assim desde que instalei os dados do teste da unidade temática :
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!
Mesmo que eu tenha solicitado 5 postagens na consulta $ personalizada, ele retornará seis, porque a postagem adesiva continuará. Se não houver wp_reset_postdata
no exemplo anterior, a saída será assim, porque o valor $GLOBALS['post']
será inválido.
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
tem wp_reset_query
função
É como um botão de reset. $GLOBALS['wp_the_query']
deve ser congelado o tempo todo, e plugins ou temas nunca devem alterá-lo.
Aqui está o que wp_reset_query
fazer:
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
Observações sobre get_posts
get_posts
parece
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);
Os números das linhas podem mudar no futuro.
É apenas um invólucro em torno de WP_Query
que os retornos das mensagens objeto de consulta.
A ignore_sticky_posts
configuração como true significa que as postagens adesivas podem aparecer apenas em uma posição natural. Não haverá postagens adesivas na frente. O outro no_found_rows
conjunto como true significa que a API do banco de dados WordPress não será usada SQL_CALC_FOUND_ROWS
para implementar a paginação, reduzindo a carga no banco de dados para executar linhas encontradas contagem de .
Isso é útil quando você não precisa de paginação. Entendemos agora que podemos imitar esta função com esta consulta:
$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );
Aqui está a solicitação SQL correspondente:
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
Compare o que temos agora com a solicitação SQL anterior, onde SQL_CALC_FOUND_ROWS
existe.
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
O pedido sem SQL_CALC_FOUND_ROWS
será mais rápida.
Observações sobre query_posts
Dica: No início de 2004, havia apenas global $wp_query
. A partir da versão 2.1 do WordPress $wp_the_query
chegou. Dica: $GLOBALS['wp_query']
e $GLOBALS['wp_the_query']
são objetos separados.
query_posts()
é WP_Query
invólucro. Retorna a referência ao WP_Query
objeto principal e, ao mesmo tempo, define o global $wp_query
.
File: /wp-includes/query.php
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
No PHP4, tudo, incluindo objetos, foi passado por valor. query_posts
foi assim:
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);
}
Observe no cenário típico com uma consulta primária e uma secundária que temos essas três variáveis:
$GLOBALS['wp_the_query']
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary
Digamos que cada um desses três consuma 1 milhão de memória. Total seria 3M de memória. Se usarmos query_posts
, $GLOBALS['wp_query']
será desativado e criado novamente.
O PHP5 + deve ser inteligente esvaziando o $GLOBALS['wp_query']
objeto, assim como no PHP4, fizemos com ounset($GLOBALS['wp_query']);
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
Como resultado, query_posts
consome 2M de memória no total, enquanto get_posts
consome 3M de memória.
Observe query_posts
que não estamos retornando o objeto real, mas uma referência ao objeto.
Do php.net : Uma referência PHP é um alias, que permite que duas variáveis diferentes gravem no mesmo valor. A partir do PHP 5, uma variável de objeto não contém mais o próprio objeto como valor. Ele contém apenas um identificador de objeto que permite que seus acessadores encontrem o objeto real. Quando um objeto é enviado por argumento, retornado ou atribuído a outra variável, as diferentes variáveis não são alias: elas mantêm uma cópia do identificador, que aponta para o mesmo objeto.
Também no PHP5 +, o operador assign (=) é inteligente. Ele usará cópia rasa e não cópia de objeto físico. Quando escrevermos assim, $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
apenas os dados serão copiados, e não o objeto inteiro, pois eles compartilham o mesmo tipo de objeto.
Aqui está um exemplo
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'] ) ) );
Resultará:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
d6db1c6bfddac328442e91b6059210b5
Tente redefinir a consulta:
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'] ) ) );
Resultará:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
Você pode criar problemas mesmo se usar 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'] ) ) );
Obviamente, a solução seria usar a wp_reset_query
função novamente.
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'] ) ) );
É por isso que acho que query_posts
pode ser melhor do ponto de vista da memória. Mas você deve sempre fazer wp_reset_query
truques.