Quand utiliser WP_query (), query_posts () et pre_get_posts

Jai lu @nacin « s Vous ne connaissez pas la requête hier et vous avez été envoyé un peu dans un terrier de lapin. Avant hier, jutilisais (à tort) query_posts() pour tous mes besoins de requêtes. Maintenant, je « suis un peu plus sage sur lutilisation de WP_Query() , mais jai encore des zones grises.

Ce que je pense savoir avec certitude:

Si je « fais un complément boucle nimporte où sur une page – dans la barre latérale, dans un pied de page, tout type de « messages associés », etc. – Je souhaite utiliser WP_Query() . Je peux lutiliser à plusieurs reprises sur une seule page sans aucun dommage. (droit?).

Ce que je ne sais pas avec certitude

  1. Quand est-ce que jutilise @nacin « s pre_get_posts contre WP_Query() ? Dois-je utiliser pre_get_posts pour tout maintenant?
  2. Lorsque je veux modifier la boucle dans une page de modèle – disons que je veux modifier une page darchive de taxonomie – est-ce que je supprime la partie if have_posts : while have_posts : the_post et écris mon Posséder WP_Query() ? Ou est-ce que je modifie la sortie en utilisant pre_get_posts dans mon fichier functions.php?

tl; dr

Les règles tl; dr Je « voudrais tirer de ceci:

  1. Ne jamais utiliser query_posts plus
  2. Lorsque vous exécutez plusieurs requêtes sur une seule page, utilisez WP_Query()
  3. Lorsque vous modifiez une boucle, faites ceci __________________.

Merci pour votre sagesse

Terry

ps: Jai vu et lu: Quand devriez-vous utiliser WP_Query vs query_posts () vs get_posts ()? Ce qui ajoute une autre dimension – get_posts . Mais ne traite pas du tout de pre_get_posts .

Commentaires

Réponse

Vous avez raison de dire:

Nutilisez plus query_posts

pre_get_posts

pre_get_posts est un filtre permettant de modifier tout . Il est le plus souvent utilisé pour modifier uniquement la « requête principale »:

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

(je vérifierais également que is_admin() renvoie false – bien que cela puisse être redondant.). La requête principale apparaît dans vos modèles sous la forme:

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

Si vous ressentez le besoin de modifier cette boucle – utilisez pre_get_posts. cest-à-dire si vous êtes tenté dutiliser query_posts() – utilisez plutôt pre_get_posts.

WP_Query

La requête principale est une instance importante dun WP_Query object . WordPress lutilise pour décider quel modèle utiliser, par exemple, et tous les arguments passés dans lurl (par exemple la pagination) sont tous canalisés dans cette instance de lobjet WP_Query.

Pour les boucles secondaires (par exemple dans les barres latérales ou les listes de « publications associées »), vous « voudrez créer votre propre instance distincte de lobjet WP_Query. Par exemple

$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(); 

Remarque wp_reset_postdata(); – cest parce que la boucle secondaire remplacera le $post qui identifie le « message actuel ». Cela réinitialise essentiellement cela au $post sur lequel nous nous trouvons.

get_posts ()

Il sagit essentiellement dun wrapper pour une instance distincte dun objet WP_Query. Cela renvoie un tableau dobjets de publication. Les méthodes utilisées dans la boucle ci-dessus ne vous sont plus disponibles. Ce nest plus  » ta « Loop », simplement un tableau dobjet de publication.

<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 réponse à vos questions

  1. Utilisez pre_get_posts pour modifier votre requête principale. Utilisez un objet WP_Query séparé (méthode 2) pour les boucles secondaires dans les pages de modèle.
  2. Si vous souhaitez modifier la requête de la boucle principale, utilisez pre_get_posts.

Commentaires

  • Y a-t-il donc un scénario où lon irait directement à get_posts () plutôt quà WP_Query?
  • @drtanz – oui. Supposons, par exemple, que vous n’avez ‘ pas besoin de pagination, ou de messages collants en haut – dans ces cas, get_posts() est plus efficace.
  • Mais est-ce que ‘ t qui ajouterait une requête supplémentaire où nous pourrions simplement modifier pre_get_posts pour modifier la requête principale?
  • @drtanz – vous ne le feriez pas ‘ t utiliser get_posts() pour la requête principale – cest pour les requêtes secondaires.
  • @StephenHarris Right =) Si vous utilisez next_post () sur lobjet au lieu dutiliser the_post, vous navez ‘ pas sur la requête globale et ne ‘ pas besoin de vous rappeler de utilisez ensuite wp_reset_postdata.

Réponse

Il existe deux contextes différents pour les boucles:

    Boucle

  • principale qui se produit en fonction de la demande dURL et est traitée avant le chargement des modèles
  • secondaire

boucles qui se produisent dune autre manière, appelées à partir de fichiers modèles ou autrement

Problème avec query_posts() est que cest la boucle secondaire qui essaie dêtre principale et échoue lamentablement. Oubliez donc quil existe.

Pour modifier la boucle principale

  • nutilisez pas query_posts()
  • utilisez pre_get_posts filtre avec $query->is_main_query() check
  • utilisez alternativement le filtre request ( un peu trop grossier donc ci-dessus est mieux)

Pour exécuter une boucle secondaire

Utilisez new WP_Query ou get_posts() qui sont à peu près interchangeables (ce dernier est un wrapper fin pour le premier).

Pour nettoyer

