web-dev-qa-db-fra.com

Requête personnalisée - messages alternatifs par catégorie

J'ai un type de message personnalisé appelé "services" avec une taxonomie personnalisée appelée "emplacement". Chaque publication est classée dans les catégories "Emplacement A" ou "Emplacement B".

J'ai besoin d'interroger tous les articles du type d'article "services" et de les classer par date. Cependant, plutôt que de simplement lister par date, je veux alterner les posts par chaque catégorie, comme ceci:

  1. Dernier article de "Location A"
  2. Dernier article de "Location B"
  3. 2ème post le plus récent de "Location A"
  4. 2ème post le plus récent de "Location B"
  5. 3ème post le plus récent de "Location A"
  6. 3ème post le plus récent de "Location B"

etc...

Est-il possible de modifier la requête suivante pour y parvenir? Ou dois-je faire quelques jonctions/fusions de bases de données avancées, etc. (comme vous pouvez le deviner, ces requêtes ne me sont pas familières).

<?php $args = array(
        'post_type' => 'services', 
        'posts_per_page' => '-1',
        'order_by' => 'date',
        'order' => 'DESC',
            'tax_query' => array(
                array(
                    'taxonomy' => 'location',
                    'field' => 'slug',
                    'terms' => array ('location-a', 'location-b')
                )
            )
        );
        $query = new WP_Query( $args );

        if (have_posts()) : while( $query->have_posts() ) : $query->the_post(); ?>

Notes complémentaires:

  • Il n'y aura pas un nombre pair de publications dans chaque catégorie, j'ai donc besoin de la requête pour continuer à répertorier les publications de l'emplacement A, une fois que vous aurez épuisé les publications de l'emplacement B, et inversement.
  • Que se passe-t-il si un article a été classé dans les deux catégories? Je ne veux pas que ça se voit deux fois.
  • La taxonomie personnalisée "emplacement" est partagée par plusieurs types de publication. Mais je veux seulement interroger un type de message à la fois.
  • Je dois conserver la capacité de rendre certains messages collants.

Est-ce possible? Merci beaucoup.

3
LBF

MODIFIER

A partir de vos commentaires, j'ai retravaillé l'ensemble de la solution. Je garde la réponse originale juste pour référence

Si j'ai 3 posts collants, ne devraient-ils pas être les 3 premiers posts sur la première page, quelle que soit leur date de publication? Ce qui se passe, c'est que seuls les messages collants qui se trouvent dans cette première série de 10 messages en fonction de leur date sont traités comme tels. Le reste des messages collants apparaît en haut de la page sur laquelle ils tombent, en fonction de leur date. Comment les faire apparaître en haut de la page FIRST, quelle que soit leur date?

J'ai testé ce que vous avez dit, et le comportement des posts collants ne correspond pas à mes attentes lorsque vous utilisez une requête fiscale avec une nouvelle instance de WP_Query.

Solutions possibles

  • Vous pouvez simplement exécuter deux requêtes, une pour les posts collants et une autre comme décrit dans ma réponse initiale, et simplement pour exclure les posts collants de la deuxième requête. Vous aurez juste besoin de retravailler un peu la réponse originale. L'inconvénient est que si vous avez besoin de 10 messages par page, cela ne fonctionnera pas. Pour que cela fonctionne, vous devrez utiliser des compensations

  • La solution que j’ai choisie consiste à traiter toutes les maladies séparément et à les combiner ensuite comme une seule et même solution.

SOLUTION

Je suis allé tester quelques solutions ici pour obtenir celle qui sera la plus rapide et la moins gourmande en ressources. Les exigences définies dans le PO sont assez uniques, aussi cette solution serait-elle excessive dans d'autres situations où il n'est pas nécessaire d'alterner les publications en fonction de la durée, par exemple si vous avez simplement besoin de publications en fonction de la date et de post-it.

La solution complète utilise jusqu'à quatre requêtes personnalisées et vous pouvez penser que c'est assez difficile d'atteindre la base de données, mais ce n'est pas le cas. Au contraire, cela est en réalité deux fois plus rapide que ma réponse initiale, en raison du fait que vous ne faites pas de contrôle pour voir si un message appartient à un terme ou non. Pour accélérer le processus de manière significative, j'ai utilisé des transitoires, ce qui rend cette modification presque quatre fois plus rapide que ma réponse d'origine.

OK, codons: ( Je ne vais pas entrer dans les détails sur certains points comme cela a été traité dans la réponse originale )

