Cuándo usar WP_query (), query_posts () y pre_get_posts

Leí @nacin «s No conoces a Query ayer y te enviaron un poco por un agujero de conejo. Antes de ayer, estaba (incorrectamente) usando query_posts() para todas mis necesidades de consulta. Ahora soy un poco más inteligente acerca del uso de WP_Query() , pero todavía tengo algunas áreas grises.

Lo que creo que sé con certeza:

Si estoy ganando más se repite en cualquier lugar de una página (en la barra lateral, en un pie de página, cualquier tipo de «publicaciones relacionadas», etc.) Quiero usar WP_Query() . Puedo usar eso repetidamente en una sola página sin ningún daño. (¿derecho?).

Lo que no sé con certeza

  1. Cuándo ¿uso @nacin «s pre_get_posts a? > frente a WP_Query() ? ¿Debería usar pre_get_posts para todo ahora?
  2. Cuando quiero modificar el bucle en una página de plantilla, digamos que quiero modificar una página de archivo de taxonomía, ¿elimino la parte if have_posts : while have_posts : the_post y escribo mi propio WP_Query() ? ¿O modifico la salida usando pre_get_posts en mi archivo functions.php?

tl; dr

Las reglas tl; dr Me gustaría sacar de esto:

  1. Nunca use query_posts
  2. Cuando ejecute varias consultas en una sola página, use WP_Query()
  3. Cuando modifique un ciclo, haga esto __________________.

Gracias por su sabiduría

Terry

pd: He visto y leído: ¿Cuándo debería usar WP_Query vs query_posts () vs get_posts ()? Lo que agrega otra dimensión – get_posts . Pero no trata con pre_get_posts en absoluto .

Comentarios

Responder

Tiene razón al decir:

Nunca más use query_posts

pre_get_posts

pre_get_posts es un filtro, para alterar cualquier consulta. Se utiliza con mayor frecuencia para modificar solo la «consulta principal»:

