WordPress WP_Query: Get Posts by Meta Values

It is the most useful thing when you create post filters or advanced search on your WordPress blog / WooCommerce shop.

January 3, 2014 / #Custom Fields, #Filters, #WP_Query

In this post I assume that you already have basic knowledges how to work with WP_Query class in WordPress. Before I begin, I want to show you some very simple examples. The similar examples you can find in WordPress Codex.

As you know all the posts have the metadata you can fill in «Custom fields» metabox (it can also be hidden). So, for example, if you want to get a post with meta key show_on_homepage and meta value on, you can do it in the following way:

$rd_args = array(
	'meta_key' => 'show_on_homepage',
	'meta_value' => 'on'
);
 
$rd_query = new WP_Query( $rd_args );

Otherwise, if you need to query all posts except the ones with this pair of meta key and value, you can use the following parameters:

$rd_args = array(
	'meta_key' => 'show_on_homepage',
	'meta_value' => 'on',
	'meta_compare' => '!='
);
 
$rd_query = new WP_Query( $rd_args );

Do not forget that all examples in this post are simplified, so, some of WP_Query parameters are missing, e.g posts_per_page or post_type.

This was very very simple examples, just an introdution. But this post is about meta_query parameter. This parameter allows us to create a really cool post filters and search scripts.

meta_query Usage Examples

Get Posts with a Specific Custom Field Value

This is a simple example. Let’s get all the posts with custom field name «color» and custom field value «white».

