wake-up-neo.net

Listen Sie Autoren mit Beiträgen in einer Kategorie auf

Ich versuche, ein benutzerdefiniertes Widget zu erstellen, um beitragende Autoren für die aktuelle Kategorie anzuzeigen, die auf einer WordPress-Site angezeigt wird. Ich habe den folgenden PHP Code:

<?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
}
?>

Es werden Autoren der Website angezeigt, die sich jedoch nicht von Kategorie zu Kategorie ändern. In jedem Abschnitt werden die gleichen drei angezeigt. Die Testanweisung am Ende des Codeblocks funktioniert wie erwartet - die im Widget angezeigte Kategorie entspricht der URI-Kategorie.

Irgendwelche Gedanken darüber, wo ich beim Erstellen des Autorenarrays einen Fehler gemacht habe?

1
Brian

Dies kann zu einer ziemlich kostspieligen Operation werden, die die Ladezeit der Seite ernsthaft beeinträchtigen kann. In diesem Stadium ist Ihr Code ziemlich teuer. Schauen wir uns einen besseren Weg an, um dieses Problem anzugehen.

Was wir tun müssen, ist, den Zeitaufwand in db zu minimieren. Um dies zu tun, erhalten wir nur die Informationen, die wir benötigen, dh die Eigenschaft post_author des Post-Objekts. Da es derzeit keine systemeigene Möglichkeit gibt, die Eigenschaft post_author mit WP_Query aus der Datenbank abzurufen, haben wir nur die Möglichkeit, das vollständige Objekt oder nur die Post-Eigenschaft ID abzurufen. Um das Verhalten ( und das generierte SQL ) zu ändern, verwenden wir den Filter posts_fields, in dem wir der SQL-Abfrage befehlen können, nur das Feld post_author zurückzugeben, wodurch wir eine Menge Zeit sparen die db bekommen wir da nur was wir brauchen.

Um die Leistung zu verbessern, teilen wir WP_Query zweitens mit, dass keine Post-Daten oder Post-Term- und Post-Meta-Daten zwischengespeichert werden sollen. Da wir keine Metadaten oder Post-Term-Daten benötigen, können wir einfach WP_Query bitten, diese nicht abzufragen und für die spätere Verwendung zwischenzuspeichern. Dies spart uns außerdem viel zusätzliche Zeit in db, Zeit zum Hinzufügen dieser Daten Cache, und wir werden auch auf DB-Abfragen speichern.

Geben Sie dies alles in den Code ein: ( HINWEIS: Der gesamte Code ist ungetestet und erfordert PHP 5.4+ )

posts_fields FILTER

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);

Sie werden feststellen, dass wir einen benutzerdefinierten Auslöser namens wpse_post_author haben. Immer wenn wir diesem benutzerdefinierten Trigger den Wert true übergeben, wird unser Filter ausgelöst.

get_posts() QUERY

Standardmäßig übergibt get_posts()suppress_filters=true an WP_Query, um zu verhindern, dass Filter auf get_posts() einwirken. Damit unser Filter funktioniert, müssen wir ihn auf true zurücksetzen.

Nur ein weiterer Hinweis: Um die aktuelle Kategorie zuverlässig abzurufen, verwenden Sie für die Kategorie-ID $GLOBALS['wp_the_query']->get_queried_object() und $GLOBALS['wp_the_query']->get_queried_object_id()

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
    }
}

Wie Sie sehen, habe ich einen tax_query verwendet. Dies ist aufgrund seiner Flexibilität eine persönliche Präferenz. Außerdem können Sie den Code auf jeder Termseite wiederverwenden, ohne ihn ändern zu müssen. In diesem Fall müssen Sie nur die Bedingung is_category() ändern.

In meinem tax_query habe ich include_children auf true gesetzt, was bedeutet, dass WP_Query Beiträge aus der aktuellen Kategorie und den Beiträgen erhält, die zu den untergeordneten Kategorien der angezeigten Kategorie gehören. Dies ist das Standardverhalten für alle hierarchischen Term-Seiten. Wenn Sie wirklich nur Autoren aus der angezeigten Kategorie benötigen, setzen Sie include_children auf false.

Befragung der Autoren

Wenn Sie eine var_dump( $post_author_ids ) ausführen, werden Sie feststellen, dass Sie eine Reihe von Autoren-IDs für Posts haben. Anstatt jede einzelne ID zu durchlaufen, können Sie dieses Array von IDs einfach an WP_User_Query übergeben und anschließend die Ergebnisse dieser Abfrage durchlaufen.

$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;
    }
}

Wir können dies noch weiter gehen und alles in einem Übergang speichern, wodurch wir nur 2-dB-Abfragen in =/- 0,002s erhalten.

DER VORÜBERGEHENDE

Um einen eindeutigen vorübergehenden Namen festzulegen, verwenden wir den Begriff Objekt, um einen eindeutigen Namen zu erstellen

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
}

FLUSHING THE TRANSIENT

Wir können den Transienten löschen, wenn ein neuer Beitrag veröffentlicht wird oder wenn ein Beitrag bearbeitet, gelöscht, nicht gelöscht usw. wird. Dazu können wir den Hook transition_post_status verwenden. Sie können es auch so einstellen, dass es nur bei bestimmten Ereignissen ausgelöst wird, beispielsweise wenn ein neuer Beitrag veröffentlicht wird. Sowieso ist hier der Haken, der abfeuert, wenn dem Pfosten etwas passiert

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_%')" );
});

JETZT ALLE ZUSAMMEN!!!

In einer Funktionstypdatei

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_%')" );
});

In Ihrem 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;
        }
    }
}

BEARBEITEN

Der gesamte Code ist jetzt getestet und funktioniert wie erwartet

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;
}
?>

Erklären Sie den Code hier:

  1. Überprüfen der Kategoriearchivseite mit is_category () conditional tag
  2. Globale Variable zuweisen global $ wp_query;
  3. Holen Sie sich jetzt das abgefragte Objekt mit $ wp_query-> get_queried_object () function
  4. Das Array args erstellen. Ich verwende die Kategorie-ID ( $ term_obj-> term_id ) und nicht den Kategorienamen.
  5. Abrufen aller Posts der aktuellen Kategorie mit der Funktion get_posts ()
  6. Erstellen Sie nun das Array mit den eindeutigen Autoren.
  7. Zuletzt wird die Autorenliste mit der Funktion printf () angezeigt.
0