web-dev-qa-db-fra.com

Liste des auteurs avec des articles dans une catégorie

J'essaie de créer un widget personnalisé pour afficher les auteurs contributeurs pour la catégorie en cours de visualisation sur un site WordPress. J'ai le code PHP suivant:

<?php
if (is_category()) {
?>
// Grab posts from the current category
<?php
    $current_category = single_cat_title(“”, false);
    $author_array     = array();
    $args             = array(
        ‘numberposts’ => -1,
        ‘category_name’ => $current_category,
        ‘orderby’ => ‘author’,
        ‘order’ => ‘ASC’
    );
    // Get the posts in the array and create an array of the authors
    $cat_posts        = get_posts($args);
    foreach ($cat_posts as $cat_post):
        if (!in_array($cat_post->post_author, $author_array)) {
            $author_array[] = $cat_post->post_author;
        }
    endforeach;
    // Get the author information and build the output
    foreach ($author_array as $author):
        $auth      = get_userdata($author)->display_name;
        $auth_link = get_userdata($author)->user_login;
        echo "<a href='/author/'" . $auth_link . "'>" . $auth . "</a>" . '<br \/>';
    endforeach;

    // Testing to make sure the current category is being pulled correctly  
    echo $current_category;
?>
<?php
}
?>

Il affiche les auteurs du site, mais ils ne changent pas de catégorie à catégorie - les mêmes trois sont affichés dans chaque section. L'instruction de test à la fin du bloc de code fonctionne comme prévu: la catégorie affichée dans le widget correspond à la catégorie d'URI.

Avez-vous pensé où je me suis trompé en créant le tableau d'auteur?

1
Brian

Cela peut devenir une opération assez coûteuse qui peut sérieusement réduire le temps de chargement d'une page. A ce stade, votre code est assez cher. Regardons un meilleur moyen de résoudre ce problème.

Ce que nous devons faire, c'est minimiser le temps passé dans la base de données. Pour ce faire, nous n'obtiendrons que les informations dont nous avons besoin, à savoir la propriété post_author de l'objet post. Comme nous le faisons actuellement, il n’existe aucun moyen natif d’obtenir la propriété post_author à partir de la base de données avec WP_Query, nous n’avons la possibilité que d’obtenir l’objet complet ou uniquement les publications post ID. Pour modifier le comportement ( et le SQL généré ), nous allons utiliser le filtre posts_fields dans lequel nous pouvons ordonner à la requête SQL de simplement renvoyer le champ post_author, ce qui nous fera économiser une tonne de temps. la base de données car nous n'obtenons que ce dont nous avons besoin.

Deuxièmement, pour améliorer les performances, nous indiquerons à WP_Query de ne pas mettre en cache les données de publication, les données de terme et les métadonnées. Comme nous n’aurons pas besoin de métadonnées ni de données post-terme, nous pouvons simplement demander à WP_Query de ne pas les interroger et de les mettre en cache pour une utilisation ultérieure, cela nous évite également beaucoup de temps supplémentaire passé en db, temps d’ajout de ces données cache, et nous allons également enregistrer sur les requêtes de base de données.

