排除主循环中特定类别的前5个帖子

时间:2015-05-06 作者:okiedokey

我读过this article 关于如何为循环中的一个特定类别设置偏移。我想知道这是否适用于不止一个类别。

我对上面链接的文章中建议的代码的问题是,我使用一个小部件来显示我可以在小部件选项中按ID设置的类别中的五篇文章post_ID其中的个帖子已经循环通过了。

Situation:

我在我的博客页面上使用自定义小部件来显示两个指定类别中的5篇最新文章——让我们称它们为categoryA和categoryB。

回答@Pieter Goosen在评论中提出的问题:是的,我可以通过在小部件设置中手动输入ID来指定类别,并将其保存在DB中。

在这些小部件下面,博客页面循环浏览我的所有帖子并显示它们。

Effect:

博客页面上的主循环(小部件下面的循环)再次显示categoryA和categoryB中的帖子。它们看起来是双重的,因为上面的小部件已经循环了类别A和B。

Question:

是否可以将前五个帖子从主循环的categoryA和categoryB中排除?可以用pre_get_posts? 使用get_query_var? 怎样

EDIT

My own approaches

FIRST TRY

我修改了我的小部件代码,如下所示:

global $do_not_duplicate;
while($featured_posts->have_posts()): $featured_posts->the_post(); 
    $do_not_duplicate[] = get_the_ID();
因为我的小部件正在我的functions.php 文件中,我添加了以下行:

global $do_not_duplicate;
$do_not_duplicate = array();
include(\'widgets/widgets.php\');
最后在index.php, 我将这一行添加到主循环中:

if(have_posts()) :
    global $do_not_duplicate;
    while(have_posts()): the_post();
        if( in_array( $post->ID, $do_not_duplicate ) ) continue;
        get_template_part(\'content\');
    endwhile;
endif;
Please note: 这基本上是可行的,但并不完全从主查询中删除帖子,而是跳过它们。这意味着默认值posts_per_page 设置将无法完成,Jetpack无限滚动无法使用。此外,使用globals也不是一种好方法。

SECOND TRY

我采纳了@birgire的建议,并对其进行了一些修改。我考虑将建议的pre\\u get\\u posts过滤器与用于小部件使用的类别的foreach循环结合使用,以便收集它们查询的帖子的ID。以下是我的片段:

add_action(\'pre_get_posts\', \'modified_mainloop\', 10);
function modified_mainloop($query) {
    if(!is_admin() && $query->is_home() && $query->is_main_query()) {
        $cats_to_exclude = get_categories(\'include=3,4,9\');
        foreach($cats_to_exclude as $category) {
            if($category->term_id == \'9\') {
                $num_posts_to_exclude = 3;
            } else {
                $num_posts_to_exclude = 5;
            }
            $posts_to_exclude = get_posts(array(
                \'posts_per_page\' => $num_posts_to_exclude,
                \'category__in\'   => array($category->term_id),
                \'fields\'         => \'ids\'
            ));

        }
        $query->set(\'post__not_in\', (array) $posts_to_exclude);

    }
}
Please note: 想法是可以的,但代码不起作用。

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

这里有一个概念,您可以尝试从类别3和类别5中排除每个类别的5篇文章,其中属于类别9的文章被排除在外and 上述任一类别。

功能如下:(CAVEAT: 需要PHP 5.4以上版本,因为我使用了新的短数组语法。根据需要进行更改

/**
 * function get_sticky_category_posts()
 *
 * Get an array of post ids according to arguments given.
 *
 * @author Pieter Goosen
 * @see https://wordpress.stackexchange.com/q/187477/31545
 *
 * @param array $args
 */
function get_sticky_category_posts( $args = [] )
{
    /*
     * If the array is empty or not valid, return null
     */
    if ( empty( $args ) || !is_array( $args ) )
        return null;

    $ids = \'\';

    foreach ( $args as $k=>$v ) {

        /*
         * Check that $v[\'taxonomy\'], $v[\'included_terms\'] and $v[\'posts_per_page\'] are all set. If not, return null
         */ 
        if (    !isset( $v[\'taxonomy\'] ) 
             || !isset( $v[\'included_terms\'] )
             || !isset( $v[\'posts_per_page\'] )
        )
        return null;

        /*
         * Sanitize and validate user input
         */
        $included_terms = filter_var( $v[\'included_terms\'], FILTER_VALIDATE_INT, [\'flags\'  => FILTER_FORCE_ARRAY] );
        $taxonomy       = filter_var( $v[\'taxonomy\'], FILTER_SANITIZE_STRING );

        /*
         * Create tax_query according to whether $v[\'excluded_terms\'] is set
         */
        if ( !isset( $v[\'excluded_terms\'] ) ) {
            $tax_query = [
                [
                    \'taxonomy\'         => $taxonomy,
                    \'terms\'            => $included_terms,
                    \'include_children\' => false,
                ],
            ];
        } else {
            $tax_query = [
                [
                    \'taxonomy\'         => $taxonomy,
                    \'terms\'            => $included_terms,
                    \'include_children\' => false,
                ],
                [
                    \'taxonomy\'         => $taxonomy,
                    \'terms\'            => filter_var( $v[\'excluded_terms\'], FILTER_VALIDATE_INT, [\'flags\'  => FILTER_FORCE_ARRAY] ),
                    \'include_children\' => false,
                    \'operator\'         => \'NOT IN\'
                ],
            ];
        } // endif ( !$v[\'excluded_term\'] ) statement

        /*
         * Use get_posts to get an array of post ids to exclude
         */
        $posts_to_exclude = get_posts(
            [
                \'posts_per_page\' => filter_var( $v[\'posts_per_page\'], FILTER_VALIDATE_INT ),
                \'fields\'         => \'ids\',
                \'tax_query\'      => $tax_query
            ]
        );
        if ( $posts_to_exclude ) {

            /*
             * Concatenate all ids into a string using implode
             */
            $ids .= implode( \' \', $posts_to_exclude );
            $ids .= \' \';
        } //endif ( $posts_to_exclude )

    } //end foreach

    /*
     * If we don\'t have any ids, thus empty string, return null
     */
    if ( !$ids )
        return null;

    /*
     * Create a single flat array of post ids. Use rtrim to remove trailing white space
     */
    return explode( \' \', rtrim( $ids ) );
}
她的工作原理是:

  • 您需要以以下格式将多维数组传递给函数的参数

    $args = [
        0 => [\'posts_per_page\' => 5, \'taxonomy\' => \'category\', \'included_terms\' => 3, \'excluded_terms\' => 9],
        1 => [\'posts_per_page\' => 5, \'taxonomy\' => \'category\', \'included_terms\' => 4, \'excluded_terms\' => 9],
    ];
    $a = get_sticky_category_posts( $args );
    
    有四个允许的参数,其中have to set 这个posts_per_page, taxonomyincluded_terms需要是整数或术语ID数组)参数,否则函数返回null. 另一个允许的参数(不是必需的,可以省略)是excluded_terms 它也是一个整数或一个术语ID数组,是POST不应包含的术语。上述内容将返回以下内容(即以下内容)

    • 5 从分类术语发布ID3 从分类法category, 但是任期内的职位39 不应退回

    • 5 从分类术语发布ID4 从分类法category, 但是任期内的职位49 不应退回

      函数返回的数组(var_dump( $a )) 看起来像这样

      array(10) {
        [0]=>
        string(3) "159"
        [1]=>
        string(3) "149"
        [2]=>
        string(3) "129"
        [3]=>
        string(3) "126"
        [4]=>
        string(3) "119"
        [5]=>
        string(2) "76"
        [6]=>
        string(3) "528"
        [7]=>
        string(3) "394"
        [8]=>
        string(3) "147"
        [9]=>
        string(2) "97"
      }
      
      此数组现在可以传递给pre_get_postspost__not_in 参数从函数中排除帖子。您还可以在任何其他位置使用此ID数组,也可以将其返回到自定义查询或其他用途,如在除中使用的主页之外的其他页面上的粘贴帖子this answer :-)

      下面是一个用例pre_get_posts. 这将从主查询中删除所需的帖子。(由于函数中的语法和闭包的使用,需要使用PHP 5.4+(闭包可以使用PHP 5.3+)

      add_action( \'pre_get_posts\', function ( $q )
      {
          if (    !is_admin() // Not necessary for home page, included it to be used on any other template like category pages
               && $q->is_main_query() // Make sure this is the main query
               && $q->is_home() // Targets the home page only
          ) {
              if ( function_exists( \'get_sticky_category_posts\' ) ) {
      
                  $args = [
                      0 => [\'posts_per_page\' => 5, \'taxonomy\' => \'category\', \'included_terms\' => 3, \'excluded_terms\' => 9],
                      1 => [\'posts_per_page\' => 5, \'taxonomy\' => \'category\', \'included_terms\' => 4, \'excluded_terms\' => 9],
                  ];
                  $sticky_cat_posts = get_sticky_category_posts( $args );
      
                  if ( !empty( $sticky_cat_posts ) ) {
                      $q->set( \'post__not_in\', $sticky_cat_posts );
                  }   
              }
          }
      }); 
      

SO网友:birgire

你可以试试这种pre_get_posts 吊钩进近(未测试):

add_action( \'pre_get_posts\', function( $q )
{
    $exclude_cats = [ 12, 34 ]; // <-- Edit these category ids!

    if(    ! is_admin() 
        && $q->is_main_query()
        && ! is_singular()
        && ! is_category( $exclude_cats ) 
    )
    {
        $exclude_post_ids = get_posts( 
            [
                \'fields\'         => \'ids\',
                \'posts_per_page\' => 5,
                \'category__in\'   => $exclude_cats,
            ]
        );
        $q->set( \'post__not_in\', (array) $exclude_post_ids ); 
    }
} );
您可能需要进一步根据自己的需要进行调整。

您可能还想使用类别段塞,但您必须设置一个适当的tax_query, 自从category__in 仅支持类别ID数组。

结束

相关推荐

Loop for sticky posts

我用过Justin Tadlock\'s 关于如何创建仅包含粘性帖子的循环的教程。代码大致如下所示:$sticky = get_option( \'sticky_posts\' ); rsort( $sticky ); $sticky = array_slice( $sticky, 0, 2 ); query_posts( array( \'post__in\' => $sticky, \'caller_get_posts\' => 1 ) ); 根据教程,我