Utilisez wp_reset_query() si vous avez utilisé query_posts() ou joué avec $wp_query global directement – vous naurez donc presque jamais besoin de le faire.

Utilisez wp_reset_postdata() si vous avez utilisé the_post() ou setup_postdata() ou si vous avez joué avec et besoin de restaurer létat initial des éléments liés aux articles.

Commentaires

  • Rarst signifiait wp_reset_postdata()

Answe r

Il existe des scénarios légitimes dutilisation de query_posts($query), par exemple:

  1. Vous souhaitez afficher une liste darticles ou darticles de type article personnalisé sur une page (à laide dun modèle de page)

  2. Vous voulez que la pagination de ces articles fonctionne

Maintenant, pourquoi voudriez-vous lafficher sur une page au lieu dutiliser un modèle darchive?

  1. Cest plus intuitif pour un administrateur (votre client?) – il peut voir la page dans les « Pages »

  2. Il vaut mieux lajouter aux menus (sans la page, ils « auraient pour ajouter directement lurl)

  3. Si vous souhaitez afficher du contenu supplémentaire (texte, vignette de publication ou tout autre méta-contenu personnalisé) sur le modèle, vous pouvez facilement lobtenir à partir du page (et tout cela a plus de sens pour le client aussi). Voyez si vous avez utilisé un modèle darchive, vous devez soit coder en dur le contenu supplémentaire, soit utiliser par exemple des options de thème / plugin (ce qui le rend moins intuitif pour le client)

Voici « un exemple de code simplifié (qui serait sur votre modèle de page – par exemple 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... }  

Maintenant, pour être parfaitement clair, nous pourrions éviter dutiliser query_posts() ici aussi et utiliser WP_Query à la place – comme ceci:

// ... 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(); // ... 

Mais, pourquoi ferions-nous cela alors que nous avons une si jolie petite fonction disponible?

Commentaires

  • Brian, merci pour cela. Jai ‘ avoir du mal à faire fonctionner pre_get_posts sur une page EXACTEMENT le scénario que vous décrivez: le client doit ajouter des champs / contenu personnalisés à ce qui serait autrement une page darchive, donc un La  » page  » doit être créée; le client a besoin de voir quelque chose à ajouter au menu de navigation, car lajout dun lien personnalisé leur échappe; etc. +1 de moi!
  • Cela peut également être fait en utilisant  » pre_get_posts « . Je lai fait pour avoir une  » page daccueil statique  » répertoriant mes types de messages personnalisés dans un ordre personnalisé et avec un filtre personnalisé. Cette page est également paginée. Consultez cette question pour voir comment cela fonctionne: wordpress.stackexchange.com / questions / 30851 / … Bref, il ny a toujours plus de scénario légitime pour utiliser query_posts;)
  • Parce que  » Il convient de noter que son utilisation pour remplacer la requête principale sur une page peut augmenter les temps de chargement de la page, dans le pire des cas, plus que doubler la quantité de travail nécessaire ou plus. Bien que facile à utiliser, la fonction est également sujette à confusion et à des problèmes plus tard.  » Source codex.wordpress.org/Function_Reference/ query_posts
  • Cette réponse est erronée de toutes sortes. Vous pouvez créer une  » Page  » dans WP avec la même URL que le type de publication personnalisé. Par exemple, si votre CPT est Bananes, vous pouvez obtenir une page nommée Bananes avec la même URL. Ensuite, vous ‘ vous retrouverez avec siteurl.com/bananas. Tant que vous avez archive-bananas.php dans votre dossier de thème, il utilisera le modèle et  » écrasera  » cette page à la place . Comme indiqué dans lun des autres commentaires, lutilisation de cette  » méthode  » crée deux fois la charge de travail pour WP et ne doit donc JAMAIS être utilisée.

Réponse

Je modifie la requête WordPress à partir de 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%")"; } 

Commentaires

  • serait intéressé de voir cet exemple mais où la clause est sur la méta personnalisée.

Réponse

Juste pour souligner quelques améliorations à la réponse acceptée puisque WordPress a évolué avec le temps et que certaines choses sont différentes maintenant (cinq ans plus tard) :

pre_get_posts est un filtre, pour modifier nimporte quelle requête. Il est le plus souvent utilisé pour modifier uniquement la « requête principale »:

Il sagit en fait dun crochet daction. Pas un filtre, et cela affectera nimporte quelle requête.

La requête principale apparaît dans vos modèles sous la forme:

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

En fait, ce nest pas vrai non plus. La fonction have_posts itère lobjet global $wp_query qui nest pas lié uniquement à la requête principale. global $wp_query; peut également être modifié avec les requêtes secondaires.

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

get_posts ()

Il sagit essentiellement dun wrapper pour une instance distincte dun objet WP_Query.

En fait, de nos jours, WP_Query est une classe, nous avons donc une instance dune classe.


Pour conclure: À lépoque, @StephenHarris écrivait très probablement tout cela était vrai, mais au fil du temps, les choses dans WordPress ont changé.

Commentaires

  • Techniquement, il ‘ s tous les filtres sous le capot, les actions ne sont quun simple filtre. Mais vous avez raison ici, cest ‘ une action qui transmet un argument par référence, ce qui diffère des actions plus simples.
  • get_posts renvoie un tableau dobjets de publication, pas un objet WP_Query, donc cest en effet toujours correct. et WP_Query a toujours été une classe, une instance dun class = object.
  • Merci, @Milo, corrigez une raison pour laquelle javais un modèle trop simplifié dans ma tête.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *