web-dev-qa-db-fra.com

Oblitérer la requête principale et la remplacer

Il y a beaucoup de bonnes ressources sur la façon de modifier la requête principale, ou d'ajouter des boucles secondaires ...

Mais je souhaite en réalité remplacer complètement la requête principale par une requête totalement différente.

Je pirate une de mes pages pour servir, essentiellement, de page de catégorie. (Notez que je passe de "page" à "post" dans mes efforts pour le faire.) Mais quand je modifie la requête principale en procédant comme suit:

function front_page_announcements( $query ) {
    if ( $query->query_vars['page_id'] == 84 && $query->is_main_query() && !$query->is_admin ) {
        $query->set("category_name", "special-announcement");
        $query->set("page_id", NULL);
    }
}
add_action( 'pre_get_posts', 'front_page_announcements' );

Je finis par obtenir chaque page (pas post) dans la base de données. Ce que je veux réellement, c’est chaque message (pas la page) avec un identifiant de catégorie de 3, ou special-announcement dans mon cas.

Je ne veux pas faire d'appels inutiles à la base de données, il me semble donc que je veux utiliser le crochet d'action pre_get_posts, mais je n'arrive pas à le comprendre. Même le simple réglage de $query = new WP_Query('cat=3') ne semble pas fonctionner.

6
Don

Lorsque 'pre_get_posts' est activé, WordPress a déjà effectué de nombreuses tâches, telles que configurer toutes les variables de la requête (également la requête que vous n'envoyez pas) et configurer toutes les propriétés conditionnelles (toutes les propriétés is_*). Donc, si vous voulez complètement remplacer la requête, vous devez réinitialiser tout cela et définir les vôtres.

En fait, même si votre code fonctionne, WordPress utilisera page.php comme modèle.

Cependant, il existe une approche plus simple: act before WordPress fait tout.

Un bon endroit est le crochet de filtre 'request'; à ce moment-là, WordPress a créé les vars de requête à partir d’url et va passer ces vars à WP_Query. Vous pouvez alors intercepter et modifier les arguments des requêtes avant de les envoyer.

Cette action est déclenchée par la classe WP et transmet les vars de requête à définir ( voir code ).

add_filter( 'request', function( array $query_vars ) {

  // triggered also in admin pages
  if ( is_admin() )
    return $query_vars;

  // you should check also for page slug, because when pretty permalink are active
  // WordPress use 'pagename' query vars, not 'page_id'
  $id = isset($query_vars['page_id']) && (int) $query_vars['page_id'] === 84;
  // remember to replace "slug" with real page slug
  $name = isset($query_vars['pagename']) && $query_vars['pagename'] === 'slug';

  if ( ( $id || $name)  && ! isset($query_vars['error']) ) {
    $query_vars = array('category_name' => 'special-announcement');
  }

  return $query_vars;

});

Remplacez 'slug' par le slug réel de votre page, puis laissez WordPress faire son travail.

Notez que je n'ai pas vérifié la requête principale, car 'request' n'est déclenché que pour la requête principale.

Si vous souhaitez utiliser un modèle spécifique, vous devez utiliser un filtre sur template_include sinon 'category.php' (ou le modèle approprié en fonction de modèle hiérarchie ) sera utilisé.

12
gmazzap