¿Cuándo deberías usar WP_Query vs query_posts() vs get_posts()?

13 sept 2010, 15:58:39
Vistas: 197K
Votos: 465

Parece que la mitad de los tutoriales en el Codex y en la blogosfera usan query_posts() y la otra mitad usa WP_Query.

Todos hacen cosas similares, así que ¿cuándo debería usar uno en lugar de los otros?

1
Comentarios

Consulta también este análisis más detallado

prosti prosti
25 dic 2016 23:26:16
Todas las respuestas a la pregunta 7
22
748
  • query_posts() es excesivamente simplista y una forma problemática de modificar la consulta principal de una página al reemplazarla con una nueva instancia de la consulta. Es ineficiente (vuelve a ejecutar consultas SQL) y fallará por completo en algunas circunstancias (especialmente al tratar con la paginación de publicaciones). Cualquier código moderno de WP debe usar métodos más confiables, como hacer uso del hook pre_get_posts, para este propósito. En resumen: nunca uses query_posts().

  • get_posts() es muy similar en uso y acepta los mismos argumentos (con algunos matices, como valores predeterminados diferentes), pero devuelve un array de publicaciones, no modifica variables globales y es seguro de usar en cualquier lugar.

  • WP_Query es la clase que impulsa ambos detrás de escena, pero también puedes crear y trabajar con tu propia instancia de ella. Un poco más complejo, menos restricciones, también seguro de usar en cualquier lugar.

Diagrama comparativo: WP_Query vs query_posts vs get_posts Fuente de la imagen: https://www.rarst.net/images/query_functions.png

13 sept 2010 16:10:20
Comentarios

(1) "y es seguro de usar en cualquier lugar" --> pero no lo uses para el bucle PRINCIPAL. (2) recuerda usar global $query_string; antes de la línea que tiene query_posts();

edelwater edelwater
19 feb 2011 10:05:19

@scribu aunque de nuevo 'get_posts' funcionará aunque no se recomienda: http://core.trac.wordpress.org/ticket/16545

edelwater edelwater
19 feb 2011 10:27:18

Creo que query_posts también es menos eficiente ya que ejecutará consultas adicionales, mientras que si usas solo WP_Query para tu bucle principal, solo ejecutará la consulta que elijas en WP_Query.

jjeaton jjeaton
8 ago 2011 14:15:09

@jjeaton query_posts() es una pequeña función envoltorio para WP_Query, lo único adicional que hace (según el diagrama de flujo) es sobrescribir la variable global $wp_query

Rarst Rarst
8 ago 2011 15:39:23

@Rarst Me refería a esta sección en el Codex para query_posts sin embargo, puede que me equivoque respecto al efecto en el rendimiento. A menos que usar WP_Query en tu archivo de plantilla tenga el mismo resultado (es decir, descartar tu consulta y volver a ejecutarla)

jjeaton jjeaton
8 ago 2011 16:33:13

@jjeaton Reemplazar query_posts() con WP_Query no hará diferencia en el rendimiento, la consulta original de la página seguirá ejecutándose porque es parte de la carga del núcleo. Esas consultas se ejecutarán incluso si tu archivo de plantilla no tiene ningún bucle.

Rarst Rarst
8 ago 2011 17:15:17

No puedo quitarme la sensación de que este es el post más genial y votado en WPSE. Debería estar en el Codex también.

kaiser kaiser
16 sept 2011 00:03:07

Ok, después de mirarlo durante bastante tiempo, creo que a query_posts() le falta una variable estática que se establece en verdadero después del primer uso y - si se usa dos veces - debería activar _doing_it_wrong();. Supongo que voy a molestar a los chicos de wp-hacker o trac con esto.

kaiser kaiser
16 sept 2011 00:06:12

@kaiser bueno... usar query_posts() dos veces es casi tan malo como una, no importa mucho en mi opinión. :) por cierto Andrew Nacin va a hacer una presentación sobre consultas y dijo que podría proponer algunas mejoras al diagrama de flujo, así que la versión dos podría llegar en algún momento en el futuro.

Rarst Rarst
16 sept 2011 09:41:04

Voy a añadir mi descripción más clara del "problema de rendimiento de query_posts()": Usar query_posts() o WP_Query dentro de un archivo de plantilla tendrá el mismo costo de rendimiento: la consulta que acabas de realizar. El problema discutido en el artículo del codex es que si realmente quieres reemplazar la consulta, deberías hacerlo filtrando la query_posts() original con el filtro 'parse_query'. De esa manera solo tendrás la consulta original deseable, en lugar de hacer una segunda consulta para reemplazarla torpemente. ¡¡query_posts() NUNCA ES LA SOLUCIÓN!! ¡¡NUNCA!!

jerclarke jerclarke
19 abr 2012 22:24:25

Esto no menciona el filtro 'request', que es una excelente manera de modificar la consulta principal. La ventaja sobre query_posts es que esa función elimina la consulta original y genera una nueva, igual que si usaras WP_Query. Al usar el filtro request, estás modificando la consulta original antes de que se envíe. Creo que a eso se refiere @JeremyClarke arriba.