// the meta_key 'color' with the meta_value 'white'
$rd_args = array(
	'meta_query' => array(
		array(
			'key' => 'color',
			'value' => 'white'
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

If you look in the post edit page (in admin area) of any queried posts, you will see the following in the «Custom Fields» section:

the meta_key and the meta_value

Get all the posts except the ones with meta key «color» and meta value «white»:

$rd_args = array(
	'meta_query' => array(
		array(
			'key' => 'color',
			'value' => 'white',
			'compare' => '!='
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

Now let’s get all the posts with white OR green color custom field value:

// custom field name is color and custom field value is 'white' OR 'green'
$rd_args = array(
	'meta_query' => array(
		array(
			'key' => 'color',
			'value' => array('white','green'),
			'compare' => 'IN'
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

Get all the posts (products in online shop for example) except white products and green products:

$rd_args = array(
	'meta_query' => array(
		array(
			'key' => 'color',
			'value' => array('white','green'),
			'compare' => 'NOT IN'
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

Get Posts Within a Given Range of Numeric Meta Values

For example, let’s filter the online shop products by prices:

// the product price is more than 2000 and less than 4000
$rd_args = array(
	'meta_query' => array(
		array(
			'key' => 'price',
			'value' => array( 2000, 4000 ),
			'type' => 'numeric',
			'compare' => 'BETWEEN'
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

Numeric Comparison

The product price in this example is 2000 or more than 2000:

$rd_args = array(
	'meta_query' => array(
		array(
			'key' => 'price',
			'value' => 2000,
			'type' => 'numeric',
			'compare' => '>='
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

The product price is less than 4000:

$rd_args = array(
	'meta_query' => array(
		array(
			'key' => 'price',
			'value' => 4000,
			'type' => 'numeric',
			'compare' => '<'
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

Query Posts by Several (two or more) Custom Field Values

Let’s combine some of the previous examples:

// the 'color' is 'white' AND the 'price' is more than 2000 and less than 4000
$rd_args = array(
	'meta_query' => array(
		'relation' => 'AND',
		array(
			'key' => 'show_on_homepage',
			'value' => 'on'
		),
		array(
			'relation' => 'OR',
			array(
				'key' => 'color',
				'value' => 'white'
			),
			array(
				'key' => 'price',
				'value' => array( 2000, 4000 ),
				'type' => 'numeric',
				'compare' => 'BETWEEN'
			)
		)
	)
);
 
$rd_query = new WP_Query( $rd_args );

Only the best of WordPress

once a week, no spam

Comments 30

  • I’m trying to figure out how I would wrap a short code function around your code sample so that the admin could put in their own values to filter the meta content displayed on a page

    function product_listing_function($atts) {
     
    	 extract(shortcode_atts( array(
    		'color' => '',
    		'price' => '',
    		), $atts
    	)
    );
    }
    add_shortcode( 'product_list', 'product_listing_function' );

    [product_list color=”white” price=”100″]

    I can’t seem to get the values to pass into the meta_query array? Could you please share an example of this.

    Thank You

    • I hope it helps.

      function product_listing_function($atts) {
      	extract(shortcode_atts( array(
      		'color' => '',
      		'price' => '',
      		), $atts
      	)
      	);
      	$rd_args = array(
      		'meta_query' => array(
      			'relation' => 'AND',
      			array(
      				'key' => 'color',
      				'value' => $color
      			),
      			array(
      				'key' => 'price',
      				'value' => $price,
      				'type' => 'numeric'
      			)
      		)
      	);
      	$rd_query = new WP_Query( $rd_args );
      }
       
      add_shortcode( 'product_list', 'product_listing_function' );
  • Hi! what if i’ve the meta placed in the comment_meta? I’ve been trying to pull the data with meta_query and nothing seems to work.

    I’ve a rating value stored in the comments meta, the key is rating and the values go from 0.00 to 5.00, i would like to query the posts that have at less 4.00.

    Thanks in advance for the help.

  • Hi man,

    This seems like some nice clear examples of the WP_Query. I was working with the WP_Meta_Query and wondered how it was possible to just query for all values under a particular meta key. Say for example you have a custom field called member_city, and many posts use this to give location informations such as “This user is from London”.

    What I’m actually trying to do is kind of hard to explain. I’m trying to get all custom meta data from the database, i.e all the cities, then output them into an array which can be used to generate a drop down menu that users can then select from to search users by location. I also don’t want this to duplicate cities, i.e if two people are from London, I don’t want London in the list twice. I’m using WordPress Advanced Search by Growth Spark for my search.

    I’m able to query the database and get an output such as:

    INNER JOIN rm_postmeta ON (rm_posts.ID = rm_postmeta.post_id)
         AND ( (rm_postmeta.meta_key = 'member_city' AND CAST(rm_postmeta.meta_value AS CHAR) IN    ('London')) )

    I just don’t know how to extract that information, then get it into my drop down. Does this make sense to you? May be confusing without code examples and understanding of the site architecture.

  • Salvatore CapolupoJanuary 2, 2015 at 09:01

    Fine and useful examples, happy new year!

  • Thanks a lot !!!

  • Hi, i found this examples very good, but i have a doubt, what if i want to order by a metabox value. For example, I have a custom post type named team_member and this post-type have a metabox named order, later in the loop, i need query the post but ordering by this order that i defined in the metabox, How i could do this?
    Thanks in advance.
    Please sorry my english….

    • MishaAuthorMay 30, 2015 at 06:05

      Hi,
      WP_Query supports the orderby parameter, so it should look like this:

      $args = array(
      	'meta_key'=>'key_of_the_metabox_field',
      	'orderby'=>'meta_value',
      	'order'=> 'ASC' // or DESC
      );
  • thanks Misha, I try your code, but instead ‘orderby’=>’meta_value’ I used ‘orderby’=>’meta_value_num’ and it’s working perfect!!!! Thanks a lot for the answer.
    Regards
    Juankql

  • How would I come about showing all post if meta value doesn’t exist.

    In my case I am querying post based on dropdown selection. And based on your example, the script is working just fine. It loads the post based on meta value. But what if in the dropdown selection I have a show all option. How can I come about doing that?

    Thanks!

    • MishaAuthorAugust 7, 2015 at 06:08

      Do you need to get posts with exact meta key and with any meta value?

      • Here is the code I’m working with right now:

        <form method="get">
               <label>Day: </label>
            <select name="day" size="1" onchange="this.form.submit()">
                <option value="all" <?php if($selected_day == "all"){ print "selected='selected'"; } ?> >All</option>
                <option value="monday" <?php if($selected_day == "monday"){ print "selected='selected'"; } ?> >Monday</option>
                <option value="tuesday" <?php if($selected_day == "tuesday"){ print "selected='selected'"; } ?> >Tuesday</option>
                <option value="wednesday" <?php if($selected_day == "wednesday"){ print "selected='selected'"; } ?> >Wednesday</option>
            </select>
        </form>
        $query_day = '';
        switch( $_GET['day'] ) {
            case 'saturday': $query_day = 'saturday'; break;
            case 'friday': $query_day = 'friday'; break;
            case 'thursday': $query_day = 'thursday'; break;
            case 'wednesday': $query_day = 'wednesday'; break;
            case 'tuesday': $query_day = 'tuesday'; break;
            case 'monday': $query_day = 'monday'; break;
            default: case 'all': $query_day = HOW DO I GET ALL  break;
        }
        $page = (get_query_var('paged')) ? get_query_var('paged') : 1;
         
        // Build the args
        $args = array(
        	'post_type'	=> 'connect-groups',
        	'posts_per_page' => 100,
        	'meta_query' => array(
                array(
                    'key'     => 'connect_group_day',
        			'field'		=> 'slug',
        			'value'		=>  $query_day,
                )
            )
        );
        // Query the posts
        $posts = query_posts( $args );

        So here I get posts with specific meta selected from the dropdown menu, but if the user selects ALL i want to grab from all terms that exist.

        • MishaAuthorAugust 11, 2015 at 07:08

          I think you need something like this:

          $args = array(
          	'post_type'	=> 'connect-groups',
          	'posts_per_page' => 100,
          	'meta_query' => array(
          		array(
          			'key'     => 'connect_group_day',
          			'compare' => 'EXISTS' // WP 3.5 +
          		)
          	)
          );
  • Hello! It doesn’t seem to work for me :(

    My task is to show “events” on the page that has “event_repeate” value equal to “weekly”. So the custom post type is “event” and meta_key and meta_value in the table wp_metadata are “event_repeate” and “weekly” respectively.

    My code is:

    <?php 
    	$args = array(
    	  'event_category' => 'active',
    	  'meta_query' => array(
    		  'key' => 'event_repeat',
    		  'value' => 'weekly'
    	  )
    	);
    	$events_future_query = new WP_Query($args);
    ?>

    But this doesn’t seem to work :(

    Maybe you have a thought how this can be solved?

  • Rtchie MatosJune 27, 2016 at 03:06

    I just want to thank you for all the examples you’ve posted. It has given me some way to be able to start off with the project I’m doing, based on a query on premium post listing. Again, thank you.

  • I have a key that has 2 meta options: “id”:”12345″ , and “select new”

    How can i return only the first? (the ome with the id?

    • MishaAuthorJune 30, 2016 at 06:06

      Let me clarify — you have two meta values with the same key and you want to get posts with the first value only, is that right?

      • thanks @Misha for your reply :)

        yes, the key is the same and i want to get in return only {“id”:”12345″} << which comes like this (including the ' " ' charachter and the ' : '.)

        thanks !

        • MishaAuthorJune 30, 2016 at 08:06

          I hope it helps :)

          $args = array(
          	 'meta_query' => array(
          		'key' => 'YOUR_KEY_NAME',
          		'value' => '{"id":"12345"}'
          	)
          );
  • sure did!

    thank you very much :)

  • This code not working for me. i put key and value from custom field.. is there need any type of function.php code??

  • Every custom field have two type of values. brand key values [ Apple or Nokia ] and Price key values [ 100$ or 200$ ]..
    How to get posts for these checkboxs using custom field vlaue ??

    Brand:
      <input name="nokia" id="nokia" type="checkbox" /> Nokia <br>
      <input name="apple" id="apple" type="checkbox" /> Apple <br>        
      Price:
      <input name="price1" id="price1" type="checkbox" /> 100$ <br>
      <input name="price2" id="price2" type="checkbox" /> 200$ <br>
    • MishaAuthorJuly 1, 2016 at 07:07

      Hello,

      if I understand you properly, this is the part of the form filter, so put in your php file which process the form data the following code:

      $args = array(
      	// another WP_Query parameters
      );
      $args['meta_query'] = array();
      if( $_POST['nokia'] == 'on'  && $_POST['apple'] == 'on' )
      	$args['meta_query'][] = array(
      		'key' => 'phone', // this is your meta key, it may be different on your website
      		'value' => array('nokia','apple'),
      		'compare' => 'IN'
      	);
      if( $_POST['nokia'] == 'on' )
      	$args['meta_query'][] = array(
      		'key' => 'phone', // this is your meta key, it may be different on your website
      		'value' => 'nokia'
      	);
      if( $_POST['apple'] == 'on' )
      	$args['meta_query'][] = array(
      		'key' => 'phone', // this is your meta key, it may be different on your website
      		'value' => 'apple'
      	);
       
       
      $q = new WP_Query( $args );
      • i put this code on single.php page inside php tag.. there is no output of this code..
        is there need for any kind of echo for this value or fields????

        • MishaAuthorJuly 1, 2016 at 20:07

          Of course this is just the part of $args array, just a algorithm to you how to do it :)

          P.S. I think you need to read the official WP_Query reference as well.

          • Hello Misha,
            Finally i make a custom field value filter form using AJAX and JSON but not working, can you please check it? When i check any box nothing happen, still remain as it was…. I also check console J query working properly..

            Form.php

            <form id='test'>
            <input type="checkbox" name="t[]" value="Nokia" class="br">
            <input type="checkbox" name="t[]" value="Sony" class="br">
            <input type="checkbox" name="t[]" value="Apple" class="br">
            <div class="mobile_brand">
             
            </div>
            </form>

            Script:-

            <script type="text/javascript">
            jQuery(document).ready(function(){
                jQuery('.br').click(function(){
                    jQuery('.contents').remove();
                    var checked = jQuery('#test').serialize();
                    jQuery.ajax({
                        url:"<?php echo admin_url('admin-ajax.php'); ?>",
                        data:"action=call_post&"+checked,
                        success:function(obj){
                             var render_data = "<div class='contents'>";
             
                            // This is to watch your json object
                            console.log(obj);   
             
                            for(var i=0;i<obj.length;i++)
                            {
                                console.log(obj[i].post_title);
                                render_data+="<h4>"+obj[i].post_title+"</h4>";
                                render_data+="<p>"+obj[i].post_content+"</p>";
                            }
                            render_data+="</div>";
                            jQuery(render_data).appendTo('.mobile_brand');
             
                        }
                    });
                })
            });
            </script>

            function.php

            <?php
            add_action('wp_ajax_call_post','call_post');
            add_action('wp_ajax_nopriv_call_post','call_post');
            function call_post(){
                $test = $_REQUEST['mobile'];
             
                $args = array(
                    'post_type'  => 'post',
                    'meta_query' => array(
                        array(
                            'key'     => 'brand',
                            'value'   => $test,
                            // 'compare' => 'IN',
                        ),
                    ),
                );
             
            $query = new WP_Query( $args );
            wp_send_json($query->posts);
            }
            ?>
          • If you send me a working filter form through email using this code. i will be really thankful to you..

          • MishaAuthorAugust 15, 2016 at 10:08

            Tomorrow I plan to publish a post about it.

Leave your question or feedback

phpjsHTMLCSSSQLCode
Please, enter a comment
Please, enter a name
Incorrect email