如何查询X个相关帖子的数量首先按标签征税,如果标签相关的帖子数量不够,则再按类别征税

时间:2016-03-03 作者:Andre Bulatov

问题

如何首先输出与标签相关的帖子,然后如果与标签相关的帖子少于4篇,请用与类别相关的帖子填充其余的4篇帖子?

场景

有时一篇文章只有很少的标签,或者它所标记的标签有很少的文章。当输出“标签相关帖子”时,该区域要么非常稀疏,只有1或2篇帖子,要么完全是空的。

为了解决这个问题,如果没有足够的标签相关帖子来满足需求,那么最好显示相关类别的帖子posts_per_page => X.

所以,像这样:

场景A——如果存在4个以上与标签相关的帖子,那么:

Related Posts:

Show the below posts:

1. tag-related post #1
2. tag-related post #2
3. tag-related post #3
4. tag-related post #4

Do Not show the below posts:

5. tag-related post #5
6. tag-related post #6
7. tag-related post #7
...
方案B——如果只有2个标签相关帖子,那么:

Related Posts:

Show the below posts:

1. tag-related post #1
2. tag-related post #2  
3. category-related post #1
4. category-related post #2

Do Not show the below posts:

5. category-related post #3
6. category-related post #4
7. category-related post #5
...
我尝试的税务查询:

