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
- Cuándo ¿uso @nacin «s
pre_get_posts
a? > frente aWP_Query()
? ¿Debería usarpre_get_posts
para todo ahora? - 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 propioWP_Query()
? ¿O modifico la salida usandopre_get_posts
en mi archivo functions.php?
tl; dr
Las reglas tl; dr Me gustaría sacar de esto:
- Nunca use
query_posts
- Cuando ejecute varias consultas en una sola página, use
WP_Query()
- 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
- Posible duplicado de ¿Cuándo debería usar WP_Query vs query_posts () vs get_posts ( )?
- @saltcod, ahora es diferente, WordPress evolucionó, agregué algunos comentarios en comparación con la respuesta aceptada aquí .
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
- Utilice
pre_get_posts
para modificar su consulta principal. Use un objetoWP_Query
separado (método 2) para los bucles secundarios en las páginas de la plantilla. - 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:
-
Quieres mostrar una lista de publicaciones o publicaciones de tipo de publicación personalizada en una página (usando una plantilla de página)
-
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?
-
Es más intuitivo para un administrador (¿su cliente?): pueden ver la página en las «Páginas»
-
Es mejor agregarla a los menús (sin la página, tendrían para agregar la URL directamente)
-
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 objetoWP_Query
, por lo que todavía es correcto. yWP_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.