WordPress.org

Codex

Interested in functions, hooks, classes, or methods? Check out the new WordPress Code Reference!

Class Reference/WP Meta Query

Description

WP_Meta_Query is a class defined in wp-includes/meta.php that generates the necessary SQL for meta-related queries. It was introduced in Version 3.2.0 and greatly improved the possibility to query posts by custom fields. In the WP core, it's used in the WP_Query and WP_User_Query classes, and since Version 3.5 in the WP_Comment_Query class. Unless you're writing a custom SQL query, you should look in the *Custom Field Parameters* section for the corresponding class.

Usage

Accepted Arguments

The following arguments can be passed in a key=>value paired array.

  • meta_key (string) - Custom field key. ( You must sanitize this yourself )
  • meta_value (string|array) - Custom field value. ( You must sanitize this yourself )
  • meta_type (string) - Custom field type (see type below for options).
  • meta_compare (string) - Operator to test the 'meta_value' (see compare below for possible values).
  • meta_query (array) - Contains one or more arrays with the following keys:
    • key (string) - Custom field key.
    • value (string|array) - Custom field value. It can be an array only when compare is 'IN', 'NOT IN', 'BETWEEN', or 'NOT BETWEEN'. You don't have to specify a value when using the 'EXISTS' or 'NOT EXISTS' comparisons in WordPress 3.9 and up.
      (Note: Due to bug #23268, value was required for NOT EXISTS comparisons to work correctly prior to 3.9. You had to supply some string for the value parameter. An empty string or NULL will NOT work. However, any other string will do the trick and will NOT show up in your SQL when using NOT EXISTS. Need inspiration? How about 'bug #23268'.)
    • compare (string) - Operator to test. Possible values are '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Values 'REGEXP', 'NOT REGEXP' and 'RLIKE' were added in WordPress 3.7. Default value is '='.
    • type (string) - Custom field type. Possible values are 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'. Default value is 'CHAR'.

The 'type' DATE works with the 'compare' value BETWEEN only if the date is stored at the format YYYY-MM-DD and tested with this format.

Note: The 'meta_key', 'meta_value', 'meta_type' and 'meta_compare' arguments will only work if you use the second method described below.

Initializing WP_Meta_Query

You generally have two options on how to initialize and use a new WP_Meta_Query object:

Passing an Array of query parameters to the constructor:

$meta_query_args = array(
	'relation' => 'OR', // Optional, defaults to "AND"
	array(
		'key'     => '_my_custom_key',
		'value'   => 'Value I am looking for',
		'compare' => '='
	)
);
$meta_query = new WP_Meta_Query( $meta_query_args );

In this case, you pass an array of key/value pair arrays (which were described above in the meta_query argument).

You can optionally pass the `relation` key and set it to either OR or AND. It defines the relation, when there is more than one meta query (whether all of the conditions should be met, or at least one of them needs to be met).

Nested arrays can be used to construct complex queries. For example, where _my_custom_key = value OR (_my_custom_key_2 = value AND _my_custom_key_3 = value).

$meta_query_args = array(
	'relation' => 'OR', // Optional, defaults to "AND"
	array(
		'key'     => '_my_custom_key',
		'value'   => 'Value I am looking for',
		'compare' => '='
	),
	array(
		'relation' => 'AND',
		array(
			'key'     => '_my_custom_key_2',
			'value'   => 'Value I am looking for 2',
			'compare' => '='
		),
		array(
			'key'     => '_my_custom_key_3',
			'value'   => 'Value I am looking for 3',
			'compare' => '='
		)
	)
);
$meta_query = new WP_Meta_Query( $meta_query_args );

Using the WP_Meta_Query::parse_query_vars( $query ) method: You can use this method, if you want to use the simple query args(`meta_key`, `meta_value`, `meta_type`, `meta_compare`), or if you are unsure of the presence of meta query parameters.

// $query_vars can have various contents, so an example is not added here, but you need to have it defined beforehand
$meta_query = new WP_Meta_Query();
// Won't work with an array( 'relation', array( 'key' => '...' ) )
// as the parse_query_vars() method searches for the `meta_` prefix
$meta_query->parse_query_vars( array(
	'meta_key' => 'some_key',
	// etc.
) );

Getting the final SQL

You can retrieve the generated SQL by using the following method.

$mq_sql = $meta_query->get_sql(
	$type,
	$primary_table,
	$primary_id_column,
	$context = null
);

List of Arguments:

  • $type' (string) - Type of meta(post, comment, user).
  • $primary_table (string) - The table where we will be looking for rows. You can pass for instance $wpdb->posts, or the alias name if you are aliasing the table in your SQL query
  • $primary_id_column (string) - The column that holds the ID(for posts, it is ID, for comments it is comment_ID and for users is ID).
  • $context (object) - Optional - The main query object. It is only used when the result is passed to the get_meta_sql filter.

On failure(for instance - lacking any meta query parameters in the query array), this function will return `false`.

On success, it will return an array like this:

array(
	'join'  => $join_sql,
	'where' => $where_sql
)

With each key holding the SQL for the corresponding section.

Example: Single Meta Entry - Flat array

Query

// Note that this will produce a "key only" query
// If you want a full one, add a meta_value and meta_compare array key/value pair
$query_args = array(
	'meta_key' => 'some_key_name',
);
$meta_query = new WP_Meta_Query();
$meta_query->parse_query_vars( $query_args );
$mq = $meta_query->get_sql(
	'post',
	$wpdb->posts,
	'ID',
	null
);

Result

array (size=2)
  'join' => string ' INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)' (length=62)
  'where' => string ' AND (wp_postmeta.meta_key = 'some_key' )' (length=40)

Example: Multiple Meta Entries - Multi dimensional array:

Query:

$query_args = array( 'meta_query' => array(
	'relation' => 'OR',
	array(
		'key' => 'foo_key',
		// 'value' => 'foo',
		// 'compare' => 'LIKE',
	),
	array(
		'key' => 'bar_key',
	),
) );
$meta_query = new WP_Meta_Query();
$meta_query->parse_query_vars( $query_args );
$mq_sql = $meta_query->get_sql(
	'post',
	$wpdb->posts,
	'ID',
	null
);

Result:

'join' => string ' INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id' (length=60)
'where' => string ' AND (wp_postmeta.meta_key = 'foo_key' OR wp_postmeta.meta_key = 'bar_key' )' (length=75)

Note: This example will not append a space to the join statement, so you have to do it manually to not crash your query. The same goes for the where statement.

If you're using the value and compare parts of the meta_query input argument array, then the query string will look something like the following:

'where' => string ' AND (wp_postmeta.meta_key = 'foo_key' OR  (mt1.meta_key = 'bar_key' AND CAST(mt1.meta_value AS CHAR) LIKE '%foo%') )'

Keep in mind that mt1 is the alias of the meta table and the join clause will look something like this and therefore use the JOIN twice:

'join' => string ' INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)'

Use that in further queries or form inside your posts_clauses, posts_where or posts_join filter callbacks.

Named sub-meta queries and multiple orderby arguments

Named meta sub-queries are particularly useful when you wish to sort by multiple different meta keys. If you pass the name (key) of your meta sub-query to the orderby array, WordPress will use that sub-query as the orderby parameter. See this example below:

$q = new WP_Query( array(
    'meta_query' => array(
        'relation' => 'AND',
        'state_clause' => array(
            'key' => 'state',
            'value' => 'Wisconsin',
        ),
        'city_clause' => array(
            'key' => 'city',
            'compare' => 'EXISTS',
        ), 
    ),
    'orderby' => array( 
        'city_clause' => 'ASC',
        'state_clause' => 'DESC',
    ),
) );

Props cybmeta on WPSE for this example.

Source File

WP_Meta_Query() is located in wp-includes/class-wp-meta-query.php.

Related

See also index of Class Reference and index of Function Reference.