J'ai décidé de poster deux possibles pour les posts collants comme vous le verrez. Vous devrez décider comment vous voulez gérer les stickies, puis décommentez et commentez le code en fonction de vos besoins. Voici les deux méthodes que j'ai utilisées

  • Si vos notes persistantes doivent respecter les deux conditions, vous pouvez simplement utiliser le code tel quel.

  • Si vos notes collantes incluent des publications n'appartenant pas aux deux termes définis et que vous devez exclure ceux qui n'appartiennent pas aux deux termes définis, vous devrez alors supprimer le commentaire du code qui a été supprimé, puis supprimer cette ligne.

    $q = array_merge( $sticky_post, $new_posts_array );
    

FONCTIONS DE BASE DU CODE

Les publications (nous récupérons uniquement les ID de publication ici pour accélérer les requêtes) d'un terme spécifique sont extraites séparément. La raison en est qu'il est plus rapide que de récupérer toutes les publications en une seule fois, puis de les trier par terme. Pour m'assurer que vous n'obtenez pas de doublons, j'ai configuré la seconde requête pour exclure tous les posts appartenant aux deux termes. Ces publications sont récupérées par la première requête uniquement

De nouvelles clés sont ensuite attribuées à chacun des deux tableaux renvoyés. Un tableau aura même des clés, l'autre des clés inégales. Ces tableaux sont ensuite combinés et triés. Le nouveau tableau contiendra désormais les messages des deux tableaux triés alternativement par terme

La dernière étape consiste à ajouter les posts collants à cela. Ce que vous avez maintenant est un tableau qui contient les identifiants de post, les post-collants en premier, puis les posts triés alternativement par terme. Ce tableau d'identifiants est enregistré dans un fichier transitoire qui sera mis à jour tous les 7 jours (vous pouvez le définir en conséquence) ou lorsqu'un message est mis à jour, supprimé ou qu'un nouveau message est publié.

Ce tableau d'identifiants de publication est maintenant utilisé normalement pour afficher les publications dans un new WP_Query, et la séquence dans laquelle l'identifiant de publication est utilisé sera utilisée pour trier les publications par. Voici le code complet

if ( false === ( $q = get_transient( 'ordered_posts' ) ) ) {

    $sticky_post = get_option( 'sticky_posts' );
    /* 
     * Only do this if sticky posts can belong to terms outside the given two terms
     * and you only need to include sticky posts that belongs to the given two terms
     * Uncomment this part if needed
    */
    /* 
    if( $sticky_post ) {
        $sticky_args = array(
            'post_type'         => 'services', 
            'posts_per_page'    => -1,
            'post__in'          => $sticky_post,
            'fields'            => 'ids',
            'tax_query'         => array(
                array(
                    'taxonomy'  => 'location',
                    'field'     => 'slug',
                    'terms'     => array ('location-a', 'location-b' )
                )
            )
        );
        $sticky_query = get_posts( $sticky_args );
    }
    */

    $args1 = array(
        'post_type'         => 'services', 
        'posts_per_page'    => -1,
        'post__not_in'      => $sticky_post,
        'fields'            => 'ids',
        'tax_query'         => array(
            array(
                'taxonomy'  => 'location',
                'field'     => 'slug',
                'terms'     => array ('location-a')
            )
        )
    );
    $query1 = get_posts( $args1 );

    $new_posts_array1 = [];

    if( $query1 ) {
        $counter1 = 0;

        foreach ( $query1 as $post ) {
            $new_posts_array1[$counter1++ * 2] = $post;
        }
        unset( $post );
    }

    $args2 = array(
        'post_type'         => 'services', 
        'posts_per_page'    => -1,
        'post__not_in'      => $sticky_post,
        'fields'            => 'ids',
        'tax_query'         => array(
                array(
                    'taxonomy'  => 'location',
                    'field'     => 'slug',
                    'terms'     => array ('location-b')
                ),
                array(
                    'taxonomy'  => 'location',
                    'field'     => 'slug',
                    'terms'     => array ('location-a'),
                    'operator'  => 'NOT IN',
                )
            )
    );
    $query2 = get_posts( $args2 );

    $new_posts_array2 = [];

    if( $query2 ) {
        $counter2 = 0;

        foreach ( $query2 as $post ) {
            $new_posts_array2[($counter2++ * 2) + 1] = $post;
        }
        unset( $post );
    }


    $new_posts_array = $new_posts_array1 + $new_posts_array2;
    ksort( $new_posts_array );

    // Comment this line out if you uncommented the other block of code
    $q = array_merge( $sticky_post, $new_posts_array );

    /* 
     * If you going to use the first block of commented-out code
     * then you will need to uncomment this piece of code. Just remember
     * to comment the piece of code above out as stated. You cannot have both
     * pieces of code going at once
    */
    /*
    if( isset( $sticky_query ) ) {
        $q = array_merge( $sticky_query, $new_posts_array );
    }else{
        $q = $new_posts_array;
    }   
    */

    set_transient( 'ordered_posts', $q, 7 * DAY_IN_SECONDS );
}

