I’d like to exclude posts on the homepage which are closed for comments. This works thanks to this: Show only posts which can be commented
Now I’d like to add the possibility for exceptions – to show certain posts for which the comments are closed nevertheless. They are marked with a custom field “show_always”.
I tried:
function wpjj_filter_sticky( $query ) {
$meta_query = array(
'relation' => 'OR',
array(
'key' => 'show_aways',
'value' => 'yes',
'compare' => 'EXISTS'
),
array (
'comment_status' => 'open'
)
);
$query->set( 'meta_query', $meta_query );
}
add_filter( 'pre_get_posts', 'wpjj_filter_sticky' );
But it will only show the posts with the meta, not the open posts.
1
Lets try the following:
By default, all posts are returned regardless of comment_status
, so lets run the main query as normal, that is, query all posts regardless of comment_status
.
We will also run a small, but very lean secondary query where we will get all posts which have
-
a
comment_status
of closed -
which have a meta value of not
yes
The returned ID’s will then be passed as post__not_in
to the main query to exclude these posts
I think this is a better approach because handling SQL which involves meta queries yourself can get really messy, specially when you start adding complicated nested meta queries. Let WP_Query
handle the meta_query
part for us.
We will still use the comment_status
parameter which is supported by the custom filter by @TheDeadMedic in your linked question
add_action( 'pre_get_posts', function ( $q )
{
if ( $q->is_home()
&& $q->is_main_query()
) {
// Run our secondary query to get the posts to exclude
$args = [
'posts_per_page' => -1,
'comment_status' => 'closed',
'meta_query' => [
'relation' => 'OR',
[ // Compensate for posts which have the custom field set but not set to yes
'key' => 'show_always',
'value' => 'yes',
'compare' => 'NOT IN' // Get posts which value is not yes
],
[ // Compensate for posts which does not have the custom fields
'key' => 'show_always',
'compare' => 'NOT EXISTS' // Get posts which value is not yes
]
],
'fields' => 'ids', // Return only post ID's
'suppress_filters' => false, // Allow the comment_status filter
// Any other parameters
];
$exclude_ids = get_posts( $args );
// Now we can exclude the ID's we just queried
$q->set( 'post__not_in', $exclude_ids );
}
});
EDIT
The above code is now tested and working as expected
EDIT from comments
@birgire has filed a new trac ticket (trac ticket #35601) to enquire why comment_status
is not available in WP_Query
by default. Lets hope that we will see this incorporated into core in the near future. As soon as that happens, the custom filter will not be needed anymore