web-dev-qa-db-fra.com

Devrais-je utiliser Pre Get Posts ou WP_Query

J'ai la requête suivante que j'appelle dans mon modèle taxonomy.php via query_brands_geo('dealers', 'publish', '1', $taxtype, $geo, $brands);

Cette fonction fonctionne parfaitement. Toutefois, après avoir lu le codex pour les publications de requête, il a mentionné pré_get_posts comme moyen privilégié de modification de la requête par défaut. Les pre_get_posts seraient-ils plus efficaces que ma fonction wp_query ci-dessous?

Si tel est le cas, comment pourrais-je construire le pre_get_posts et transmettre ma variable et ma requête ci-dessous?

function my_custom_query($posttype, $poststatus, $paidvalue, $taxtype, $geo, $brands) {
   global $wp_query; 
   $wp_query = new WP_Query();
   $args = array( 
      'post_type' => $posttype, 
      'post_status' => array($poststatus), 
      'orderby' => 'Rand', 
      'posts_per_page' => 30, 
      'meta_query' => array( 
         array( 
            'key' => 'wpcf-paid', 
            'value' => array($paidvalue), 
            'compare' => 'IN', 
            ) 
      ), 
      'tax_query' => array( 
         'relation' => 'AND', 
         array( 
            'taxonomy' => $taxtype, 
            'field' => 'slug', 
            'terms' => $geo 
         ), 
         array( 
            'taxonomy' => 'brands', 
            'field' => 'slug', 
            'terms' => $brands 
         ) 
      ) 
   ); 

   return $wp_query->query($args); 
} 
29
user1609391

pre_get_posts exécutera la même requête, donc les deux prendront le même temps. Toutefois, si vous utilisez l'action pre_get_posts, vous enregistrez une ou plusieurs requêtes SQL. À l'heure actuelle, WordPress exécute la requête par défaut, puis vous exécutez votre requête avec cette fonction qui remplace les résultats de la requête par défaut (la requête par défaut résultante est donc inutile). Vous trouverez ci-dessous comment déplacer votre $args vers

function custom_pre_get_posts($query, $posttype='dealers', $poststatus='publish', $paidvalue='1', $taxtype='any_default_value', $geo='any_default_value', $brands='any_default_value') {

    // filter your request here.
    if($query->is_category) {

        $args = array(
            'post_type' => $posttype,
            'post_status' => array($poststatus),
            'orderby' => 'Rand',
            'posts_per_page' => 30,
            'meta_query' => array(
                array(
                    'key' => 'wpcf-paid',
                    'value' => array($paidvalue),
                    'compare' => 'IN',
                )
            ),
            'tax_query' => array(
                'relation' => 'AND',
                array(
                    'taxonomy' => $taxtype,
                    'field' => 'slug',
                    'terms' => $geo
                ),
                array(
                    'taxonomy' => 'brands',
                    'field' => 'slug',
                    'terms' => $brands
                )
            )
        );
        $query->query_vars = $args;
    }
}
add_action('pre_get_posts', 'custom_pre_get_posts');
14
M-R

Une réponse tardive car la réponse la plus votée cassera votre requête et n'est tout simplement pas vraie sur certains points principaux.

Le principal WP_Query et ses filtres

Tout d’abord, WordPress utilise en interne query_posts() (un fin emballage autour de WP_Query que ne devrait pas être utilisé dans des thèmes ou des plugins) pour créer un WP_Query. Ce WP_Query agit en tant que boucle/requête principale. Cette requête passera par de nombreux filtres et actions jusqu'à ce que la chaîne de requête SQL réelle soit générée. L'un d'entre eux est pre_get_posts. Les autres sont posts_clauses, posts_where, etc. qui aussi vous permettent d'intercepter le processus de création d'une chaîne de requête.

Un regard en profondeur sur ce qui se passe à l'intérieur du noyau

WordPress exécute la fonction wp() (dans wp-includes/functions.php), qui appelle $wp->main() ($wp est un objet de la classe WP, définie dans wp-includes/class-wp.php). Ceci dit à WordPress de:

  1. Analyser l'URL dans une spécification de requête en utilisant WP->parse_request() - pour plus d'informations, voir ci-dessous.
  2. Définissez toutes les variables is_ utilisées par les balises conditionnelles à l'aide de $wp_query->parse_query() ($wp_query est un objet de class WP_Query, défini dans wp-includes/query.php). Notez que malgré le nom de cette fonction, dans ce cas, WP_Query->parse_query ne fait en réalité aucune analyse syntaxique pour nous, puisque ceci est fait avant par WP->parse_request().
  3. Convertissez la spécification de requête en requête de base de données MySQL et exécutez la requête de base de données pour obtenir la liste des publications, dans la fonction WP_Query-> get_posts (). Enregistrez les articles dans l'objet $ wp_query à utiliser dans la boucle WordPress.

Source Codex

Conclusion

Si vous voulez vraiment modifier la requête principale, vous pouvez utiliser une grande variété de filtres. Utilisez simplement $query->set( 'some_key', 'some_value' ); pour changer les données ou utilisez $query->get( 'some_key' ); pour récupérer les données pour effectuer des contrôles conditionnels. Cela vous évitera de faire une seconde requête, car vous modifiez la requête SQL uniquement.

Si vous devez faire une requête additional, utilisez un objet WP_Query. Cela va ajouter une autre requête à la base de données.

Exemple

Comme les réponses fonctionnent toujours mieux avec un exemple, vous en avez ici un très gentil (accessoire de Brad Touesnard), qui étend simplement l’objet principal et est donc assez réutilisable (en faire un plugin):

class My_Book_Query extends WP_Query
{
    function __construct( $args = array() )
    {
        // Forced/default args
        $args = array_merge( $args, array(
            'posts_per_page' => -1
        ) );

        add_filter( 'posts_fields', array( $this, 'posts_fields' ) );

        parent::__construct( $args );
    }

    public function posts_fields( $sql )
    {
        return "{$sql}, {$GLOBALS['wpdb']->terms}.name AS 'book_category'";
    }
}

Vous pouvez ensuite exécuter votre seconde _/requête supplémentaire, comme vous pouvez le voir dans l'exemple suivant. N'oubliez pas de réinitialiser votre requête par la suite.

$book_query = new My_Book_Query();
if ( $book_query->have_posts() )
{
    while ( $book_query->have_posts() )
    {
        $book_query->the_post();
        # ...do stuff...
    } // endwhile;
    wp_reset_postdata();
} // endif;
10
kaiser

Consultez les réponses sous Quand utiliser WP_query (), query_posts () et pre_get_posts .

C'est une excellente ressource si vous avez des doutes.

6
fischi