add_action("pre_get_posts","wpse50761_alter_query"); function wpse50761_alter_query($query){ if( $query->is_main_query() ){ //Do something to main query } } 

(También comprobaría que is_admin() devuelve falso , aunque esto puede ser redundante). La consulta principal aparece en sus plantillas como:

if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

Si alguna vez siente la necesidad de editar este bucle, use pre_get_posts. es decir, si tiene la tentación de utilizar query_posts(), utilice pre_get_posts en su lugar.

WP_Query

La consulta principal es una instancia importante de WP_Query object . WordPress lo usa para decidir qué plantilla usar, por ejemplo, y todos los argumentos que se pasan a la URL (por ejemplo, la paginación) se canalizan en esa instancia del objeto WP_Query.

Para bucles secundarios (por ejemplo, en barras laterales o listas de «publicaciones relacionadas»), «querrá crear su propia instancia separada del objeto WP_Query. Por ejemplo,

$my_secondary_loop = new WP_Query(...); if( $my_secondary_loop->have_posts() ): while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post(); //The secondary loop endwhile; endif; wp_reset_postdata(); 

Aviso wp_reset_postdata();: esto se debe a que el ciclo secundario anulará el $post variable que identifica la «publicación actual». Esto esencialmente lo restablece a la $post en la que estamos.

get_posts ()

Esto es esencialmente un contenedor para una instancia separada de un objeto WP_Query. Esto devuelve una matriz de objetos de publicación. Los métodos usados en el ciclo anterior ya no están disponibles para usted. Esto no es » ta «Loop», simplemente una matriz de objeto de publicación.

<ul> <?php global $post; $args = array( "numberposts" => 5, "offset"=> 1, "category" => 1 ); $myposts = get_posts( $args ); foreach( $myposts as $post ) : setup_postdata($post); ?> <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li> <?php endforeach; wp_reset_postdata(); ?> </ul> 

En respuesta a sus preguntas

  1. Utilice pre_get_posts para modificar su consulta principal. Use un objeto WP_Query separado (método 2) para los bucles secundarios en las páginas de la plantilla.
  2. Si desea modificar la consulta del bucle principal, use pre_get_posts.

Comentarios

  • Entonces, ¿hay algún escenario en el que uno vaya directamente a get_posts () en lugar de WP_Query?
  • @drtanz – sí. Digamos, por ejemplo, que no ‘ no necesita paginación o publicaciones fijas en la parte superior; en estos casos, get_posts() es más eficiente.
  • ¿Pero no ‘ t eso agregaría una consulta adicional donde podríamos modificar pre_get_posts para modificar la consulta principal?
  • @drtanz – usted no ‘ No use get_posts() para la consulta principal; es para consultas secundarias.
  • @StephenHarris Right =) Si usa next_post () en el objeto en lugar de usar the_post, no ‘ t pisar la consulta global y no ‘ no es necesario recordar use wp_reset_postdata después.

Respuesta

Hay dos contextos diferentes para los bucles:

  • main bucle que ocurre según la solicitud de URL y se procesa antes de que se carguen las plantillas
  • secundario

bucles que suceden de cualquier otra forma, llamados desde archivos de plantilla o de otro modo

Problema con query_posts() es que es un bucle secundario que intenta ser el principal y falla estrepitosamente. Por lo tanto, olvídese de que existe.

Para modificar el bucle principal

  • no use query_posts()
  • use pre_get_posts filtro con $query->is_main_query() marca
  • use alternativamente request filtro ( un poco demasiado tosco, así que arriba es mejor)

Para ejecutar el ciclo secundario

Use new WP_Query o get_posts() que son prácticamente intercambiables (la última es una envoltura delgada para la primera).

Para limpiar

Use wp_reset_query() si usó query_posts() o se metió con $wp_query global directamente, por lo que casi nunca lo necesitará.

Use wp_reset_postdata() si usaste the_post() o setup_postdata() o si usaste $post y es necesario restaurar el estado inicial de las cosas relacionadas con la publicación.

Comentarios

  • Rarst significaba wp_reset_postdata()

Answe r

Existen escenarios legítimos para usar query_posts($query), por ejemplo:

  1. Quieres mostrar una lista de publicaciones o publicaciones de tipo de publicación personalizada en una página (usando una plantilla de página)

  2. Quieres hacer que la paginación de esas publicaciones funcione

Ahora, ¿por qué querría mostrarlo en una página en lugar de usar una plantilla de archivo?

  1. Es más intuitivo para un administrador (¿su cliente?): pueden ver la página en las «Páginas»

  2. Es mejor agregarla a los menús (sin la página, tendrían para agregar la URL directamente)

  3. Si desea mostrar contenido adicional (texto, miniatura de publicación o cualquier metacontenido personalizado) en la plantilla, puede obtenerlo fácilmente de la página (y también tiene más sentido para el cliente). Vea si usó una plantilla de archivo, necesitaría codificar el contenido adicional o usar, por ejemplo, opciones de tema / complemento (lo que lo hace menos intuitivo para el cliente)

Aquí «un código de ejemplo simplificado (que estaría en la plantilla de su página, por ejemplo, page-page-of-posts.php):

 /** * Template Name: Page of Posts */ while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... } // now we display list of our custom-post-type posts // first obtain pagination parametres $paged = 1; if(get_query_var("paged")) { $paged = get_query_var("paged"); } elseif(get_query_var("page")) { $paged = get_query_var("page"); } // query posts and replace the main query (page) with this one (so the pagination works) query_posts(array("post_type" => "my_post_type", "post_status" => "publish", "paged" => $paged)); // pagination next_posts_link(); previous_posts_link(); // loop while(have_posts()) { the_post(); the_title(); // your custom-post-type post"s title the_content(); // // your custom-post-type post"s content } wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data // So, now we can display the page-related content again (if we wish so) while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... }  

Ahora, para ser perfectamente claros, podríamos evitar usar query_posts() aquí también y usar WP_Query en su lugar – así:

// ... global $wp_query; $wp_query = new WP_Query(array("your query vars here")); // sets the new custom query as a main query // your custom-post-type loop here wp_reset_query(); // ... 

Pero, ¿por qué haríamos eso cuando tenemos una pequeña función tan agradable disponible para ella?

