edit: Think I managed to figure it out, check the answer right under here, or click the following link: https://wordpress.stackexchange.com/a/51175/15809

I've been trying to find a way to exclude posts with 2 meta keys + values, but also keep the posts without the metas at all.

I looked into parse query request and have this in my functions.php:

function filter_out_efter15_posts( $request ) {
    $dummy_query = new WP_Query();
    $dummy_query->parse_query( $request );

    if ( $dummy_query->is_home() || $dummy_query->is_category('notiser') ) {
        $request['meta_query'][0]['key'] = 'efter15';
        $request['meta_query'][0]['value'] = 'Nej';
        $request['meta_query'][0]['compare'] = '=';
        $request['meta_query'][0]['type'] = 'CHAR';

        $request['meta_query'][1]['key'] = 'show_on_front_page';
        $request['meta_query'][1]['value'] = 'Ja';
        $request['meta_query'][1]['compare'] = '=';
        $request['meta_query'][1]['type'] = 'CHAR';

        return $request;
    else {
        return $request;

As you can see above, queries on the front page/home and on the category notiser (only category with posts that have these metas) filters out any posts with the meta key efter15 with the value Nej, and meta key show_on_front_page with the value Ja.

However, when I go to a tag page, the above function will not alter anything, and thus all posts with that tag will show up. I still want the posts with the metas filtered out.

I could add $dummy_query->is_tag(), but then it would filter out all the other posts that does not have the metas. Obviously I cannot set specific tags, like with the category.

Hopefully you'll understand what I'm trying to do. Is there a clean and good way to deal with this? I'd like to keep the number of queries to a minimum, and there are 20k+ posts in the database so I don't know about running all of them into post__not_in, read it might slow things down a bit.

Do I have to use a custom select query?


1 Answer 1


I think I managed to solve this.

What I did was to add the following in my functions.php file:

add_filter( 'posts_where', 'exclude_my_posts' );    

function exclude_my_posts( $where ) {
    global $wpdb;

    //  For the front page. Hide posts with "efter15" set to "Ja", and only show posts with "show_on_front_page" set to "Nej"
    if (is_front_page()) {
        return $where . " AND $wpdb->posts.ID NOT IN ( SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = 'efter15' AND meta_value = 'Ja' ) AND $wpdb->posts.ID NOT IN ( SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = 'show_on_front_page' AND meta_value = 'Nej' )";
    //  Always show all in dashboard
    elseif (is_admin()) {
        return $where;
    //  Everywhere else: Hide posts with "efter15" set to "Ja"
    else {
        return $where . " AND $wpdb->posts.ID NOT IN ( SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = 'efter15' AND meta_value = 'Ja' )";


And in my index.php file - which is also used for category, tag etc (therefore the is_front_page()) for now at least:

<?php if (is_front_page()) {
    query_posts(array('category_name' => 'notiser', 'paged' => get_query_var('paged')));
} ?>

Then follows the loop and the rest. Looks good so far.

Your Answer

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

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