我读过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: 想法是可以的,但代码不起作用。
最合适的回答,由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
, taxonomy
和included_terms
(需要是整数或术语ID数组)参数,否则函数返回null
. 另一个允许的参数(不是必需的,可以省略)是excluded_terms
它也是一个整数或一个术语ID数组,是POST不应包含的术语。上述内容将返回以下内容(即以下内容)5
从分类术语发布ID3
从分类法category
, 但是任期内的职位3
和9
不应退回5
从分类术语发布ID4
从分类法category
, 但是任期内的职位4
和9
不应退回函数返回的数组(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_posts
到post__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 );
}
}
}
});