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.

#metas, #WP_Query  /  April 12  /   33

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

Subscribe to this weekly newsletter to receive the latest blog posts by email.I respect your privacy. Your email is safe with me.

Comments 33

← Older
  • 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?

    • MishaAuthor June 30, 2016 at 06:33

      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 !

        • MishaAuthor June 30, 2016 at 08:14

          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>
    • MishaAuthor July 1, 2016 at 07:29

      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????

        • MishaAuthor July 1, 2016 at 20:22

          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..

          • MishaAuthor August 15, 2016 at 10:55

            Tomorrow I plan to publish a post about it.

  • Ivan Lemus August 1, 2017 at 23:51

    Hi Misha, thanks for this info…. and since you seem to be very proficient in Wp_Query… Can I pick your brain a little bit and ask for your help:

    I need to display posts (tours) that are in a specific location (city) so in my location_taxonomy.php I have a meta query in the form of:

    $args = array(
      'post_type'     => 'tour',
      'meta_key'      => 'trav_tour_city',
      'meta_value'    => $term->term_id,
    );

    When the key stored in the tour has only one value (one city), it displays the posts. When the key has more than one value (multiple cities or a string of ids separated by commas), it doesn’t.

    How can I change the $args so the query would determine that the current city ($term->term_id) exists within the comma separated values stored as a string in ‘trav_tour_city’?

    I have tried something in the line of:

    $args = array(
      array(
    	'post_type'   => 'tour',
    	 'meta_query' => array(
    	  array(
    		'key'=> 'trav_tour_city',
    		'value'   => $term->term_id, 
    		'compare' => 'LIKE',
    	  ),
    	),
    	),
    );

    and also I tried “LIKE”, but obviously I don’t know what I’m doing… haha..

    any help would be greatly appreciated!

    Regards,

    Ivan

    • MishaAuthor August 2, 2017 at 07:42

      Hi Ivan,

      LIKE with the exact value is similar to =. If trav_tour_city values contain ID or IDs separated by commas, this should help:

      'meta_query' => array(
      	  array(
      		'key'=> 'trav_tour_city',
      		'value'   => '%' . $term->term_id . '%', 
      		'compare' => 'LIKE',
      	  ),
      	),
      • Ivan Lemus August 2, 2017 at 07:50

        This did the trick:

        					$args = array (
        						'post_type' => 'tour',
        						'meta_query'=> array(
        							array(
        								'key' => 'trav_tour_city', 
        								'compare' => 'LIKE',
        								'value' => $term->term_id,
        							)
        						),
        						'meta_key' => 'trav_tour_city',
        					);

        I will try yours also…

        Thanks a lot for your input!

Leave your question or feedback

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