5

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 Answer 1

3

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

6
  • I'm not sure why comment_status isn't avialable in WP_Query, so I created a ticket here to hopefully shine some light on that.
    – birgire
    Jan 25, 2016 at 16:44
  • @birgire it is quite strange as comment_status already is in the wp_posts table. I hope something like this gets accepted into core. Holding thumbs ;-) Jan 25, 2016 at 16:48
  • That was quick, committed to core in only few hours after the ticket was created, thanks to Boone Gorges.
    – birgire
    Jan 26, 2016 at 7:09
  • @birgire I've been following the trac ;-). See that implementation is set for 4.5. That was really quick. Congrats, that will save a lot of custom coding and extra filters Jan 26, 2016 at 7:11
  • 1
    You guys are amazing!! Pieter, thank you so much for your solution—works perfectly! @birgire Thanks for the ticket—this was lightning fast! Jan 26, 2016 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.