eddiemoya eddiemoya
2 may 2012 19:32:59

Hay una explicación increíblemente buena sobre query_posts escrita por John James Jacoby en el blog de developer.wordpress.com que supera todas estas respuestas. El punto principal: query_posts no modifica el bucle principal en absoluto, lo reemplaza después de que ya se ha ejecutado. La mejor manera de modificar el bucle principal es a través de un filtro pre_get_posts.

http://developer.wordpress.com/2012/05/14/querying-posts-without-query_posts/

Dan Gayle Dan Gayle
9 jun 2012 23:10:48

@Dan estás confundiendo la implementación técnica y el propósito. query_posts() sí reemplaza el objeto del loop principal, pero su propósito es modificar el loop principal. Además, aprecio mucho los filtros de loop, pero eso no era lo que preguntaba la pregunta. Hay una pregunta de seguimiento de otra persona sobre ese tema.

Rarst Rarst
10 jun 2012 10:44:50

La pregunta era "Cuándo deberías usar... query_posts()" y según la lógica presentada por esa entrada de blog y los comentarios anteriores, la respuesta es probablemente nunca.

Dan Gayle Dan Gayle
11 jun 2012 20:04:17

entonces, si es tan malo, ¿por qué existe query_posts?

Manny Fleurmond Manny Fleurmond
10 sept 2012 17:33:49

@Manny Fleurmond conceptualmente query_posts() es un intento de simplificar los conceptos del bucle principal al nivel de una etiqueta de plantilla (facilidad que es uno de los puntos fuertes de la popularidad de WP). La tarea simplemente resultó ser demasiado para que una etiqueta de plantilla pudiera lograrlo. Los desarrolladores principales mencionaron la posibilidad de que se deprecie, pero no creo que haya habido una decisión al respecto todavía.

Rarst Rarst
10 sept 2012 18:04:30

En realidad no puedes "usar en cualquier lugar" WP_Query(), acabo de intentarlo y todavía falla en $thequery->have_posts(), recursión infinita, ver http://wordpress.stackexchange.com/questions/34270

NoBugs NoBugs
21 oct 2014 07:16:37

@NoBugs el bucle en esa pregunta está mal y hay una respuesta que explica por qué.

Rarst Rarst
21 oct 2014 07:54:12

Agghh gracias por esto. Finalmente, algo tiene sentido. En serio, WordPress y su pésima documentación. No sé cómo un software tan enredado y con malos estándares de codificación se volvió tan popular.

racl101 racl101
16 abr 2015 23:32:31

Encontré esta prueba de velocidad entre wp_query y get_posts http://www.wpclocked.com/

Anagio Anagio
18 jul 2015 20:36:53

Confiaría en tal prueba... exactamente nada. :) La función es un envoltorio muy delgado, cualquier diferencia vendrá de ligeras variaciones en los argumentos y/o hooks.

Rarst Rarst
19 jul 2015 16:50:45

No hay necesidad de emociones, query_posts() es una función con efectos secundarios: establece una variable global. WordPress está plagado de funciones con efectos secundarios. Esto no es un problema de rendimiento sino un problema de calidad de código. Mira https://developer.wordpress.org/reference/functions/query_posts/ y observa lo que hace query_posts. Usa WP_Query a menos que quieras alterar variables globales.

th00ht th00ht
14 mar 2020 17:22:07
Mostrar los 17 comentarios restantes
3
96

query_posts - Nunca deberías usar query_posts. Además de lo que @Rarst ha mencionado, el gran problema con query_posts es que rompe el objeto de consulta principal (almacenado en $wp_query). Muchos plugins y código personalizado dependen del objeto de consulta principal, por lo que romperlo significa que estás afectando la funcionalidad de plugins y código personalizado. Una de estas funciones es la importante función de paginación, así que si rompes la consulta principal, rompes la paginación.

Para demostrar lo malo que es query_posts, en cualquier plantilla, haz lo siguiente y compara los resultados:

var_dump( $wp_query );
query_posts( '&posts_per_page=-1' );
var_dump( $wp_query );

get_posts y WP_Query son la forma correcta de construir consultas secundarias (como publicaciones relacionadas, sliders, contenido destacado y contenido en páginas de inicio estáticas). Cabe destacar que no deberías usar ninguno de los dos en lugar de la consulta principal en la página de inicio, página individual o cualquier tipo de página de archivo, ya que romperá la funcionalidad de la página. Si necesitas modificar la consulta principal, usa pre_get_posts para hacerlo, no una consulta personalizada. (ACTUALIZACIÓN: Para páginas de inicio estáticas y páginas verdaderas, consulta Usando pre_get_posts en páginas verdaderas y páginas de inicio estáticas*)

