列出某个类别中包含帖子的作者

时间:2016-07-06 作者:Brian

我正在尝试创建一个自定义小部件,以显示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
}
?>
它显示的是来自网站的作者,但他们并没有从一个类别切换到另一个类别——每个部分都显示相同的三个作者。代码块末尾的测试语句按预期工作-小部件中显示的类别与URI类别匹配。

有没有想过我在创建作者数组时哪里出错了?

2 个回复
最合适的回答,由SO网友:Pieter Goosen 整理而成

这可能会成为一个非常昂贵的操作,严重影响页面加载时间。在这个阶段,您的代码非常昂贵。让我们看看更好的方法来解决这个问题。

我们需要做的是尽量减少在db中花费的时间,要做到这一点,我们只会得到我们需要的信息,即post_author post对象的属性。正如我们现在所看到的,没有任何本地方法可以post_author 来自数据库的属性WP_Query, 我们只可能得到完整的对象或只是帖子ID\'s、 要更改行为(和生成的SQL),我们将使用posts_fields 我们可以命令SQL查询只返回post_author 字段,这将节省我们在db中花费的大量时间,因为我们只得到我们需要的。

其次,为了提高性能,我们将告诉WP_Query 不缓存任何post数据或post术语和post元数据。由于我们不需要任何元数据或后期数据,我们可以简单地询问WP_Query 为了不查询这些数据并将其缓存以供以后使用,这也节省了我们在db上花费的大量额外时间,以及在缓存中添加这些数据的时间,我们还将节省db查询的时间。

让我们把这些全部放在代码中:(NOTE: 所有代码都未经测试,需要PHP 5.4+)

posts_fields 过滤器

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() 默认情况下,查询,get_posts() 通行证suppress_filters=trueWP_Query 以避免过滤器作用于get_posts(), 所以为了让我们的过滤器工作,我们需要将其设置回true。

另一个注意事项是,要可靠地获取当前类别,请使用$GLOBALS[\'wp_the_query\']->get_queried_object()$GLOBALS[\'wp_the_query\']->get_queried_object_id() 对于类别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数组传递给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.002s中只得到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
}

FLUSHING THE TRANSIENT

我们可以在发布新帖子或编辑、删除、取消删除帖子等时刷新瞬态。为此,我们可以使用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;
        }
    }
}
编辑所有代码现在都已测试并按预期工作

SO网友:Chinmoy Kumar Paul

<?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;
}
?>
此处解释代码:

检查类别存档页is_category() 条件标记分配全局变量global $wp_query;现在通过以下方式获取查询的对象$wp_query->get_queried_object() 函数创建args数组。我正在使用类别ID($term_obj->term_id) 不是类别名称获取当前类别的所有帖子get_posts() 函数现在创建唯一作者数组printf() 功能