Comentarios

  • Brian, gracias por eso. ‘ he estado luchando para que pre_get_posts funcione en una página EXACTAMENTE el escenario que usted describe: el cliente necesita agregar campos / contenido personalizados a lo que de otra manera sería una página de archivo, » la página » debe crearse; el cliente necesita ver algo para agregar al menú de navegación, ya que agregar un enlace personalizado los escapa; etc. ¡+1 de mí!
  • Eso también se puede hacer usando » pre_get_posts «. Hice eso para tener una » página frontal estática » que enumera mis tipos de publicaciones personalizadas en un orden personalizado y con un filtro personalizado. Esta página también está paginada. Consulte esta pregunta para ver cómo funciona: wordpress.stackexchange.com / questions / 30851 / … Entonces, en resumen, todavía no hay un escenario más legítimo para usar query_posts;)
  • Porque » Cabe señalar que usar esto para reemplazar la consulta principal en una página puede aumentar los tiempos de carga de la página, en el peor de los casos duplicando la cantidad de trabajo necesario o más. Si bien es fácil de usar, la función también es propensa a confusión y problemas más adelante. » Fuente codex.wordpress.org/Function_Reference/ query_posts
  • Esta respuesta es incorrecta. Puede crear una » Página » en WP con la misma URL que el tipo de publicación personalizada. Por ejemplo, si su CPT es Bananas, puede obtener una página llamada Bananas con la misma URL. Entonces, ‘ d terminarás con siteurl.com/bananas. Siempre que tenga archive-bananas.php en su carpeta de temas, usará la plantilla y » anulará » esa página en su lugar . Como se indica en uno de los otros comentarios, el uso de este » método » crea el doble de carga de trabajo para WP, por lo que NO debe usarse nunca.

Responder

Modifico la consulta de WordPress desde functions.php:

//unfortunately, "IS_PAGE" condition doesn"t work in pre_get_posts (it"s WORDPRESS behaviour) //so you can use `add_filter("posts_where", ....);` OR modify "PAGE" query directly into template file add_action( "pre_get_posts", "myFunction" ); function myFunction($query) { if ( ! is_admin() && $query->is_main_query() ) { if ( $query->is_category ) { $query->set( "post_type", array( "post", "page", "my_postType" ) ); add_filter( "posts_where" , "MyFilterFunction_1" ) && $GLOBALS["call_ok"]=1; } } } function MyFilterFunction_1($where) { return (empty($GLOBALS["call_ok"]) || !($GLOBALS["call_ok"]=false) ? $where : $where . " AND ({$GLOBALS["wpdb"]->posts}.post_name NOT LIKE "Journal%")"; } 

Comentarios

  • estaría interesado en ver este ejemplo pero donde la cláusula está en meta personalizada.

Respuesta

Solo para describir algunas mejoras a la respuesta aceptada ya que WordPress evolucionó con el tiempo y algunas cosas son diferentes ahora (cinco años después) :

pre_get_posts es un filtro para modificar cualquier consulta. Se usa con mayor frecuencia para modificar solo la «consulta principal»:

En realidad, es un gancho de acción. No es un filtro y afectará a cualquier consulta.

La consulta principal aparece en sus plantillas como:

if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

En realidad, esto tampoco es cierto. La función have_posts itera el global $wp_query objeto que no está relacionado solo con la consulta principal. global $wp_query; también puede modificarse con las consultas secundarias.

function have_posts() { global $wp_query; return $wp_query->have_posts(); } 

get_posts ()

Esto es esencialmente un contenedor para una instancia separada de un objeto WP_Query.

En realidad, hoy en día WP_Query es una clase, así que tenemos una instancia de una clase.


Para concluir: En el momento en que @StephenHarris escribió, probablemente todo esto era cierto, pero con el tiempo las cosas en WordPress han cambiado.

Comentarios

  • Técnicamente, ‘ s Todos los filtros bajo el capó, las acciones son solo un filtro simple. Pero tiene razón aquí, es ‘ una acción que pasa un argumento por referencia, que es en lo que se diferencia de las acciones más simples.
  • get_posts devuelve una matriz de objetos de publicación, no un objeto WP_Query, por lo que todavía es correcto. y WP_Query siempre ha sido una clase, instancia de un objeto class =.
  • Gracias, @Milo, correcto por alguna razón, tenía un modelo demasiado simplificado en mi cabeza.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *