WordPress VIP and other development guides I've seen recommend avoiding the use of post__not_in for performance reasons when using WordPress at scale. Their suggestion is to filter out the posts in php:
$posts_to_exclude = [ 67, 68, 69 ];
$query = new WP_Query( [
'post_type' => 'post',
'posts_per_page' => 5 + count( $posts_to_exclude ),
'paged' => get_query_var( 'paged' ),
] );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post();
if ( in_array( get_the_ID(), $posts_to_exclude, true ) ) {
continue;
}
the_title();
endwhile;
endif;
My question is how do you show the correct number of posts per page when filtering out the posts via php? The example above adds the count of the excluded posts to the posts_per_page variable. However this would result in there being between 5 – 8 posts per page depending on how many posts are excluded for a particular page. Is there a workable solution for making the number of posts per page consistent or is this optimisation only really meant for posts that aren't going to be paginated?
WordPress VIP and other development guides I've seen recommend avoiding the use of post__not_in for performance reasons when using WordPress at scale. Their suggestion is to filter out the posts in php:
$posts_to_exclude = [ 67, 68, 69 ];
$query = new WP_Query( [
'post_type' => 'post',
'posts_per_page' => 5 + count( $posts_to_exclude ),
'paged' => get_query_var( 'paged' ),
] );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post();
if ( in_array( get_the_ID(), $posts_to_exclude, true ) ) {
continue;
}
the_title();
endwhile;
endif;
My question is how do you show the correct number of posts per page when filtering out the posts via php? The example above adds the count of the excluded posts to the posts_per_page variable. However this would result in there being between 5 – 8 posts per page depending on how many posts are excluded for a particular page. Is there a workable solution for making the number of posts per page consistent or is this optimisation only really meant for posts that aren't going to be paginated?
$limit = 5;
if ( $query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post();
if ( in_array( get_the_ID(), $posts_to_exclude, true ) && $limit > 0 ) {
continue;
}
$limit--;
the_title();
endwhile;
endif;
If You want to keep posts
limit and avoid parameter post_not_in
You should add these code to filter posts
in $query
.
//get posts from query object
$posts = $query->posts;
//set limit of posts that You need on page
$limit = 5;
//filter by ID that You want to exclude
$posts = array_filter($posts, function( $data ){
if( ! in_array( $data->ID, $posts_to_exclude ) )return true;
});
$posts = array_slice($posts, 0, $limit);
//put filtered posts in query object
$query->posts = $posts;
//here You can do Your loop
The truth here is: while you surely can remove the posts you do not want to have in your loop or after querying, you can not do so without messing up the pagination. If you want a correct loop and pagination, you won't be able to get around post__not_in. However, if your query is not that complicated (like multiple meta queries additional to the post__not_in), the performance won't be that affected. Sure, "NOT IN" statements are not that great, but they won't bring your websites performance that much down.
So, as long as you don't already have to fight slow response times, you probably can use this one post__not_in ;)