Show only posts which can be commented OR have custom meta field

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

Leave a Comment