Is there a way to have a meta_query with sub relations? I don't want one relation to apply to all of the query's arrays.
I tried this, but to no avail:
'meta_query' => array(
array(
'key' => 'event_type',
'value' => 'session',
'compare' => 'LIKE'
),
array(
'relation' => 'OR',
array(
'key' => 'event_video',
'value' => '0',
'compare' => '>'
),
array(
'key' => 'event_summary',
'value' => '',
'compare' => '!='
)
),
array(
'key' => 'event_date_single',
'value' => '',
'compare' => 'LIKE'
),
array(
'key' => 'event_start_time',
'value' => '',
'compare' => 'LIKE'
)
)
So 'relation' => 'OR' should only apply between event_video and event_summary. Everything else is independent of one another. Is this possible somehow?
Thanks
It looks like this could be a meta_query limitation. WP Codex shows that you can use relations for meta queries, but as far as I see the limitation is that you can only use one kind of relation for the whole meta_query.
This means you can have a full OR or a full AND (default) relation between meta_query parameters, but you can never have them both combined, which is just what you want.
As I was not glad when I faced it at WP Codex, I went deeper in the matter by manually searching the code. So I found out that WP_Query calls WP_Meta_Query to parse meta_query parameters. This is WP_Meta_Query's class constructor (you can find it in wp-includes/meta.php at line 643 in WP 3.6):
/**
* Constructor
*
* #param array $meta_query (optional) A meta query
*/
function __construct( $meta_query = false ) {
if ( !$meta_query )
return;
if ( isset( $meta_query['relation'] ) && strtoupper( $meta_query['relation'] ) == 'OR' ) {
$this->relation = 'OR';
} else {
$this->relation = 'AND';
}
$this->queries = array();
foreach ( $meta_query as $key => $query ) {
if ( ! is_array( $query ) )
continue;
$this->queries[] = $query;
}
}
Long story short, the second if shows that this class will work only either with a OR or AND relation, but never with both of them combined.
So, unfortunately, it seems that it's not possible to achieve what you are trying to do (at least until WP 3.6). I guess your best shot is to split the main query, first doing specific Meta Queries and then applying their results(returned metas) to your main query.
I know that this is not a solution but an answer. Nevertheless, I hope this may help you to find a solution for this matter.
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 large WP site with about 2k posts and 150k postmeta. When browsing to a large category, the archive loads very slow due to the WP query that is seeking for featured posts, to show them first.
I know that the ultimate target is to optimize the postmeta table, but for now I would like to know if there is any possible way to optimize the meta query (one at the bottom) below.
I did some debugging (see the //comments) and found that the 'compare' => '!=' is causing for the query to get really slow. I've also found that '' or '<' is speeding up the query a lot, with the same results, but I am not sure if that is a proper way to go. Please let me know if there is a way to speed up this query. Thanks
function appthemes_addon_on_top_query( $wp_query ){
$addon_type = $wp_query->get( 'addon_on_top' );
if( ! $addon_type || ! appthemes_addon_exists( $addon_type ) ) {
return;
}
$addon_info = appthemes_get_addon_info( $addon_type );
$flag_key = $addon_info['flag_key']; //custom field for featured posts
$meta_query = (array) $wp_query->get( 'meta_value', 1 );
$meta_query = array_filter( $meta_query );
$meta_query[] = array(
'relation' => 'OR',
array(
'key' => $flag_key,
'compare' => 'NOT EXISTS',
),
array(
'relation' => 'OR',
//Deleting the array below makes the query quick, but i need it to show featured posts first
array(
'key' => $flag_key,
'value' => 1,
),
//Deleting the array below makes the query quick, but i need it to properly sorting the posts by date (see below: $wp_query->set( 'orderby')
array(
'key' => $flag_key,
'value' => 1,
'compare' => '!=', //It is about this comparison. '' or '<' makes the query quick, but i am not sure if that is a proper replacement. Also not sure why '!=' makes it this slow.
),
),
);
$wp_query->set( 'meta_query', $meta_query );
$wp_query->set( 'orderby', array( 'meta_value' => 'DESC', 'date' => 'DESC' ) );
}
Ok, Ive found that 'compare' => '!=' slows it down, but 'compare' => '<>' does not. I guess both are the same, so I guess this question is solved.
I have been through several topics on sorting taxonomies and custom fields, including some that were promising. However, I am still not constructing my query args correctly it seems.
I am "fixing" someone else's code in a custom theme that is used in a multisite configuration, but I am able to override/filter the query on a per-site basis.
The query is called via the theme with the following:
return apply_filters( 'theme_query_args_filter', $args);
I have custom fields in the "role" taxonomy that include:
last_name
first_name
Pretty common I think.
However, when the args are executed, the following filter args are sorting only by last name (key part is the else clause):
function my_args_filter( $args ) {
if (is_home() && !is_search()) {
$args['meta_key'] = 'event_date';
$args['orderby'] = 'event_date';
$args['order'] = 'DESC';
}
else {
$tax = $args['taxonomy'];
$theterm = $args['term'];
$args = array (
'taxonomy' => $tax,
'term' => $theterm,
'meta_key' => 'last_name',
'orderby' => 'meta_value',
'order' => 'ASC'
);
}
add_filter( 'theme_query_args_filter', 'my_args_filter' );
I've tried to modify the orderby as indicated in https://make.wordpress.org/core/2014/08/29/a-more-powerful-order-by-in-wordpress-4-0/ to use an array to do a multisort, but I'm hitting my head up against the wall. I think the problem is that the code is written using a mixture of old ways of doing things and new ways.
Any advice is appreciated. According to the example on in the docs above, I SHOULD be able to pass in multiple meta key/value/orders via an array, but I'm just not getting it.
Thanks for any leads you might have. (long-time listener, first-time caller)
(I also looked at https://wordpress.stackexchange.com/questions/109849/order-by-desc-asc-in-custom-wp-query but I couldn't extrapolate that example to this one either)
Figured it out on my most recent try. Hat tip to this solution https://wordpress.stackexchange.com/questions/249881/multiple-custom-fields-for-orderby-in-wp-query by Nath. if there is a more elegant way to do it, please let me know.
$tax = $args['taxonomy'];
$theterm = $args['term'];
$paged = $args['paged'];
$args = array (
'taxonomy' => $tax,
'term' => $theterm,
'paged' => $paged,
'posts_per_page' => '10',
'meta_query' => array(
array(
'relation' => 'AND',
'last_name' =>
array(
'key' => 'last_name',
'compare' => 'EXISTS',
),
'first_name' =>
array(
'key' => 'first_name',
'compare' => 'EXISTS',
),
),
),
'orderby' => array (
'last_name' => 'ASC',
'first_name' => 'ASC',
)
);
}
My site has woocommerce plugin, so post_type is product. Each product has several custom fields used by another plugin (Compare Products Pro).
Now we would like to query products by URL so eg: www.domain.com/?post_type=product&custom_field=value
Is this possible? And how?
Any help would be highly appriciated!
You could add something like this to your query arguments:
'post_type' => $_GET['post_type'],
'meta_query' => array(
array(
'key' => '_woo_compare_field-',
'value' => $_GET['_woo_compare_field-'],
'compare' => '=',
)
),
But its very static, will not work for different meta key value pairs.
You could assign them to an array and append that array like this
$meta_queries = array(
'relation' => 'AND',
);
foreach($_GET as $key => $value) {
$result = array(
'key' => $key,
'value' => $value,
'compare' => '=',
);
$meta_queries[] = $result;
}
And append the $meta_queries array to the wordpress query arguments.
But this means all your get variables are used as meta key value pairs. You can ofcourse write some logic for this but it will never be pretty
This kind of follows on from a previous question where JanW : http://bit.ly/VQy9hb
I'm trying to hide posts that contain certain meta data, in this case meta_name = "smartPrivate".
The function below works but unfortunately also affects the menu loop (it just disappears).
Does anyone know how I can hide these posts from appearing in all loops but not affect the menu (and who knows what else...)
Thanks in advance
Rob
function hide_some_posts( $query ) {
if (!is_user_logged_in()) {
$query->set( 'meta_query', array(
array(
'key' => 'smartPrivate',
'value' => 'smartPrivate_loggedIn',
'compare' => '!='
),
array(
'key' => 'smartPrivate',
'value' => 'smartPrivate_loggedInMentors',
'compare' => '!='
)
));
}
return $query;
}
add_filter( 'pre_get_posts', 'hide_some_posts' );
So your problem is that it affects other queries than the main query, if I understand your situation correctly. This is pretty much why is_main_query exists. So try this:
function hide_some_posts( $query ) {
if (!is_user_logged_in() && $query->is_main_query() ) {
$query->set( 'meta_query', array(
array(
'key' => 'smartPrivate',
'value' => 'smartPrivate_loggedIn',
'compare' => '!='
),
array(
'key' => 'smartPrivate',
'value' => 'smartPrivate_loggedInMentors',
'compare' => '!='
)
));
}
return $query;
}
add_filter( 'pre_get_posts', 'hide_some_posts' );