Mettons tout cela dans le code: ( NOTE: Tout le code n'est pas testé et nécessite PHP 5.4+ )

posts_fields FILTRE

add_filter( 'posts_fields', function ( $fields, \WP_Query $q ) use ( &$wpdb )
{
    remove_filter( current_filter(), __FUNCTION__ );

    // Only target a query where the new wpse_post_author parameter is set to true
    if ( true === $q->get( 'wpse_post_author' ) ) {
        // Only get the post_author column
        $fields = "
            $wpdb->posts.post_author
        ";
    }

    return $fields;
}, 10, 2);

Vous remarquerez que nous avons un déclencheur personnalisé appelé wpse_post_author. Chaque fois que nous passons une valeur de true à ce déclencheur personnalisé, notre filtre se déclenche.

get_posts() QUERY

Par défaut, get_posts() passe suppress_filters=true à WP_Query afin d'éviter que les filtres agissent sur get_posts(). Pour que notre filtre fonctionne, nous devons donc redéfinir la valeur sur True.

Juste une autre remarque, pour obtenir la catégorie actuelle de manière fiable, utilisez $GLOBALS['wp_the_query']->get_queried_object() et $GLOBALS['wp_the_query']->get_queried_object_id() pour l’ID de catégorie.

if ( is_category() ) {
    $current_category = get_term( $GLOBALS['wp_the_query']->get_queried_object() );

    $args = [
        'wpse_post_author'       => true, // To trigger our filter
        'posts_per_page'         => -1,
        'orderby'                => 'author',
        'order'                  => 'ASC',
        'suppress_filters'       => false, // Allow filters to alter query
        'cache_results'          => false, // Do not cache posts
        'update_post_meta_cache' => false, // Do not cache custom field data
        'update_post_term_cache' => false, // Do not cache post terms
        'tax_query'              => [
            [
                'taxonomy'         => $current_category->taxonomy,
                'terms'            => $current_category->term_id,
                'include_children' => true
            ]
        ]
    ];
    $posts_array = get_posts( $args );

    if ( $posts_array ) {
        // Get all the post authors from the posts
        $post_author_ids = wp_list_pluck( $posts_array, 'post_author' );

        // Get a unique array of ids
        $post_author_ids = array_unique( $post_author_ids );

        // NOW WE CAN DO SOMETHING WITH THE ID'S, SEE BELOW TO INCLUDE HERE
    }
}

Comme vous pouvez le constater, j’ai utilisé un tax_query, ce qui est une préférence personnelle du fait de sa souplesse. Vous pouvez également réutiliser le code sur n’importe quelle page de terme sans avoir à le modifier. Dans ce cas, il vous suffit de modifier la condition is_category().

Dans mon tax_query, j'ai défini include_children sur true, ce qui signifie que WP_Query obtiendra les publications de la catégorie actuelle et les publications appartenant aux catégories enfants de la catégorie affichée. C'est le comportement par défaut pour toutes les pages de termes hiérarchiques. Si vous avez vraiment besoin que des auteurs de la catégorie en cours de visualisation, définissez include_children sur false

RECHERCHER LES AUTEURS

Si vous faites un var_dump( $post_author_ids ), vous verrez que vous avez un tableau d'identifiants post-auteur. Maintenant, au lieu de parcourir en boucle chaque ID, vous pouvez simplement passer ce tableau d'identifiants à WP_User_Query , puis parcourir en boucle les résultats de cette requête.

$user_args = [
    'include' => $post_author_ids
];
$user_query = new \WP_User_Query( $user_args );
var_dump( $user_query->results ); // For debugging purposes

if ( $user_query->results ) {
    foreach ( $user_query->results as $user ) {
        echo $user->display_name;
    }
}

Nous pouvons aller encore plus loin et tout enregistrer dans un environnement transitoire, ce qui nous évitera seulement 2 requêtes de base de données dans =/- 0.002s.

Le transitoire

Pour définir un nom transitoire unique, nous allons utiliser le terme objet pour créer un nom unique.

if ( is_category() ) {
    $current_category = get_term( $GLOBALS['wp_the_query']->get_queried_object() );
    $transient_name = 'wpse231557_' . md5( json_encode( $current_category ) );

    // Check if transient is set
    if ( false === ( $user_query = get_transient( $transient_name ) ) ) {

        // Our code above

        // Set the transient for 3 days, adjust as needed
        set_transient( $transient_name, $user_query, 72 * HOUR_IN_SECONDS );
    }

    // Run your foreach loop to display users
}

RINÇAGE DU TRANSIENT

Nous pouvons vider le transitoire chaque fois qu'une nouvelle publication est publiée ou lorsqu'une publication est modifiée, supprimée, non supprimée, etc. Pour cela, nous pouvons utiliser le hook transition_post_status. Vous pouvez également l'ajuster pour qu'il ne se déclenche que lorsque certains événements se produisent, notamment lorsqu'un nouveau message est publié. Quoi qu'il en soit, voici le crochet qui va tirer quand il se passe quelque chose à la poste

add_action( 'transition_post_status', function () use ( &$wpdb )
{
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_wpse231557_%')" );
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_wpse231557_%')" );
});

TOUS ENSEMBLE MAINTENANT!!!

Dans un fichier de type fonctions

add_filter( 'posts_fields', function ( $fields, \WP_Query $q ) use ( &$wpdb )
{
    remove_filter( current_filter(), __FUNCTION__ );

    // Only target a query where the new wpse_post_author parameter is set to true
    if ( true === $q->get( 'wpse_post_author' ) ) {
        // Only get the post_author column
        $fields = "
            $wpdb->posts.post_author
        ";
    }

    return $fields;
}, 10, 2);

add_action( 'transition_post_status', function () use ( &$wpdb )
{
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_wpse231557_%')" );
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_wpse231557_%')" );
});

Dans votre widget

if ( is_category() ) {
    $current_category = get_term( $GLOBALS['wp_the_query']->get_queried_object() );
    $transient_name = 'wpse231557_' . md5( json_encode( $current_category ) );

    // Check if transient is set
    if ( false === ( $user_query = get_transient( $transient_name ) ) ) {

        $args = [
            'wpse_post_author'       => true, // To trigger our filter
            'posts_per_page'         => -1,
            'orderby'                => 'author',
            'order'                  => 'ASC',
            'suppress_filters'       => false, // Allow filters to alter query
            'cache_results'          => false, // Do not cache posts
            'update_post_meta_cache' => false, // Do not cache custom field data
            'update_post_term_cache' => false, // Do not cache post terms
            'tax_query'              => [
                [
                    'taxonomy'         => $current_category->taxonomy,
                    'terms'            => $current_category->term_id,
                    'include_children' => true
                ]
            ]
        ];
        $posts_array = get_posts( $args );

        $user_query = false;

        if ( $posts_array ) {
            // Get all the post authors from the posts
            $post_author_ids = wp_list_pluck( $posts_array, 'post_author' );

            // Get a unique array of ids
            $post_author_ids = array_unique( $post_author_ids );

            $user_args = [
                'include' => $post_author_ids
            ];
            $user_query = new \WP_User_Query( $user_args );
        }

        // Set the transient for 3 days, adjust as needed
        set_transient( $transient_name, $user_query, 72 * HOUR_IN_SECONDS );
   }

    if (    false !== $user_query
         && $user_query->results 
    ) {
        foreach ( $user_query->results as $user ) {
            echo $user->display_name;
        }
    }
}

MODIFIER

Tout le code est maintenant testé et fonctionne comme prévu

2
Pieter Goosen
<?php
if( is_category() ) {
  global $wp_query;
  $term_obj = $wp_query->get_queried_object();
  $author_array     = array();
  $args             = array(
      'posts_per_page'  => -1,
      'category'        => $term_obj->term_id,
      'orderby'         => 'author',
      'order'           => 'ASC'
  ); 

  // Get the posts in the array and create an array of the authors
  $cat_posts  = get_posts( $args );
  foreach ( $cat_posts as $cat_post ):
      if ( ! in_array( $cat_post->post_author, $author_array ) ) {
          $author_array[] = $cat_post->post_author;
      }
  endforeach;

  // Get the author information and build the output
  foreach ( $author_array as $author ):
      $auth      = get_userdata($author)->display_name;
      $auth_link = get_userdata($author)->user_login;
      printf( '<a href="/author/%s">%s</a><br />', $auth_link, $auth );
  endforeach;
}
?>

Expliquant le code ici:

  1. Vérification de la page d’archive des catégories par is_category () balise conditionnelle
  2. Assigne la variable globale global $ wp_query;
  3. Maintenant obtenir l’objet demandé par $ wp_query-> get_queried_object () function
  4. Création du tableau args. J'utilise l'ID de la catégorie ( $ term_obj-> term_id ) et non le nom de la catégorie.
  5. Récupération de tous les articles de la catégorie actuelle par get_posts () function
  6. Nous créons maintenant le tableau unique authors.
  7. Enfin afficher la liste des auteurs par printf () fonction.
0
Chinmoy Kumar Paul