I am trying to add a delisting feature to my WordPress network. Posts which are delisted would not appear in post lists, but would still be visible if accessed directly.

I've written a plugin that helps editors delist entries with custom meta values on authors and posts. So there are two meta values that I need to check before displaying each post in public listings: the delist-post post meta value and the delist-author user meta value.

I was hoping to register a pre_get_posts filter that limits the return of get_posts() by setting the query's meta_query property. Is it possible to check a user meta value with a posts meta_query? If not, can you think of a better way to do this without adding conditional statements in theme files (i.e. not if (!get_post_meta(...) && !get_user_meta(...)) in the_loop)?


3 Answers 3


If you're using WP_Query to do your loop it should be as simple as getting all the post IDs and then setting them as negative in the p parameter.

For example:

$unwanted_posts = array(); // you must generate this
$unwanted_posts_str = '-'.implode( ',-', $unwanted_posts );

$args = array(
    'p' => $unwanted_posts_str

You can also set this on an existing query using the set() method.

  • The list could be thousands of IDs long. (Edited to remove first sentence ;) May 22, 2012 at 18:43

Shortly after writing my question, The Theme Foundry wrote a blog entry that answered my question. The solution is to add_actions for both posts_join and posts_where. These each take clauses as arguments, which you append with your own conditions and return the appended clause.

In my case, I just had to limit the join in the posts_join callback:

$join .= " 
            LEFT JOIN    " . $wpdb->postmeta . " AS pm 
            ON           (" . $wpdb->posts . ".ID = pm.post_id AND 
                        pm.meta_key = 'post_meta_key_here') 
            LEFT JOIN    " . $wpdb->usermeta . " AS um 
            ON           (" . $wpdb->posts . ".post_author = um.user_id AND 
                        um.meta_key = 'author_meta_key_here') "

... and the where clause in the posts_where callback...

$where .= " 
                AND ((pm.meta_key = 'post_meta_key_here' AND pm.meta_value = 0)
                    OR pm.meta_id IS NULL) 
                AND ((um.meta_key = 'author_meta_key_here' AND um.meta_value = 0)
                    OR um.umeta_id IS NULL) ";

Please see the blog post for more information.


I would use pre_get_posts:

function wpse52961_filter_delisted_posts( $query ) {
    // Only modify the main query
    // NOTE: You'll need to change this if
    // you intend to target a specific secondary query
    if ( $query->is_main_query() ) {
        // Define meta query
        $filtered_posts_meta_query = array(
            'relation' => 'OR',
                'meta_key' => 'delist-post',
                'meta_value' => true
                'meta_key' => 'delist-author',
                'meta_value' => true

        // Add the meta query args to the query
        $query->set( 'meta_query', $filtered_posts_meta_query );
add_action( 'pre_get_posts', 'wpse52961_filter_delisted_posts' );

I've made some assumptions about the meta key values, and the desired relationship between delist-post and delist-author.

  • The meta entries must exist or the post will be omitted. In a future version of WordPress, we will have an "exists/does not exist" criteria (core.trac.wordpress.org/ticket/18158). Also, delist-author must be attached to the user meta table, not posts meta, otherwise other posts by that author won't be delisted. May 24, 2012 at 17:06

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.