web-dev-qa-db-fra.com

Query publie des auteurs distincts

J'essaie d'obtenir un message d'une catégorie ordonnée au hasard, mais en m'assurant que l'auteur ne se répète pas.

J'ai donc cette requête qui fonctionne comme prévu, mais il y a une chance que l'auteur répète dans ces 4 messages. Donc, des idées pour que je puisse m'assurer que ça ne marche pas?

Je pensais utiliser $ wpdb mais j'espérais une solution plus simple.

$args = array (
'post_type'              => 'post',
'post_status'            => 'publish',
'category_name'          => 'premium',
'orderby'                => 'Rand',
'posts_per_page'         => 4,
'post__not_in'           => get_option( 'sticky_posts' ),
'date_query'             => array(
    array(
         array(
                'before' => 'this week'
        ) 
    ),
),
);
$query = new WP_Query( $args );

modifier:

J'ai essayé cela dans la boucle. Mais pour une raison quelconque, un seul post est affiché et le tableau $ temp est toujours rempli avec tous les doublons.

$temp=array();

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

 $author_id = the_author_meta( 'ID' );
 if( !in_array($author_id, $temp) ):
  array_Push($temp, $author_id);
  //loop stuff
 endif;
endwhile;endif;wp_reset_query();
3
CiprianD

Avec ce que vous demandez, il est vraiment difficile de trouver un moyen simple, performant et fiable. Comme @birgire l’a déjà indiqué, sa solution n’est pas fiable, mais d’après les tests, elle semble être la plus rapide avec 2 requêtes de base dans une moyenne d’environ 0,015s.

D'une discussion rapide entre @birgire et moi dans les commentaires de sa réponse , j'ai décidé d'essayer de le faire avec ce que Wordpress propose. C'est de loin le moyen le plus fiable, mais son prix est raisonnable, avec des requêtes de 20 db dans une moyenne d'environ 0,05 s.

Le véritable gros problème est que vous ne pouvez utiliser aucun type de cache en raison de la demande de résultats aléatoires. J'ai donc dû rechercher d'autres moyens de réduire le temps et les appels à la base de données.

Pour la première section, j’ai utilisé cette solution de @birgire (également mentionné par lui dans les commentaires) où nous utilisons pre_user_query pour modifier la requête SQL de WP_User_Query afin d’obtenir uniquement le nombre d’auteurs nécessaire de manière aléatoire. Cette section du code est vraiment rapide. Pour augmenter les performances, j'ai également défini le WP_User_Query pour obtenir uniquement l'ID de l'auteur car c'est tout ce dont nous avons besoin. Cette section compte 2 requêtes de base de données en moyenne de 0,002s.

Pour obtenir un seul article de chaque auteur, nous devons créer un seul WP_Query pour chacun, ce qui représente un total de 4 dans votre cas. C'est le côté plutôt coûteux de la fonction. Les facteurs contributifs qui ralentissent réellement les requêtes sont le fait que nous avons besoin d'un ordre aléatoire et que nous faisons également un tax_query qui utilise des clauses de jointure.

La seule façon d'accélérer cette section était de simplement obtenir les identifiants de poste. Globalement, cela est plus rapide que de récupérer les publications complètes et de les afficher plutôt que de simplement prendre les ID de publication et d'exécuter un autre WP_Query par la suite. J'ai 7 requêtes moins en cours d'exécution d'une instance supplémentaire de WP_Query

OK, assez parlé, voici la fonction: ( Peut-être utiliser certains réglages )

function wpse177162_random_author_posts($number = 4, $args = [])
{

    function my_pre_user_query( $q )
    {

        $limit = preg_replace( '/[^\d]/', '', $q->query_limit );

        $from   = 'WHERE 1=1';
        $to     = sprintf( 'WHERE Rand()<(SELECT ((%d/COUNT(*))*10) FROM %susers)', 
                            $limit, 
                            $GLOBALS['wpdb']->prefix 
                 );

        $q->query_where   = str_replace( $from, $to, $q->query_where );
        $q->query_orderby = ' ORDER BY Rand() ';

        // remove the hook    
        remove_action( current_filter() , __FUNCTION__ );
    }

    $user_query_args = [
        'who'    => 'authors',
        'fields' => 'ID',
        'number' => $number,
    ];

    add_action( 'pre_user_query', 'my_pre_user_query' );
    $user_query = new WP_User_Query($user_query_args);
    remove_action( 'pre_user_query', 'my_pre_user_query' );

    $users = $user_query->results;
    $post_ids = '';
    if ($users) {

        foreach ($users as $user) {

            $user_args = [
                'author' => $user,
                'fields' => 'ids',
             'no_found_rows' => true
        ];
            $combined_args = wp_parse_args($args, $user_args);
            $q = new WP_Query($combined_args);

            $q_posts[] = $q->posts;

        }

        foreach ($q_posts as $q_post) {

            foreach ($q_post as $v ) {

                $post_ids[] = $v;

            }

        }

    }
    return (array) $post_ids;

}

Juste quelques notes sur la fonction

  • Le premier paramètre $number est le nombre d’auteurs à obtenir

  • Le deuxième paramètre est $args, qui est identique aux paramètres utilisés par WP_Query et est également directement introduit dans WP_Query en tant qu'arguments de requête. Vous pouvez l'utiliser de la même manière, à une exception près, ne définissez pas les paramètres d'auteur, cela endommagerait la fonction.

Pour en arriver à son utilisation, vous l’utiliseriez ensuite dans votre modèle comme ceci

$author_posts = wpse177162_random_author_posts(4, array('posts_per_page' => 1, 'cat' => 1, 'orderby' => 'Rand'));
$q = new WP_Query(array('post__in' => $author_posts));

Comme nous l’avons déjà dit, le WP_Query supplémentaire est utilisé pour des raisons de performance, car le faire de cette manière donnait de meilleurs chiffres lors des tests.

MODIFIER

Sur recommandation de @birgire, j'ai mis à jour le code ci-dessus avec no_found_rows pour économiser sur les appels de base de données. J'ai obtenu une légère amélioration des performances. Lors du test, j'ai enregistré 4 appels de base de données, même si le temps est resté essentiellement le même.

update_post_meta_cache et update_post_term_cache ont en fait doublé le temps nécessaire pour compléter les requêtes, et les requêtes sont restées fixes à 20 minutes. Donc pas un chemin à parcourir :-)

1
Pieter Goosen

Par curiosité, j'ai joué avec des requêtes SQL statiques et celle-ci semblait fonctionner:

SELECT r.post_author, r.ID, r.post_title FROM (
    SELECT  p.post_author, p.ID, p.post_title
    FROM wp_posts p 
    INNER JOIN wp_term_relationships tr ON ( p.ID = tr.object_id ) 
    WHERE    p.post_date < '2015-02-05 00:00:00'
         AND p.ID NOT IN (10,20) 
         AND tr.term_taxonomy_id IN (1)
         AND p.post_type = 'post' 
         AND p.post_status = 'publish' 
    ORDER BY Rand() 
) as r 
GROUP BY r.post_author
LIMIT 0,4

J'ai d'abord essayé de grouper directement sur le champ post_author et de commander par Rand(), mais les champs non agrégés n'ont pas été utilisés.

Mais bien sûr ce n'est pas très flexible ;-)

2
birgire

Une autre solution qui semble fonctionner est expliquée: ici

Ajout du filtre avant la requête:

function filter_authors($groupby) {
 global $wpdb;
 $groupby = " {$wpdb->posts}.post_author";
 return $groupby;
}

add_filter('posts_groupby','filter_authors');

Et sans oublier de l'enlever ensuite:

remove_filter('posts_groupby','filter_authors');

Cette solution semble fonctionner assez bien.

0
CiprianD