I'm trying to dynamically hide posts across my entire site if the value of a custom field called distribution is "1".

I've set up a meta box on the post editor screen to set the value of the field, but, especially on older posts, the field will not always be set.

Note that I'm doing this in a plugin, so the easy way of directly editing loops and WP_queries in the theme isn't an option for me.

It seems like pre_get_posts or posts_where will do what I want.

function hide_custom_filter( $where = '') {
  global $wpdb;
  if (!is_single() && !is_admin()) {
    $where .= " AND (($wpdb->postmeta.distribution = '1')) ";
  return $where;
add_filter( 'posts_where', 'hide_custom_filter' );

The above code gives me an error: WordPress database error: [Unknown column 'wp_postmeta.distribution' in 'where clause'].

What's going on here?

  • 2
    Possible duplicate of Can I exclude a post by meta key using pre_get_posts function?
    – kero
    Aug 2 '17 at 12:57
  • The problem with your code is as the error says: there is no column(!) named distribution. It would need to be something like AND (pm.meta_key = 'distribution' AND pm.meta_value != '1') (pm for shortening my code here, use wpdb->.. instead). Still not sure if this SQL works. What if a post does not have this meta key? Anway, the linked answer should solve this
    – kero
    Aug 2 '17 at 12:59

This should do it, using pre_get_posts:

function wpse_275546_hide_distribution_post( $query ) {
    /* Don't filter posts in admin, or the current post when viewing a single post. */
    if ( ! is_admin() && ! ( $query->is_main_query() && is_single() ) ) {
         * Get current meta query if it exists, otherwise an empty array. 
         * This is to modifiy, so that we don't override any existing meta queries.
        $meta_query = $query->get( 'meta_query' ) ?: array();

        /* Add meta query to find posts that do not have distribitions set to 1. */
        $meta_query[] = array(
            'key'     => 'distribution',
            'value'   => '1',
            'compare' => '!=',

        /* Apply meta query. */
        $query->set( 'meta_query', $meta_query );
add_action( 'pre_get_posts', 'wpse_275546_hide_distribution_post' );

One thing I wasn't sure about was your use of is_single(). Do you still want to allow people to view the single post? If so, do you still want to hide it from any other possible loops, like widgets?

If you're ok showing the posts everywhere when viewing a single post, then you can remove the $query->is_main_query() && part. I added that to ensure that the main post appeared on single post views, but still kept them hidden from secondary posts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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