Pregunta esencial
Excavación Vamos en el trío: ::query_posts
, ::get_posts
y class WP_Query
para comprender ::query_posts
mejor.
La piedra angular para obtener los datos en WordPress es la WP_Query
clase. Ambos métodos ::query_posts
y ::get_posts
usan esa clase.
Tenga en cuenta que la clase WP_Query
también contiene los métodos con el mismo nombre: WP_Query::query_posts
y WP_Query::get_posts
, pero en realidad solo consideramos los métodos globales, así que no se confunda.
Entendiendo el WP_Query
La clase llamada WP_Query
se introdujo en 2004. Todos los campos que tienen la marca ☂ (paraguas) estaban presentes en 2004. Los campos adicionales se agregaron más tarde.
Aquí está la WP_Query
estructura:
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
Es la navaja suiza.
Algunas cosas sobre WP_Query
:
- es algo que puedes controlar a través de argumentos que pasas
- es codicioso por defecto
- contiene la sustancia para el bucle
- se guarda en el espacio global x2
- Puede ser primario o secundario
- utiliza clases auxiliares
- tiene un práctico
pre_get_posts
gancho
- incluso tiene soporte para bucles anidados
- contiene la cadena de consulta SQL
- contiene el número de resultados
- contiene los resultados
- contiene la lista de todos los argumentos de consulta posibles
- tiene las banderas de la plantilla
- ...
No puedo explicar todo esto, pero algunos de estos son complicados, así que proporcionemos consejos breves.
WP_Query
es algo que puedes controlar a través de argumentos que pasas
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 de WordPress versión 4.7 ciertamente cambiará en el futuro.
Este sería el ejemplo mínimo de creación del WP_Query
objeto a partir de los 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
es codicioso
Creado a partir de la idea, get all you can
los desarrolladores de WordPress decidieron obtener todos los datos posibles antes, ya que esto es bueno para el rendimiento . Esta es la razón por la cual, de manera predeterminada, cuando la consulta toma 10 publicaciones de la base de datos, también obtendrá los términos y los metadatos de estas publicaciones a través de consultas separadas. Los términos y metadatos se almacenarán en caché (se buscarán previamente).
Tenga en cuenta que el almacenamiento en caché es solo para toda la vida útil de la solicitud.
Puede desactivar el almacenamiento en caché si se establece update_post_meta_cache
y update_post_term_cache
al false
mismo tiempo establecer los WP_Query
argumentos. Cuando el almacenamiento en caché está desactivado, los datos se solicitarán a la base de datos solo bajo demanda.
Para la mayoría de los blogs de WordPress, el almacenamiento en caché funciona bien, pero hay algunas ocasiones en las que puede deshabilitar el almacenamiento en caché.
WP_Query
utiliza clases auxiliares
Si marcó los WP_Query
campos allí, tiene estos tres:
public $tax_query;
public $meta_query;
public $date_query;
Puedes imaginar agregar nuevos en el futuro.
WP_Query
contiene la sustancia para el bucle
En este código:
$query = new WP_Query( $args )
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
puede notar que WP_Query
tiene la sustancia que puede iterar. Los métodos de ayuda también están ahí. Acabas de configurar el while
bucle.
Nota. for
y los while
bucles son semánticamente equivalentes.
WP_Query
Primaria y secundaria
En WordPress tienes una consulta primaria y cero o más consultas secundarias .
Es posible no tener la consulta primaria, pero esto está más allá del alcance de este artículo.
Consulta primaria conocida como consulta principal o consulta regular . La consulta secundaria también se denomina consulta personalizada .
WordPress usa la WP_Rewrite
clase temprana para crear los argumentos de consulta basados en la URL. En base a estos argumentos, almacena los dos objetos idénticos en el espacio global. Ambos contendrán la consulta principal.
global $wp_query @since WordPress 1.5
global $wp_the_query @since WordPress 2.1
Cuando decimos consulta principal pensamos en estas variables. Otras consultas pueden llamarse secundarias o personalizadas.
Es completamente legal usar cualquiera global $wp_query
o $GLOBALS['wp_query']
, pero usar la segunda notación es mucho más notable y ahorra escribir una línea adicional dentro del alcance de las funciones.
$GLOBALS['wp_query']
y $GLOBALS['wp_the_query']
son objetos separados. $GLOBALS['wp_the_query']
debe permanecer congelado
WP_Query
Tiene el práctico pre_get_posts
gancho.
Este es el gancho de acción. Se aplicará a cualquier WP_Query
instancia. Lo llamas así:
add_action( 'pre_get_posts', function($query){
if ( is_category() && $query->is_main_query() ) {
// set your improved arguments
$query->set( ... );
...
}
return $query;
});
Este enlace es excelente y puede alterar cualquier argumento de consulta.
Esto es lo que puedes leer :
Se activa después de crear el objeto variable de consulta, pero antes de que se ejecute la consulta real.
Este gancho es un administrador de argumentos pero no puede crear nuevos WP_Query
objetos. Si tuvo una consulta primaria y una secundaria, pre_get_posts
no puede crear la tercera. O si acaba de tener una primaria, no puede crear la secundaria.
Tenga en cuenta que en caso de que necesite modificar la consulta principal, solo puede usar el request
enlace.
WP_Query
admite bucles anidados
Este escenario puede suceder si usa complementos y llama a funciones de complementos desde la plantilla.
Aquí está el ejemplo de muestra de WordPress tiene funciones de ayuda incluso para los bucles anidados:
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;
El resultado será así desde que instalé los datos de prueba de la unidad de tema :
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!
Aunque solicité 5 publicaciones en la consulta $ personalizada, me devolverá seis, porque la publicación adhesiva seguirá. Si no hay wp_reset_postdata
en el ejemplo anterior, la salida será así, ya $GLOBALS['post']
que no será válida.
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
tiene wp_reset_query
función
Esto es como un botón de reinicio. $GLOBALS['wp_the_query']
debe estar congelado todo el tiempo, y los complementos o temas nunca deben alterarlo.
Esto es lo wp_reset_query
que debes hacer:
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
Observaciones 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);
Los números de línea pueden cambiar en el futuro.
Es sólo una envoltura alrededor de WP_Query
que las declaraciones de los mensajes objeto de consulta.
El ignore_sticky_posts
conjunto en verdadero significa que las publicaciones adhesivas pueden aparecer solo en una posición natural. No habrá publicaciones adhesivas en el frente. El otro no_found_rows
conjunto en verdadero significa que la API de la base de datos de WordPress no se usará SQL_CALC_FOUND_ROWS
para implementar la paginación, lo que reduce la carga en la base de datos para ejecutar el recuento de filas encontradas .
Esto es útil cuando no necesita paginación. Entendemos que ahora podemos imitar esta función con esta consulta:
$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );
Aquí está la solicitud SQL correspondiente:
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 lo que tenemos ahora con la solicitud SQL anterior donde SQL_CALC_FOUND_ROWS
exista.
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
La solicitud sin SQL_CALC_FOUND_ROWS
será más rápida.
Observaciones sobre query_posts
Consejo: Al principio en 2004 solo había global $wp_query
. A partir de la versión 2.1 de WordPress $wp_the_query
vino. Consejo: $GLOBALS['wp_query']
y $GLOBALS['wp_the_query']
son objetos separados.
query_posts()
Es WP_Query
envoltorio. Devuelve la referencia al WP_Query
objeto principal y, al mismo tiempo, establecerá el global $wp_query
.
File: /wp-includes/query.php
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
En PHP4 todo, incluidos los objetos, se pasaba por valor. query_posts
fue así:
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);
}
Tenga en cuenta que en un escenario típico con una consulta primaria y una secundaria tenemos estas tres variables:
$GLOBALS['wp_the_query']
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary
Digamos que cada uno de estos tres toma 1M de memoria. El total sería 3M de memoria. Si lo usamos query_posts
, $GLOBALS['wp_query']
se desarmará y se volverá a crear.
PHP5 + debería ser inteligente vaciando el $GLOBALS['wp_query']
objeto, al igual que en PHP4 lo hicimos con elunset($GLOBALS['wp_query']);
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
Como resultado, query_posts
consume 2M de memoria en total, mientras que get_posts
consume 3M de memoria.
Tenga en cuenta query_posts
que no estamos devolviendo el objeto real, sino una referencia al objeto.
Desde php.net : Una referencia de PHP es un alias, que permite que dos variables diferentes escriban en el mismo valor. A partir de PHP 5, una variable de objeto ya no contiene el objeto como valor. Solo contiene un identificador de objeto que permite a los accesores de objetos encontrar el objeto real. Cuando un objeto se envía por argumento, se devuelve o se asigna a otra variable, las diferentes variables no son alias: contienen una copia del identificador, que apunta al mismo objeto.
También en PHP5 + el operador de asignación (=) es inteligente. Utilizará una copia superficial y no una copia de objetos impresos. Cuando escribimos así, $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
solo se copiarán los datos, no todo el objeto, ya que comparten el mismo tipo de objeto.
Aquí hay un ejemplo
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
Intenta restablecer la 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
Puede crear problemas incluso si usa 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'] ) ) );
Por supuesto, la solución sería usar la wp_reset_query
función nuevamente.
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'] ) ) );
Es por eso que creo que query_posts
puede ser mejor desde el punto de vista de la memoria. Pero siempre debes hacer wp_reset_query
trucos.