J'ai lu @ nacin'svous ne connaissez pas Query hier et j'ai été un peu dérouté par un lapin interrogateur. Avant hier, j'étais (à tort) en train d'utiliser query_posts()
pour tous mes besoins d'interrogation Maintenant, je suis un peu plus sage quant à l’utilisation de WP_Query()
, mais il reste des zones grises.
Ce que je pense savoir avec certitude:
Si je fais supplémentaire} boucles n'importe où sur une page - dans la barre latérale, dans un pied de page, tout type de "messages liés", etc. - je veux utiliser WP_Query()
. Je peux utiliser cela à plusieurs reprises sur une seule page sans aucun dommage. (droit?).
Ce que je ne sais pas avec certitude
pre_get_posts
vs WP_Query()
? Dois-je utiliser pre_get_posts
pour tout maintenant))?if have_posts : while have_posts : the_post
et écrire mon propre WP_Query()
?) Ou modifier la sortie à l'aide de pre_get_posts
dans mon fichier functions.php?tl; dr
Les règles que je voudrais en tirer sont les suivantes:
query_posts
plusWP_Query()
Merci pour toute sagesse
Terry
ps: J'ai vu et lu: Quand utiliser WP_Query vs query_posts () vs get_posts ()? qui ajoute une autre dimension - get_posts
. Mais ne traite pas de pre_get_posts
du tout .
Vous avez raison de dire:
Ne plus jamais utiliser
query_posts
pre_get_posts
est un filtre permettant de modifier any query. 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 voudrais également vérifier que is_admin()
renvoie false - bien que cela puisse être redondant.). La requête principale apparaît dans vos modèles en tant que:
if( have_posts() ):
while( have_posts() ): the_post();
//The loop
endwhile;
endif;
Si vous ressentez le besoin d’éditer cette boucle, utilisez pre_get_posts
. Si vous êtes tenté d'utiliser query_posts()
- utilisez plutôt pre_get_posts
.
La requête principale est une instance importante de WP_Query object
. WordPress l'utilise pour décider quel modèle utiliser, par exemple, et tous les arguments passés dans l'URL (par exemple, la pagination) sont tous canalisés dans cette instance de l'objet WP_Query
.
Pour les boucles secondaires (par exemple, dans les barres latérales ou les listes de "publications connexes"), vous voudrez créer votre propre instance distincte de l'objet 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();
Remarquez wp_reset_postdata();
- c'est parce que la boucle secondaire remplacera la variable globale $post
qui identifie la "publication actuelle". Cela réinitialise essentiellement cela au $post
nous sommes sur.
Il s'agit essentiellement d'un wrapper pour une instance distincte d'un objet WP_Query
. Cela retourne un tableau d'objets post. Les méthodes utilisées dans la boucle ci-dessus ne vous sont plus disponibles. Ce n'est pas une "boucle", simplement un tableau d'objets post.
<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>
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.pre_get_posts
.Il existe deux contextes différents pour les boucles:
Le problème avec query_posts()
est que c’est une boucle secondaire qui essaie d’être principale et qui échoue lamentablement. Donc oubliez ça existe.
query_posts()
pre_get_posts
avec la vérification $query->is_main_query()
request
(un peu trop rugueux, donc ce qui est en haut est préférable)Utilisez new WP_Query
ou get_posts()
qui sont à peu près interchangeables (ce dernier est plus fin que l'ancien).
Utilisez wp_reset_query()
si vous avez utilisé query_posts()
ou si vous avez manipulé le $wp_query
global directement - vous n’auriez donc presque jamais besoin de le faire.
Utilisez wp_reset_postdata()
si vous avez utilisé the_post()
ou setup_postdata()
ou si vous vous êtes trompé avec le $post
global et que vous devez restaurer l'état initial d'éléments liés à la publication.
Il existe des scénarios légitimes pour utiliser query_posts($query)
, par exemple:
Vous souhaitez afficher une liste de publications ou des publications de type publication personnalisée sur une page (à l'aide d'un modèle de page)
Vous voulez faire de la pagination de ces messages
Maintenant, pourquoi voudriez-vous l'afficher sur une page au lieu d'utiliser un modèle d'archive?
C'est plus intuitif pour un administrateur (votre client?) - il peut voir la page dans les 'Pages'
C'est mieux pour l'ajouter aux menus (sans la page, il faudrait ajouter l'URL directement)
Si vous souhaitez afficher du contenu supplémentaire (texte, miniature de publication ou tout méta-contenu personnalisé) sur le modèle, vous pouvez facilement l'obtenir à partir de la page (et tout cela est plus logique pour le client également). Voyez si vous avez utilisé un modèle d’archive, vous devez coder en dur le contenu supplémentaire ou 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 se trouverait 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 aussi éviter d'utiliser query_posts()
ici et utiliser WP_Query
- 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 petite fonction aussi agréable à utiliser?
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%')";
}
Juste pour souligner quelques améliorations à la réponse acceptée depuis que WordPress a évolué au fil du temps et certaines choses sont différentes maintenant (cinq ans plus tard):
pre_get_posts
est un filtre permettant de modifier n'importe quelle requête. Il est le plus souvent utilisé pour modifier uniquement la "requête principale":
Est en fait un crochet d’action. Ce n'est pas un filtre et cela affectera toute requête.
La requête principale apparaît dans vos modèles en tant que:
if( have_posts() ):
while( have_posts() ): the_post();
//The loop
endwhile;
endif;
En fait, ce n'est pas vrai non plus. La fonction have_posts
itère l'objet global $wp_query
qui n'est pas lié only à 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 s'agit essentiellement d'un wrapper pour une instance distincte d'un objet WP_Query.
En fait, de nos jours, WP_Query
est une classe, nous avons donc une instance de classe.
Pour conclure: à l'époque où @StephenHarris a écrit le plus probablement, tout cela était vrai, mais au fil du temps, les choses dans WordPress ont été modifiées.