如何在Pre_Get_Posts过滤器中获取帖子ID?

时间:2016-08-09 作者:Maikal

我正在尝试这样做:在主页(首页)上,我有多个帖子循环。我需要帖子不要在这些循环中重复(也就是说,如果帖子显示在第一个循环中,它就永远不会出现在第二个或第三个循环中,以此类推)。

I\'v想出了这些(较低),但我的解决方案要求我对每个循环执行2次查询(因此,如果我有3个循环,我将执行6个db请求),这有点糟糕。

所以我的问题是:我能在里面得到帖子ID吗pre_get_posts 滤器

迄今为止我的代码:

/** Hack to exclude repeating of posts */
if( ! function_exists( \'jews_exclude_shown_posts\' ) ) {
    function jews_exclude_shown_posts( $query ) {
        if( is_admin() ) return $query;

        if( $query->is_main_query() ) {
            $GLOBALS[\'jews_exclude\'] = array();
        } elseif (
            false !== $query->query_vars[\'jews_exclude\'] &&
            (
                null === $query->query_vars[\'post_type\']
                || ( is_array( $query->query_vars[\'post_type\'] ) && in_array( \'post\', $query->query_vars[\'post_type\'] ) )
                || \'post\' === $query->query_vars[\'post_type\']
            )
        ) {
            if( ! empty( $GLOBALS[\'jews_exclude\'] ) ) {
                $query->set(\'post__not_in\', $GLOBALS[\'jews_exclude\']);
            }
            $args = $query->query;
            $args[\'jews_exclude\'] = false;
            $execute = new WP_query( $args );//here i do dubble query witch i dont\'t want to do
            if( $execute->have_posts() ) {
                foreach( $execute->posts as $ex )
                    $GLOBALS[\'jews_exclude\'][ $ex->ID ] = $ex->ID;
            }
        }
        return $query;
    }
}
add_filter( \'pre_get_posts\', \'jews_exclude_shown_posts\' );

1 个回复
SO网友:birgire

我们可以尝试使用the_posts 如果suppress_filters 查询变量为false,用于收集相关帖子ID。

然后我们可以使用pre_get_posts 钩子,在每个查询中排除accumulated post ID数组。

以下是流程的模式示例:

// Main query
$wp_query = new WP_Query( $args );
$wp_query->posts filtered and collected post IDs [1,2] from the \'post\' post type

// Sub query #1
$q1 = new WP_Query( [ \'wpse_exclude\' => true, ... ] );
pre_get_posts excludes accumulated [1,2]
$q1->posts filtered and collected [3,4] 

// Sub query #2
$q2 = new WP_Query( [ \'wpse_exclude\' => true, ... ] );
pre_get_posts excludes accumulated [1,2,3,4]
$q2->posts filtered and collected  [5,6]

// Sub query #3
$q3 = new WP_Query( $args );
No exclusion because \'wpse_exclude\' argument is missing
$q3->posts filtered and collected [7]

// Sub query #4
$q4 = new WP_Query( [ \'wpse_exclude\' => true, ... ] );
pre_get_posts excludes accumulated [1,2,3,4,5,6,7]
$q4->posts filtered and collected [8,9]
下面是演示类的可能构建块,可以帮助实现这一点:

这个init() 方法:

public function init( $collect_post_type = \'post\' )
{
    // Collect post IDs
    add_filter( \'the_posts\', [ $this, \'the_posts\' ] );

    // Exclude accumulated post IDs in queries
    add_action( \'pre_get_posts\', [ $this, \'pre_get_posts\' ] );

    // Initialize accumulated post IDs for exclusion
    $this->exclude_pids = [];

    // Collect post IDs only from this post type
    $this->collect_post_type = $collect_post_type;
}
Thepre_get_posts() 方法:

public function pre_get_posts( \\WP_Query $q )
{
    if( 
        $q->is_home()                 // Target the home page
        && $q->get( \'wpse_exclude\' )  // Target queries with wpse_exclude set as true
     // && ... etc
    ) {     
        // Exclude accumulated set of post IDs
        if( ! empty( $this->exclude_pids ) )
            $q->set( \'post__not_in\', $this->exclude_pids );
    }
}
在这里,我们还应该考虑保留以前的post__not_in 参数。

这个the_posts() 方法:

public function the_posts( array $posts )
{
    // Collect post IDs from \'post\' post type and merge to the $pids array
    $this->exclude_pids = array_merge( 
        $this->exclude_pids , 
        (array) wp_filter_object_list( 
            $posts,
            [ \'post_type\' => $this->collect_post_type ], 
            \'AND\', 
            \'ID\' 
        )  
    );

    return $posts;
}
希望您可以根据自己的需要进行调整。

相关推荐

GET_POSTS查询大约需要40秒来执行

我在get\\u帖子中有一个元查询,它需要花很长时间才能完成。它工作得很好,但只是时间太长了。我有一个名为event. 在每个event 发布后,有自定义元数据:post\\U sort\\U日期(事件日期YmdHis 格式,用于排序)我需要做的是获取下一个事件,该事件相对于$year 和$month 变量。所以如果$year = 2021 和$month = 10 (2021 10月)然后应该在2021 11月或之后找到第一个事件。我下面的查询很好,但很慢。执行大约需要40秒,我不知道为什么。$next