$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
 'post_type' => 'services',
    'paged'                 => $paged,
    'posts_per_page'        => 5,
    'post__in'              => $q,
    'ignore_sticky_posts'   => 1,
    'orderby'               => 'post__in',
);
$query = new WP_Query( $args );

if ( $query->have_posts() ) {
    while ( $query->have_posts() ) {
        $query->the_post();

        get_template_part( 'content', get_post_format() );

    }

    next_posts_link( 'Older Entries', $query->max_num_pages ); //Remember the $max_pages parameter with custom queries
    previous_posts_link( 'Newer Entries' );

    wp_reset_postdata();
}

Ensuite, dans votre fichier functions.php, ajoutez le code suivant. Ceci supprimera le transitoire si une nouvelle publication est publiée ou si une publication est mise à jour ou si le statut change d'une publication.

add_action( 'transition_post_status', function ( $new_status, $old_status, $post )
{
        delete_transient( 'ordered_posts' );

}, 10, 3 );

DÉBOGAGE DU CODE CI-DESSUS

Une fois qu'un transitoire est défini, vous ne pouvez pas modifier le code qu'il contient. Ces modifications n'apparaîtront qu'à l'expiration du transitoire ou à sa suppression. Si le code ne fonctionne pas, procédez comme suit:

  • Tout d’abord, mettez à jour tout message pour supprimer le transitoire ou supprimez-le manuellement de la base de données.

  • Puis supprimez les deux lignes suivantes

    if ( false === ( $q = get_transient( 'ordered_posts' ) ) ) {
    
  • et

    set_transient( 'ordered_posts', $q, 7 * DAY_IN_SECONDS );
        }
    
  • Cela supprimera le transitoire d'être défini.

  • Une fois le transitoire supprimé, faites une var_dump( $var ) de toutes les variables et vérifiez si vous obtenez le résultat souhaité. Vérifiez spécialement les requêtes et ce qui est renvoyé

    • Exemple: vider ce qui est retourné par la requête $query1

      var_dump( $query1 );
      

Cela devrait vous donner une idée du problème. Si vous obtenez le résultat souhaité, renvoyez les lignes que vous avez supprimées pour le transitoire. Assurez-vous simplement que le transitoire a été supprimé avant de le réinitialiser, sinon vous obtiendrez les résultats précédents.

RÉPONSE ORIGINALE

Cette question m'a en fait donné un changement pour jouer avec les idées. Je pense que cette question a besoin d'une réponse appropriée. J'espère que cela répond à tous vos problèmes.

Vous pourrez le faire avec une seule requête. La première chose à faire sera d’obtenir tous vos messages des deux termes en une fois, comme vous l’avez déjà fait. Juste une remarque, vous n'avez pas besoin de définir l'ordre de tri car date et DESC sont les valeurs par défaut.

La taxonomie personnalisée "emplacement" est partagée par plusieurs types de publication. Mais je veux seulement interroger un type de message à la fois.

Ajoutez simplement le paramètre post_type à vos arguments de requête pour cibler un type de publication spécifique.

<?php 
$args = array(
    'post_type' => 'services', 
    'posts_per_page' => '-1',
    'tax_query' => array(
            array(
                'taxonomy' => 'location',
                'field' => 'slug',
                'terms' => array ('location-a', 'location-b')
            )
        )
);
$query = new WP_Query( $args );

