I'm comparing the trip_region custom field of my trip CPT to the first element of an array: $filter_region[0].
Howevere I may have more elements in that array and I need to select trips whose trip_region field equals any of these elements. Is it possible, with meta_query, to compare (with an OR, not an AND) a field to several values at once? Because there's nothing quite like that in the doc.
$get_trips_region = get_posts(array(
'post_type' => 'trip',
'meta_query' => array(
array(
'key' => 'trip_region',
'value' => '"' . $filter_region[0] . '"',
'compare' => 'LIKE'
)
)
));
EDIT:
Here's my new code, presumably closer to the solution but doesn't return any result:
$get_trips_region = get_posts(array(
'post_type' => 'trip',
'meta_query' => array(
array(
'key' => 'trip_region',
'value' => $filter_region,
'compare' => 'IN'
)
)
));
EDIT(2):
Replacing get_posts with WP_Query and using WP_Query's request property I see the following SQL query is being executed here:
SELECT SQL_CALC_FOUND_ROWS wp_15_posts.ID FROM wp_15_posts INNER JOIN wp_15_postmeta ON (wp_15_posts.ID = wp_15_postmeta.post_id) WHERE 1=1 AND wp_15_posts.post_type = 'trip' AND (wp_15_posts.post_status = 'publish' OR wp_15_posts.post_status = 'private') AND ( (wp_15_postmeta.meta_key = 'trip_region' AND CAST(wp_15_postmeta.meta_value AS CHAR) IN ('47','46','45')) ) GROUP BY wp_15_posts.ID ORDER BY wp_15_posts.post_date DESC LIMIT 0, 10
Relevant passage I guess is: (wp_15_postmeta.meta_key = 'trip_region' AND CAST(wp_15_postmeta.meta_value AS CHAR) IN ('47','46','45'))
Looks good to me, I don't understand why it doesn't work.
I think you have to compare with IN instead of LIKE. The value must contain an array then. Here's the doc.
$filter_region = array( 'Region 1', 'Region 2' );
$get_trips_region = get_posts(array(
'post_type' => 'trip',
'meta_query' => array(
array(
'key' => 'trip_region',
'value' => $filter_region,
'compare' => 'IN'
)
)
));
You can use compare. Here is another WordPress Codex doc on Meta_Query.
Related
I'm trying to figure out how to achieve a specific query to modify my search results for posts with WordPress. I'm trying to search via a custom field called "Common Authors".
There can be multiple Common authors, which is causing my query to sometimes fail. Here is what I've got for now:
<?php
...
$query->set('meta_key', 'common_authors');
$query->set('meta_value', serialize( array(strval($_GET['common_author'])))); // I get a single ID from the url as a string
$query->set('meta_compare', 'IN');
This is what I see when I var_dump the query:
'meta_key' => string 'common_authors'
'meta_value' => string 'a:1:{i:0;s:5:"17145";}'
This works fine if there is only one common_author.
However, there can be multiple common_authors for a post. Here is a meta_value example from the database:
a:4:{i:0;s:5:"14409";i:1;s:5:"17145";i:2;s:5:"14407";i:3;s:5:"14406";}
Could somebody help me out, to figure out how to adapt my query, so that it would return this one as well?
Try This One Work Prefect!
$args = array(
'post_type' => 'post',
'meta_query' => array(
array(
'key' => 'common_authors',
'value' => array ( 'author1', 'author2', 'author3' ),
'compare' => 'IN'
)
)
);
$query = new WP_QUERY($args);
if You Need To Use It In pre_get_posts
$meta_query = array(
array(
'key' => 'common_authors',
'value' => array ( 'author1', 'author2', 'author3' ),
'compare' => 'IN'
)
);
$query->set('meta_query', $meta_query);
I have a series of posts and all have a meta_key with the value of "owner" and meta_value with serialized data such as "a:3:{i:0;s:3:"325";i:1;s:2:"41";i:2;s:2:"29";}"
meta_key owner
meta_value a:3:{i:0;s:3:"325";i:1;s:2:"41";i:2;s:2:"29";}
I am trying to figure out how to properly use get_posts() to return all the posts that have a meta_key with the value of owner and the meta_value containing a specific value such as 41
$args = array(
'post_type' => 'rp_applications',
'nopaging' => true,
'meta_query' => array(
'relation' => 'AND',
array(
'compare' => '=',
'key' => 'archived',
'value' => '0000-00-00'
),
array(
'compare' => '=',
'key' => 'owner',
'value' => ???? WHAT DO I PUT HERE ????
)
)
);
$applications = get_posts($args);
This sounds like you should be storing the "Owner" as a taxonomy term instead of meta data. It would give you easier and faster querying abilities as well.
That said, it's definitely possible to do what you want. I'd be cautious though, because the postmeta table by default is not indexed, so a large table with meta queries run against it will slow down your site quite a lot. You may want to consider adding a partial index to the table if it's going to be even remotely large (or again, switch to Taxonomy Terms instead of post meta for this).
If you still care to use a meta query, take a look at the compare options available in the WP_Meta_Query() docs.
One of the available options is REGEXP, so you could do something like:
$args = array(
'post_type' => 'rp_applications',
'nopaging' => true,
'meta_query' => array(
'relation' => 'AND',
array(
'compare' => 'REGEXP',
'key' => 'owner',
'value' => sprintf( 'a:\d:{i:0;s:\d:"\d.*?";i:1;s:%d:"%d".*', strlen($owner_id), $owner_id )
),
array(
'compare' => '=',
'key' => 'archived',
'value' => '0000-00-00'
)
)
);
Of course this method only works if the serialized data is in the same format on each one, and you'd need to adjust the regular expression if not - but that should be enough to get you started!
I have a wordpress query that is not-using a meta key and needs to override the default AND to an OR
Code snippet:
$args = array(
'post_type' => 'post',
'author__in' => $follow_authors,
'tag_slug__in' => $follows
);
The output statement is ...WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (71) ) AND wp_posts.post_author IN (3)...
I can't find a way to make the ..) AND wp.posts.post_author... to be an OR
Something like this should get you started:
$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 );
There is more in-depth explanation and examples here: https://codex.wordpress.org/Class_Reference/WP_Meta_Query
I'm struggling to get a working solution with this wp_query. I currently have some custom settings which are assigned to posts, one is whether or not the post is 'featured' and the second is a date and time for the post to end (no longer display in the results). I have the query working with the feature, but just need to work this end date into it, here is the query working find with the 'featured':
WP_Query('meta_key=skyali_feature&showposts=4&orderby=post_date');
The end date is set in the wp_postmeta table where meta_key is 'the_date' and the meta_values look like this '05/16/2013 05:24'. I would like to edit the above query where if 'the_date' has been set posts are only included if the 'the_date' is greater that todays date and time.
Here is my failed attempt:
WP_Query(
'meta_key=skyali_feature&meta_key=the_date&meta_compare=>=&meta_value='
.date('d/m/Y H:i')
.'&showposts=4&orderby=post_date&orderby=the_date'
);
I had to do something very similar recently and ended up needing to use the meta_query property instead. You'll want to do something like this:
$today = date('Ymd');
$args = array(
'post_type' => 'post',
'posts_per_page' => '4',
'meta_key' => 'the_date',
'meta_query' => array(
array(
'key' => 'skyali_feature'
),
array(
'key' => 'the_date',
'value' => $today,
'compare' => '>='
)
),
'orderby' => 'meta_value_num',
'order' => 'ASC'
);
$your_custom_query = new WP_Query($args);
A few notes...
I only needed to filter by date in my example, but it looks like you'll need to do date/time in yours. (You can just adjust the first line for the $today variable using the format you wish).
Use posts_per_page instead of showposts. showposts is deprecated.
Notice that I have included the meta_key twice (once at the top level of the array and once as an element in the meta_query array. There's a known bug where you can't sort your results by the key if you don't include it this way. I fought that one for a while too!
Hope this helps, have fun!
[edit] Forgot to add your skyali_feature key back into the array.
for people using the advanced custom field plugin with a date data type, this is what you need for dates greater or equal than today:
$today = date('Ymd');
$args = array(
'post_type' => 'post',
'meta_key' => 'end-date',
'meta_query' => array(
array(
'key' => 'end-date'
),
array(
'key' => 'end-date',
'value' => $today,
'compare' => '>='
)
),
'orderby' => 'meta_value',
'order' => 'ASC'
);
$your_custom_query = new WP_Query($args);
for people using Custom metadata manager you'll find that a datepicker field is stored as timestamp.
So in a similar case the above example isn't working and you may have php sort out the value you need to compare against. And the timestamp for a day earlier at 23:59:59 it'll do the job:
$yesterday = strtotime('yesterday 23:59:59');
$args = array(
'post_type' => 'post',
'meta_key' => 'end-date',
'meta_query' => array(
array(
'key' => 'end-date'
),
array(
'key' => 'end-date',
'value' => $yesterday,
'compare' => '>='
)
),
'orderby' => 'meta_value',
'order' => 'ASC'
);
$your_custom_query = new WP_Query($args);
If you also want to take account of the timezone setting for the blog use current_time() as in the following example:
$now = current_time('timestamp');
$yesterday = mktime(23, 59, 59, date('n',$now), date('j',$now)-1);
Consider a situation, I've post meta fields:
Min_Price
Max_Price
So every post has these two fields, and value can be any integer from non zero to 1000.
Lets take an example:
post #1 min_price = 5; max_price = 100
post #2 min_price = 50; max_price = 150
I'd like to make custom order logics to use with query_posts. So users can select price ranges and see posts with selected values.
Now if I had only 1 price and 1 field, it would be easy to let users select price range and get posts which fall into these range, like so:
query_posts( array(
'post_type' => 'product',
'meta_query' => array(
array(
'key' => 'price',
'value' => array( 100, 200 ),
'compare' => 'BETWEEN',
'type' => 'numeric',
)
)
) );
So here every post with price between 100-200 would be visible.
But I have a range of values... and I thought this would work:
query_posts( array(
'post_type' => 'product',
'meta_query' => array(
array(
'key' => 'min_price',
'value' => array( 100, 200 ),
'compare' => 'BETWEEN',
'type' => 'numeric',
),
array(
'key' => 'max_price',
'value' => array( 100, 200 ),
'compare' => 'BETWEEN',
'type' => 'numeric',
)
)
) );
Here client selected range 100<->200
Both post #1 and post #2 have values that fall in this range, so visitor will be interested in both of them. Unfortunately my query logic excludes them.
My brain is not working well right now, so I'm missing something simple. Any hints?
I now know your way should work, except McNab is probably right (there are plenty of examples right here: http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters) but I'll let my old answer remain. Someone might find it useful for non-standard stuff.
I don't know if you can do this using query post parameters, but I looked it up in the source code and this is how the query looks:
SELECT $found_rows $distinct $fields
FROM $wpdb->posts $join
WHERE 1=1 $where
$groupby
$orderby
$limits
And these are filters corresponding to the relevant query variables:
$where = apply_filters_ref_array('posts_where', array( $where, &$this ) );
$join = apply_filters_ref_array('posts_join', array( $join, &$this ) );
So that means that the problem can be reduced to SQL:
function postmeta_join( $join )
{
$join .= "
LEFT JOIN $wpdb->postmeta AS max_price ON max_price.meta_key = 'max_price'
LEFT JOIN $wpdb->postmeta AS min_price ON min_price.meta_key = 'min_price'";
return $join;
}
function filter_prices($where)
{
$where .= " AND max_price.max_price BETWEEN 100, 200 AND min_price.min_price BETWEN 100, 200";
return $where;
}
add_filter( 'posts_where', 'filter_prices' );
add_filter( 'posts_join', 'postmeta_join' );
Now I'm not an SQL expert so there may be problems with this. But if you don't get any other answer, you could play with this. (And BTW, you probably want to remove the filters when you're done with them.)
What you've done should work but you've missed the 'relation' parameter. It should be;
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'min_price',
'value' => array( 100, 200 ),
'compare' => 'BETWEEN',
'type' => 'numeric',
),
array(
'key' => 'max_price',
'value' => array( 100, 200 ),
'compare' => 'BETWEEN',
'type' => 'numeric',
)
)
The other thing to note is that in the first instance the meta_id is 'price' and in the second you are using 'min_price' and 'max_price'. Have these definitely been set?
I'm mentioning this because recently I had a hard time on these meta_queries with multiple sub-arrays and the AND relation where the values had been submitted by the user in a form (exactly like my understanding of your question). There was an issue where the query didn't work where there are null values for items in the array. This is meant to be fixed by scribu;
http://core.trac.wordpress.org/ticket/18158
But I could not get this to work at all. Tearing my hair out. I ended up checking the submitted value to see if there was one and then creating the arrays individually. The query would work if either $min_array or $max_array was NULL, but not at all if either of the meta_values was NULL and it was built the way you are doing it. I hope this makes sense, my code is below;
if ($min_price) {
$min_array = array('key' => 'min_price','value' => $min_price, 'value' => '=', 'type' => 'numeric');
}
if ($max_price) {
$max_array = array('key' => 'max_price','value' => $max_price, 'value' => '=', 'type' => 'numeric');
}
'meta_query' => array(
'relation' => 'AND',
$min_array,
$max_array
)