// start of the tax_query arguments
$args = array( \'posts_per_page\'=>4, \'post__not_in\' => array($post->ID), \'tax_query\' => array( \'relation\' => \'OR\' ) );

// get current post tags
$tags = wp_get_object_terms( $post->ID, \'post_tag\', array( \'fields\' => \'ids\' ) );

if ( !empty( $tags ) ) {
    $args[\'tax_query\'][] = array(
        \'taxonomy\' => \'post_tag\',
        \'field\'    => \'id\',
        \'terms\'    => $tags
    );
}

// get current post categories
$categories = wp_get_object_terms( $post->ID, \'category\', array( \'fields\' => \'ids\' ) );

if ( !empty( $categories ) ) {
    $args[\'tax_query\'][] = array(
        \'taxonomy\' => \'category\',
        \'field\'    => \'id\',
        \'terms\'    => $categories
    );
}

// the query
$related_query = new WP_Query( $args );
据我所知,税务查询显示“获取相同类别的帖子,然后获取相同标签中的帖子,然后输出帖子,直到屏幕上出现4个。”

然而,它总是首先输出类别帖子(其中有很多),这符合屏幕上的4篇帖子规则,而忽略了最重要的标签相关帖子。我试着用AND 而不是OR, 这不管用,对我来说毫无意义。

我也看到过这些帖子:WordPress - producing a list of posts filtered by tag and then categoryWordpress query posts by tag and category, 但他们要输出一个按标签和类别过滤的帖子列表。我需要的职位首先相关的标签,如果4或更多,然后只输出那些前4名。如果少于4个,则输出尽可能多的类别相关职位,以满足4个职位的标准。

很明显,我误解了这个问题和/或疑问,因此如果有任何帮助,我将不胜感激。

解决方案

Peter\'s solution 很好用——谢谢你,彼得!

为了我自己的目的,我进一步构建了它,并使用您令人惊叹的注释代码,我还能够从这个查询中排除“最近的帖子”——呜呜!

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

您不能在一个查询中完成此操作,这对于什么来说有点太高级了WP_Query 可以在此时完成。我们需要在这里运行至少两个(我将使用3个)查询来实现您想要的

第一次查询

第一次查询将根据post_tag, 这也将排除当前职位。我们将只获取帖子ID

第二个查询

此查询将处理来自category 分类学要使此查询成功,我们需要以下内容

从第一次查询中排除当前帖子和帖子,以避免重复帖子

获取第一个查询中的帖子数量,从4中减去,然后使用该差异设置此查询应检索的帖子数量

我们还将在此处获取帖子ID

第三个查询

为了保持查询对象的完整性,我们将组合前一个查询中的所有ID,并查询最终的post对象。你可能认为这很贵,但事实并非如此。因为前两个查询使用get_posts() 而且只获得帖子ID,它们真的非常快。通过只查询ID,我们也不会更新缓存,这使得这些查询更快

解决方案

我更喜欢为代码这样的大块创建一个函数,因为它可以保持我的模板干净。请注意,以下内容未经测试,需要PHP 5.4

function get_max_related_posts( $taxonomy_1 = \'post_tag\', $taxonomy_2 = \'category\', $total_posts = 4 )
{
    // First, make sure we are on a single page, if not, bail
    if ( !is_single() )
        return false;

    // Sanitize and vaidate our incoming data
    if ( \'post_tag\' !== $taxonomy_1 ) {
        $taxonomy_1 = filter_var( $taxonomy_1, FILTER_SANITIZE_STRING );
        if ( !taxonomy_exists( $taxonomy_1 ) )
            return false;
    }

    if ( \'category\' !== $taxonomy_2 ) {
        $taxonomy_2 = filter_var( $taxonomy_2, FILTER_SANITIZE_STRING );
        if ( !taxonomy_exists( $taxonomy_2 ) )
            return false;
    }

    if ( 4 !== $total_posts ) {
        $total_posts = filter_var( $total_posts, FILTER_VALIDATE_INT );
            if ( !$total_posts )
                return false;
    }

    // Everything checks out and is sanitized, lets get the current post
    $current_post = sanitize_post( $GLOBALS[\'wp_the_query\']->get_queried_object() );

    // Lets get the first taxonomy\'s terms belonging to the post
    $terms_1 = get_the_terms( $current_post, $taxonomy_1 );

    // Set a varaible to hold the post count from first query
    $count = 0;
    // Set a variable to hold the results from query 1
    $q_1   = [];

    // Make sure we have terms
    if ( $terms_1 ) {
        // Lets get the term ID\'s
        $term_1_ids = wp_list_pluck( $terms_1, \'term_id\' );

        // Lets build the query to get related posts
        $args_1 = [
            \'post_type\'      => $current_post->post_type,
            \'post__not_in\'   => [$current_post->ID],
            \'posts_per_page\' => $total_posts,
            \'fields\'         => \'ids\',
            \'tax_query\'      => [
                [
                    \'taxonomy\'         => $taxonomy_1,
                    \'terms\'            => $term_1_ids,
                    \'include_children\' => false
                ]
            ],
        ];
        $q_1 = get_posts( $args_1 );
        // Count the total amount of posts
        $q_1_count = count( $q_1 );

        // Update our counter
        $count = $q_1_count;
    }

    // We will now run the second query if $count is less than $total_posts
    if ( $count < $total_posts ) {
        $terms_2 = get_the_terms( $current_post, $taxonomy_2 );
        // Make sure we have terms
        if ( $terms_2 ) {
            // Lets get the term ID\'s
            $term_2_ids = wp_list_pluck( $terms_2, \'term_id\' );

            // Calculate the amount of post to get
            $diff = $total_posts - $count;

            // Create an array of post ID\'s to exclude
            if ( $q_1 ) {
                $exclude = array_merge( [$current_post->ID], $q_1 );
            } else {
                $exclude = [$current_post->ID];
            }

            $args_2 = [
                \'post_type\'      => $current_post->post_type,
                \'post__not_in\'   => $exclude,
                \'posts_per_page\' => $diff,
                \'fields\'         => \'ids\',
                \'tax_query\'      => [
                    [
                        \'taxonomy\'         => $taxonomy_2,
                        \'terms\'            => $term_2_ids,
                        \'include_children\' => false
                    ]
                ],
            ];
            $q_2 = get_posts( $args_2 );

            if ( $q_2 ) {
                // Merge the two results into one array of ID\'s
                $q_1 = array_merge( $q_1, $q_2 );
            }
        }
    }

    // Make sure we have an array of ID\'s
    if ( !$q_1 )
        return false;

    // Run our last query, and output the results
    $final_args = [
        \'ignore_sticky_posts\' => 1,
        \'post_type\'           => $current_post->post_type,
        \'posts_per_page\'      => count( $q_1 ),
        \'post__in\'            => $q_1,
        \'order\'               => \'ASC\',
        \'orderby\'             => \'post__in\',
        \'suppress_filters\'    => true,
        \'no_found_rows\'       => true
    ];
    $final_query = new WP_Query( $final_args );

    return $final_query;
}
现在,您可以在单个模板中使用以下函数

$query = get_max_related_posts();
if ( $query ) {

    while ( $query->have_posts() ) {
        $query->the_post();

            echo get_the_title() . \'</br>\';

    }
    wp_reset_postdata();
}
少数注释默认值已设置为post_tag, category4 对于这三个参数,因此在调用函数时确实需要将任何值传递给函数

如果需要对分类法进行swop,或设置不同的分类法,或将每页的帖子设置为4以外的任何内容,只需按正确的顺序将它们传递给函数即可

$query = get_max_related_posts( \'tax_1\', \'tax_2\', 6 );