if( $query->have_posts() ) {

Vous devez maintenant diviser votre tableau de publications retournées en deux tableaux distincts, un tableau pour les termes location-aet location-b et le second pour les posts collants. Le tableau des messages retournés est conservé dans $query->posts

Que se passe-t-il si un article a été classé dans les deux catégories? Je ne veux pas que ça se voit deux fois.

Vous devez décider au préalable de la manière dont vous souhaitez traiter cette situation, soit comme location-a ou location-b, sinon vous risquez d'obtenir une duplication. Disons que nous les traitons comme location-a

Je dois conserver la capacité de rendre certains messages collants.

Les post-it seront au sommet de votre tableau retourné, et après tout le tri, nous aimerions toujours les garder au top, quel que soit le terme. Donc, permet d’exclure les posts collants du tri et de les renvoyer tels quels.

Donc, vous pouvez faire quelque chose comme ça

$counter1 = 0;
$counter2 = 0;

$new_posts_array = [];
$sticky = [];
foreach ( $query->posts as $post ) {
    if( is_sticky() ) {
       $sticky[] = $post;
    }elseif( has_term( 'location-a', 'location' ) && has_term( 'location-b', 'location' ) || has_term( 'location-a', 'location' ) ) {
       $new_posts_array[$counter1++ * 2] = $post;
    }else{
       $new_posts_array[($counter2++ * 2) + 1] = $post;
    }
}

Toutes les questions ont été abordées maintenant. Nous avons maintenant deux tableaux, l'un contenant le tableau de messages collants et l'autre les clés réorganisées avec un tableau de messages

Nous devons maintenant trier le tableau de publications de façon naturelle pour que les clés soient dans l’ordre de tri normal à partir de 0. ( Nous pouvons également "réinitialiser" toutes les clés, bien que cela ne soit pas nécessaire )

ksort($new_posts_array);

Nous pouvons maintenant fusionner nos deux tableaux pour avoir à nouveau un tableau. Ce tableau sera celui qui affichera nos posts

$q = array_merge( $sticky, $new_posts_array );

Il ne reste plus maintenant qu'à supprimer le tableau de publications d'origine, à réinitialiser le tableau de publications d'origine avec notre tableau réorganisé, à rembobiner la boucle et à la réexécuter pour afficher notre liste.

unset( $query->posts );
$query->posts = $q;

$query->rewind_posts();

while( $query->have_posts() ) { 
   $query->the_post();

  //Display loop elements

}
wp_reset_postdata();

}

TOUS ENSEMBLE MAINTENANT!!!

<?php 
$args = array(
    'post_type' => 'services', 
    'posts_per_page' => '-1',
    'tax_query' => array(
            array(
                'taxonomy' => 'location',
                'field' => 'slug',
                'terms' => array ('location-a', 'location-b')
            )
        )
);
$query = new WP_Query( $args );

if( $query->have_posts() ) {

    $counter1 = 0;
    $counter2 = 0;

    $new_posts_array = [];
    $sticky = [];
    foreach ( $query->posts as $post ) {
        if( is_sticky() ) {
           $sticky[] = $post;
        }elseif( has_term( 'location-a', 'location' ) && has_term( 'location-b', 'location' ) || has_term( 'location-a', 'location' ) ) {
           $new_posts_array[$counter1++ * 2] = $post;
        }else{
           $new_posts_array[($counter2++ * 2) + 1] = $post;
        }
    }

    ksort($new_posts_array);

    $q = array_merge( $sticky, $new_posts_array );

    unset( $query->posts );
    $query->posts = $q;

    $query->rewind_posts();

    while( $query->have_posts() ) { 
       $query->the_post();

      //Display loop elements like
      echo get_the_term_list( $post->ID, 'location');
      the_title(); 

    }
    wp_reset_postdata();

}

QUERY AVEC PAGINATION

// set the "paged" parameter (use 'page' if the query is on a static front page)
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
    'post_type'         => 'services', 
    'paged'             => $paged,
    'posts_per_page'    => '5',
    'tax_query'         => array(
            array(
                'taxonomy'  => 'location',
                'field'     => 'slug',
                'terms'     => array ('location-a', 'location-b')
            )
        )
);
$query = new WP_Query( $args );

if( $query->have_posts() ) {

    $counter1 = 0;
    $counter2 = 0;

    $new_posts_array = [];
    $sticky = [];
    foreach ( $query->posts as $post ) {
        if( is_sticky() ) {
           $sticky[] = $post;
        }elseif( has_term( 'location-a', 'location' ) && has_term( 'location-b', 'location' ) || has_term( 'location-a', 'location' ) ) {
           $new_posts_array[$counter1++ * 2] = $post;
        }else{
           $new_posts_array[($counter2++ * 2) + 1] = $post;
        }
    }

    ksort($new_posts_array);

    $q = array_merge( $sticky, $new_posts_array );

    unset( $query->posts );
    $query->posts = $q;

    $query->rewind_posts();

    while( $query->have_posts() ) { 
       $query->the_post();

      //Display loop elements like
      echo get_the_term_list( $post->ID, 'location');
      the_title(); 

    }

    next_posts_link( 'Older Entries', $query->max_num_pages ); //Remember the $max_pages parameter with custom queries
    previous_posts_link( 'Newer Entries' );


    wp_reset_postdata();

}
6
Pieter Goosen