query_posts exclude a meta key

<?php query_posts(array('showposts' => 1000, 'post_parent' => $post->ID, 'post_type' => 'page', 'orderby' => 'title', 'order' => 'ASC', 'meta_key' => featured_product, 'meta_value' => 1)); ?>


<?php query_posts(array('showposts' => 1000, 'post_parent' => $post->ID, 'post_type' => 'page', 'orderby' => 'title', 'order' => 'ASC')); ?>

I have 2 queries, first to show meta key with featured_product eq 1. So I want to exclude all the featured products on the second query. How can i do that please? Thanks!

Related posts

Leave a Reply

4 comments

  1. I’ve never had any luck getting the meta compare to work either–but I came up with a workaround for this exact situation (having “featured” items at the top of the page).

    First, you probably shouldn’t be using query_posts for both queries. You should use a custom query for at least the first one. Then, while you’re running that loop, keep the ids of any “featured” posts in a variable. When you run your second loop, you can use the “post__not_in” arg to exclude the featured ones. Like so:

    // Set up a custom query
    $featured_query = new WP_query();
    
    // Your query args
        $featured_args=array(
            'post_type'=>'post',
            'meta_key'=>'featured_product',
            'meta_value'=>'1'
        );
    
    // Run it
        $featured_query->query($featured_args);
    
        if ($featured_query->have_posts()) {
    
        while ($featured_query->have_posts()) {
    
                $featured_query->the_post();
    
            // Remember the featued ID
            $featured_post_id = get_the_ID(); 
    
            // Render your featured post here
    
        }
    
    }
    
    // Set up the args for your main query
    $args = array(
            'post_type' => 'post',
            'post__not_in' => array($featured_post_id) // Don't show the featured post
        );
    
    // Now run your main query and so on...
    
  2. MathSmath’s answer is ok, but it’s very inefficient and would not scale to a WordPress site with 100,000+ posts or what have you. Doing a WP_Query() for 1000 posts is going to be slow enough.

    Rather than using a posts_not_it (which would pass a query long string if you hade several thousand posts here) if you have MySQL 4.1+ it would be better to use a subquery to exclude the posts you don’t want.

    Here is a slightly modified example I am using on a site with 250,000+ posts.

    // add a filter to 'posts_where' to add the subquery
    add_filter( 'posts_where', '_exclude_meta_key_in_posts_where' );    
    
    // make the query, the below function will be called
    query_posts(array('showposts' => 1000, 'post_parent' => $post->ID, 'post_type' => 'page', 'orderby' => 'title', 'order' => 'ASC'));
    
    function _exclude_meta_key_in_posts_where( $where ) {
    
        global $wpdb;
        return $where . " AND $wpdb->posts.ID NOT IN ( SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = 'featured_product' AND meta_value > '' )";
    }
    
    //remove the filter incase we do any more query_posts()s
    remove_filter( 'posts_where', '_exclude_meta_key_in_posts_where' );
    

    You could probably do it all in one create_function() though I am not sure if that is very efficient, but would be less lines:

    // add a filter to 'posts_where' to add the subquery
    add_filter( 'posts_where', create_function( '$where', 'global $wpdb; return $where . " AND $wpdb->posts.ID NOT IN ( SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = 'featured_product' AND meta_value > '' )";' ) );
    

    I didn’t test the create_function() example.

  3. I haven’t tried this, but some research let me to this. Using meta_compare you can check if meta_value does not equal 1 display the posts.

    <?php query_posts(array('showposts' => 1000, 'post_parent' => $post->ID, 'post_type' => 'page', 'orderby' => 'title', 'order' => 'ASC', 'meta_value' => featured_product, 'meta_compare' => '!=', 'meta_value' => 1 )); ?>
    
  4. My solution was to add the custom field with a ‘false’ value to all of the existing posts and to hook the creation of new posts in order to add the field to them as well.

    I’m not sure if this is a more efficient way to handle this situation but I wanted to stay away from custom SQL queries.

    The following is a one-time-use function I used for adding the field to all existing posts:

    function unfeature_all() {
        $args = array(
            'numberposts'   => -1,
        );
    
        $posts = get_posts( $args );
    
        foreach ($posts as $post) {
            $status = get_post_meta($post->ID, 'featured_post', true);
            if (!$status) {
                update_post_meta($post->ID, 'featured_post', false);
            }
        }
    
    }
    
    if (current_user_can('manage_options')) unfeature_all();