En esencia, WP_Query es utilizado por la consulta principal y también por get_posts, pero aunque get_posts() usa WP_Query, hay algunas diferencias:

  • get_posts es más rápido que WP_Query. El margen depende de la cantidad total de publicaciones del sitio. La razón es que get_posts pasa 'no_found_rows' => true por defecto a WP_Query, lo que omite/legalmente rompe la paginación. Con 'no_found_rows' => true, WP_Query obtiene la cantidad de publicaciones consultadas y luego se detiene, mientras que, por defecto, sigue buscando todas las publicaciones que coincidan con la consulta para calcular la paginación.

    Por esta razón, get_posts() debería usarse solo para consultas no paginadas. Paginar get_posts es realmente un gran desastre. WP_Query debería usarse para todas las consultas paginadas.

  • get_posts() no se ve influenciado por los filtros posts_*, mientras que WP_Query sí. La razón es que get_posts, por defecto, pasa 'suppress_filters' => true a WP_Query.

  • get_posts tiene algunos parámetros adicionales como include, exclude, numberposts y category. Estos parámetros se convierten en parámetros válidos para WP_Query antes de ser pasados. include se convierte en post__in, exclude en post__not_in, category en cat y numberposts en posts_per_page. Solo una nota, todos los parámetros que se pueden pasar a WP_Query funcionan con get_posts, puedes ignorar y no usar los parámetros predeterminados de get_posts.

  • get_posts devuelve solo la propiedad $posts de WP_Query, mientras que WP_Query devuelve el objeto completo. Este objeto es bastante útil cuando se trata de condicionales, paginación y otra información útil que se puede usar dentro del bucle.

  • get_posts no usa el bucle, sino un bucle foreach para mostrar las publicaciones. Además, no hay etiquetas de plantilla disponibles por defecto. Se debe usar setup_postdata( $post ) para que las etiquetas de plantilla estén disponibles. WP_Query usa el bucle y las etiquetas de plantilla están disponibles por defecto.

  • get_posts pasa 'ignore_sticky_posts' => 1 a WP_Query, por lo que get_posts ignora las publicaciones fijas por defecto.

En base a lo anterior, decidir si usar get_posts o WP_Query depende de ti y de lo que realmente necesites de la consulta. Lo anterior debería guiarte en tu elección.

18 jun 2015 17:46:01
Comentarios

Ojalá pudiera marcar respuestas como favoritas. Esto explica mucho.

InanisAtheos InanisAtheos
12 jun 2017 07:17:52

¡Excelente explicación!

"get_posts() solo debería usarse para consultas no paginadas. Paginar get_posts es realmente un gran desorden. WP_Query debería usarse para todas las consultas paginadas" es básicamente todo lo que alguien necesita saber en mi opinión.

Bullyen Bullyen
19 abr 2018 19:27:06

@pieter-goosen, ¿sabes si lo mismo aplica para WP User Query versus get_users? Me refiero a la parte de rendimiento.

User User
5 ago 2021 06:34:29
0
35

La diferencia básica es que query_posts() realmente solo sirve para modificar el Loop actual. Una vez que hayas terminado, es necesario restablecer el loop y dejarlo seguir su curso. Este método también es un poco más fácil de entender, simplemente porque tu "consulta" es básicamente una cadena de URL que pasas a la función, así:

query_posts('meta_key=color&meta_value=blue'); 

Por otro lado, WP_Query es más una herramienta de propósito general, y se parece más a escribir consultas MySQL directamente que query_posts(). También puedes usarlo en cualquier lugar (no solo en el Loop) y no interfiere con ninguna consulta de publicaciones que se esté ejecutando actualmente.

Por lo general, tiendo a usar WP_Query con más frecuencia. En realidad, todo dependerá de tu caso específico.

13 sept 2010 16:09:13
0
17

Simplemente no hay necesidad de usar query_posts(). Todo lo que hace es instanciar un nuevo objeto WP_Query y reasignar ese nuevo objeto a global wp_query.

Como referencia, lo siguiente es la función real query_posts().

function query_posts($query) {
        $GLOBALS['wp_query'] = new WP_Query();
        return $GLOBALS['wp_query']->query($query);
    }

Instancia tu propio objeto WP_Query si deseas crear un script de consulta personalizado en profundidad. O usa get_posts() si solo necesitas hacer algunas manipulaciones menores aquí y allá.

En cualquier caso, recomiendo encarecidamente que te hagas un favor y vayas a wp_includes/query.php y examines la clase WP_Query.

13 jul 2013 16:38:02
0
16

Asegúrate de usar wp_reset_query() después de usar query_posts() porque afectará también otros resultados de consulta.

8 jul 2013 04:50:45
0
12

Si recuerdo bien lo que leí, básicamente "el loop" está haciendo WP_Query en los archivos principales, pero de una manera más fácil de entender.

23 sept 2010 20:21:34
0
  • query_posts(): podría usarse en un único caso si necesitas modificar la consulta principal. Establece muchas variables globales;
  • get_posts(): es muy similar en mecánica y acepta los mismos argumentos, pero devuelve un array de posts
  • WP_Query: puedes crear y trabajar con tu propio objeto de esta clase. Un poco más complejo, con menos restricciones, es seguro usarlo en cualquier lugar.
19 jul 2017 14:28:38