web-dev-qa-db-ja.com

カテゴリ内の投稿で著者を一覧表示する

私はWordPressサイトで閲覧されている現在のカテゴリの寄稿者を表示するためのカスタムウィジェットを作成しようとしています。次のPHPコードがあります。

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

サイトの作者を表示していますが、カテゴリごとに変わるわけではありません - 各セクションに同じ3人が表示されます。コードブロックの末尾にあるテストステートメントは期待通りに動作しています - ウィジェット内に表示されているカテゴリはURIカテゴリと一致しています。

作者配列を作成する際にどこで問題が発生したのですか?

1
Brian

これは非常に高価な操作になる可能性があり、ページの読み込み時間に深刻な影響を与える可能性があります。この段階では、あなたのコードはかなり高価です。この問題に取り組むためのより良い方法を見てみましょう。

私たちがする必要があるのはdbで費やす時間を最小にすることです、そしてこれをするために、私たちは必要な情報だけを得るでしょう、それはpostオブジェクトのpost_authorプロパティです。今のところ、post_authorを使用してdbからWP_Queryプロパティを取得するだけのネイティブな方法はありません。完全なオブジェクトまたは単にIDを取得することしかできません。振る舞い(と生成されたSQL)を変更するには、posts_fieldsフィールドを返すようにSQLクエリに命令することができるpost_authorフィルタを利用します。必要なものだけが取得されるので、時間内にデータベースに費やすことになります。

次に、パフォーマンスを向上させるために、投稿データや用語や投稿メタデータをキャッシュしないようにWP_Queryに指示します。メタデータやポストタームデータは必要ないので、WP_Queryにこれらのクエリを行わず、後で使用するためにキャッシュするように依頼するだけで済みます。これにより、このデータをデータベースに追加する時間を大幅に節約できます。キャッシュし、私たちはまたdbクエリを節約します。

これをすべてコードに入れてみましょう。(注:すべてのコードはテストされていないので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);

wpse_post_authorというカスタムトリガーがあります。そのカスタムトリガーにtrueの値を渡すたびに、フィルターが起動します。

get_posts() QUERY

デフォルトでは、get_posts()にフィルタが作用しないように、get_posts()suppress_filters=trueWP_Queryに渡します。したがって、フィルタを機能させるには、これをtrueに戻す必要があります。

もう1つ注意してください。現在のカテゴリを確実に取得するには、カテゴリIDに$GLOBALS['wp_the_query']->get_queried_object()$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
    }
}

ご覧のとおり、私はtax_queryを使用しましたが、これはその柔軟性のために個人的な好みであり、また、変更する必要なしに任意の用語ページでコードを再利用できます。この場合、is_category()条件を変更するだけで済みます。

私のtax_queryではinclude_childrentrueに設定しました。これはWP_Queryが現在のカテゴリからの投稿と、表示されているカテゴリの子カテゴリに属する​​投稿を取得することを意味します。これはすべての階層用語ページのデフォルトの動作です。表示されているカテゴリの著者が本当に必要なだけの場合は、include_childrenfalseに設定します。

著者への質問

あなたがvar_dump( $post_author_ids )をするならば、あなたはあなたがポスト作者のIDの配列を持っているのを見るでしょう。さて、すべてのIDをループするのではなく、このIDの配列を WP_User_Query に渡して、そのクエリの結果をループするだけです。

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

これをさらに進めて、すべてを一時的に保存することができます。その結果、=/ - 0.002秒で2 dbクエリしかできなくなります。

過渡期

一意の一時的な名前を設定するには、オブジェクトという用語を使用して一意の名前を作成します。

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
}

トランジェントを流す

新しい投稿が公開されたとき、または投稿が編集、削除、削除されていないときなどにトランジェントをフラッシュすることができます。これにはtransition_post_statusフックを使用できます。新しい投稿が公開されたときだけのように、特定のことが起きたときにのみ起動するように調整することもできます。とにかく、これはポストに何かが起こったときに起動するフックです。

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

今すぐすべての!!!

関数型ファイル内

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

あなたのウィジェットで

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

編集

すべてのコードはテスト済みであり、期待通りに動作する

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

ここでコードを説明する:

  1. is_category()コンディショナルタグでカテゴリアーカイブページをチェックする
  2. グローバル変数を代入するグローバル$ wp_query;
  3. クエリされたオブジェクトを$ wp_query-> get_queried_object()関数で取得するようになりました
  4. Args配列を作成します。カテゴリ名ではなくカテゴリID($ term_obj-> term_id)を使用しています。
  5. 現在のカテゴリの全投稿をget_posts()関数で取得する
  6. 今度はユニークなauthors配列を作成します。
  7. 最後にprintf()関数で著者リストを表示します。
0