I want to get 12 term objects by calling get_terms; and I have a specific array of terms_ids which should come first.
Here is my query so far:
$term_args = array(
'taxonomy' => 'coupon_store',
'number' => 12,
'include' => $location_terms,
'meta_query' => array(
array(
'key' => '_wpc_is_featured',
'value' => 'on',
'compare' => '=',
),
)
);
$store_terms = get_terms( $term_args );
The problem is that since $location_terms consists of only 3 values, the whole result count is also restricted to 3. I know this is not quite possible as per get_terms documentation.
Is there any hack to get the rest 9 results, after getting the 3 from that array?
UPDATE
I have achieved it by using 2 queries as described in #Yoda's answer. Is there any way to get it done by using get_terms only once.
So... this basically doesn't work.
The include parameter sets up a where condition in the SQL query that requires all results to be within the include array.
So, that's not great for what you're after.
However, I do have a solution for you!
$term_args = array(
'taxonomy' => 'coupon_store',
'number' => 12,
'include' => $location_terms,
'meta_query' => array(
array(
'key' => '_wpc_is_featured',
'value' => 'on',
'compare' => '=',
),
)
);
$store_terms_location = get_terms( $term_args );
$term_args = array(
'taxonomy' => 'coupon_store',
'number' => 12 - count($store_terms_location), // only get as many as you still need
'exclude' => $location_terms,
'meta_query' => array(
array(
'key' => '_wpc_is_featured',
'value' => 'on',
'compare' => '=',
),
)
);
$store_terms_other = get_terms( $term_args );
// merge the two arrays together in order of priority
$store_terms = array_merge($store_terms_location, $store_terms_other);
So, to cover what this does:
Get up to 12 location terms
Get the remaining number of terms from a list that excludes the ones we checked for earlier
Merge the two lists together
This should give you the results you need. You can tidy it up, use some conditionals to determine whether the latter part needs to run, etc. Build on the general idea and make it fit what you're trying to do with your code.
What you are trying to do doesn't make a whole lot of sense.
If you already know the identity of the three terms you to have get first in your array, making a query to get those is kinda irrelevant. You could simply make two separate queries and merge the results.
E.g.:
$first_terms = array(
'taxonomy' => 'coupon_store',
'include' => $location_terms,
);
$store_terms_1 = get_terms( $term_args );
$remaining_terms = array(
'taxonomy' => 'coupon_store',
'number' => 9,
'exclude' => $location_terms,
'meta_query' => array(
array(
'key' => '_wpc_is_featured',
'value' => 'on',
'compare' => '=',
),
)
);
$store_terms_2 = get_terms( $term_args );
$resulting_terms = array_merge( $store_terms_1, $store_terms_2 );
Without knowing more about your data, it is not easy to do much more.
Guesstimating a bit, since you are already using term metas in your query, you could add another term meta with the order, and use that to order your results. This way you wouldn't need to hardcode those first three terms that you want to have on top, and you would only need to make one query.
E.g.:
$store_terms = [
'taxonomy' => 'coupon_store',
'number' => 12,
'meta_key' => 'coupon_store_term_order,
'orderby' => 'meta_value_num',
'meta_query' => [
[
'key' => '_wpc_is_featured',
'value' => 'on',
'compare' => '=',
],
]
];
This way, you have to set up a new term meta for your terms (coupon_store_term_order), and save there your desired order. You would need a bit more fiddling (e.g. deal with terms with no defined order, etc).
And logically, I'm further assuming that these three terms are also featured terms. Otherwise, making two requests and merging is still the only logical way to go.
Related
I have a page that shows standings for an online Fifa league, the standings should be sorted by Points and then Goal Differential. I collect the data for Wins, Draws, Losses, Goals For and Goals against. Here is my code -
<?php
$args = array(
'post_type' => 'post',
'cat' => '5',
'numberposts' => 12,
'meta_query' => array(
'relation' => 'AND',
'_fifa_w' => array(
'key' => '_fifa_w',
),
'_fifa_d' => array(
'key' => '_fifa_d',
),
'_fifa_gf' => array(
'key' => '_fifa_gf',
),
'_fifa_ga' => array(
'key' => '_fifa_ga',
),
),
'orderby' => array(
'_fifa_w' => 'DESC',
'_fifa_d' => 'DESC',
'_fifa_gf' => 'ASC',
'_fifa_ga' => 'DESC'
)
);
$product_posts = get_posts( $args );
?>
This sorts by total points but does nothing for the goal differential. If I exclude _fifa_w (wins) and _fifa_d (draws) from the code like this -
'orderby' => array(
'_fifa_gf' => 'ASC',
'_fifa_ga' => 'DESC'
)
);
Then it sorts by goal differential properly.
How can I get it to all work togetheR?
Try:
'orderby' => '_fifa_w _fifa_d _fifa_gf-_fifa_ga',
'order' => 'DESC'
I don't use Wordpress, but the idea is to sort by the first two columns normally, then sort on the calculated difference between the goalsfor and goals against.
Probably a good idea not to blindly trust me, but to eyeball the rendered query to be sure that Wordpress isn't backtick-wrapping the mathematical expression. Maybe $wp_query->request will show you what is being rendered.
Otherwise, there is always the php option of usort() on your result set.
I'm using wordpress to search some content with a few restrictions. Every time I save a post, I save in meta a related posts array.
Then I'm trying to search all posts which has a certain post as related, I have the following query. Selected post is an id to the post I'm looking for.
I checked $selected_post and it has values like the following one.
$selected_post = "25";
I added the meta value using the following instruction, I'm using update_post_meta. $related_posts contains an array of post ids, like the example below.
update_post_meta( $post->ID, 'related_post', $related_posts );
Query
$arg = array(
'post_type' => 'post',
'posts_per_page' => 5,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'related_post',
'value' => array( $selected_post ),
'compare' => 'IN',
'type' => 'STRING'
),
),
);
I checked this meta in some of my current posts, and I have something like this.
'related_post' => array( '15', '25', '46' );
When I execute this query using WP_Query it always returns me an empty array. I think I need something more in the query to make this works.
Any help would be appreciated.
The problem is that you are trying to query related_posts as if it was an array, but it actually gets serialised when its added to the database.
Using WP_Query on serialized arrays
If you were to add an array of post meta as follows:
$fruit_array = array( 'apple', 'orange', 'banana' );
update_post_meta( $post->ID, 'fruit', $fruit_array );
...the value for fruit in the database would be:
a:3:{i:0;s:5:"apple";i:1;s:6:"orange";i:2;s:6:"banana";}
Therefore you need to use LIKE to search the serialised string for the value you are looking for.
For the above example, your $args would be something like:
$args = array(
'post_type' => 'post',
'posts_per_page' => 5,
'meta_query' => array(
array(
'key' => 'fruit',
'value' => 'apple',
'compare' => 'LIKE',
),
)
);
Search for numbers/post ids
In your case, this is complicated by the fact that you are using post ids. Post ids or numbers aren't an issue specifically, but the problem is that LIKE will also return partial matches, so a query for 14 would also return 141, 1455 etc.
Based on the structure of the serialised string, I believe the following should work:
$args = array(
'post_type' => 'post',
'posts_per_page' => 5,
'meta_query' => array(
array(
'key' => 'related_post',
'value' => '"25"', /* include the double quotes in the search value */
'compare' => 'LIKE',
),
)
);
As the values in the serialised string becomes "25"; including the double quotes in the value you want to search for should work.
A post is created for each talent with a status of either coming-soon or in-town or others saved as meta_values. I needed to display posts first by "coming-soon" and then "intown" and then "others".
I realized that I was looking for orderby multiple meta_keys and found a solution here. I converted the syntax in order for it to work with pre_get_posts hook ( since it is main loop in category.php). As I need, code below mostly works and shows results ordered by coming-soon->in-town->others.
add_filter('pre_get_posts', 'pre_get_posts_hook' );
function pre_get_posts_hook($wp_query) {
if (is_category() && $wp_query->is_main_query()) {
$wp_query->set('meta_query',
array( 'relation' => 'OR',
'soon' => array( 'key' => 'coming_soon',
'value' => 'yes',
'compare' => '='
),
town' => array( 'key' => 'in-town',
'value' => 'positive',
'compare' => '='
),
'others' => array( 'key' => 'others',
'value' => 'null',
'compare' => '='
)
)
);
$wp_query->set('orderby', array('soon' => 'DESC', 'town' => 'DESC', 'others' => 'DESC'));
return $wp_query;
}
}
Now, I need to run a second level of orderby. I mean, with the code above, first I get the posts with meta_key coming-soon, I expect these posts to be again ordered by date_modified and possibly a control on their order eg. ASC, DESC. I am quite sure that it is possible. I just have no clue how do I nest it further.
Solved. I will leave the answer in case it may help someone in future. I had to replace this line.
$wp_query->set('orderby', array('soon' => 'DESC', 'town' => 'DESC', 'others' => 'DESC'));
with this line.
$wp_query->set('orderby', array('meta_value' => 'DESC', 'modified' => 'DESC' ));
I think the code is pretty self-explanatory. What it does is, it will allow you to run you primary-orderby and then once you get those results, you can run a secondar-orderby. Of course, the second associative array is not limited to modified, it can be any other parameters of orderby. Eg. title, author etc.
I'm trying to use a custom WP_Query but the results are not right.
I want to do is create a custom form to filter the Jobs registered with "WP Job Manager" using radius search.
This is my query:
$args = array(
'post_type' => 'job_listing',
'post_status' => array( 'publish' ),
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'geolocation_long',
'value' => array($maxLong,$minLong),
'compare' => 'between',
'type' => 'numeric',
),
array(
'key' => 'geolocation_lat',
'value' => array($maxLat,$minLat),
'compare' => 'between',
'type' => 'numeric',
),
),
);
$the_query = new WP_Query( $args );
Can you spot any issue?
Any help would be appreciated. Thank you!
This may be a problem with the compare BETWEEN feature. I would suggest you have a look at the exact query being generated and whether the compare is actually comparing floats, not strings (which might produce unexpected results).
Have a look at the troubleshooting done for a very similar query over on wordpress.stackexchange.com.
The following is quoted from the question:
Since postmeta values are stored as strings, I figured I should be casting to DECIMAL, but it just seems to trim the decimal value from the string due to the lack of DECIMAL arguments/precision parameters.
and review Rarst's answer:
You can filter generated SQL and add precision parameters that you need.
Enable filters for get_posts() by adding following to query:
'suppress_filters' => false,
And:
add_filter('get_meta_sql','cast_decimal_precision');
function cast_decimal_precision( $array ) {
$array['where'] = str_replace('DECIMAL','DECIMAL(10,3)',$array['where']);
return $array;
}
Notice OP's comment on this suggestion too though:
tried both solutions and it looks like it compares them as strings with single quotes (wp 3.1.1), any ideas on that? trying raw sql did work though.
Please update your question with further findings to enable us to help you out.
change $minlong and $maxlong
$args = array(
'post_type' => 'job_listing',
'post_status' => array( 'publish' ),
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'geolocation_long',
'value' => array($minLong,$maxLong),
'compare' => 'between',
'type' => 'numeric',
),
array(
'key' => 'geolocation_lat',
'value' => array($minLat,$maxLat),
'compare' => 'between',
'type' => 'numeric',
),
),
);
$the_query = new WP_Query( $args );
I am using Woocommerce, although my question relates to WP_Query in general. I am creating a custom WP_Query loop for bestselling products and I want to allow users to be able to sort the results by price, from high to low and low to high. The problem is in Woocommerce both _price and total_sales are meta fields and as far as I can tell I can only orderby 1 meta field in Wordpress loops. Is there a way around this?
My full code including some of my attempts is here, the most relevant code segment looks like as follows:
$queryArgs = array(
'post_type' => 'product',
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => '_visibility',
'value' => array('catalog', 'visible'),
'compare' => 'IN'
)
),
'meta_key' => '_price',
'orderby' => array('meta_value_num' => $sortBy['terms'])
);
The actual code is more complicated than this because it's built for a range of filtering and sorting options, but this is the gist of it and bestsellers is the only thing giving me issues because of the two meta_keys. I've read this but it doesn't apply to custom meta fields.
I've tried:
'meta_key' => '_price total_sales'
'meta_key => array('_price', 'total_sales')
'orderby' => array('meta_value_num' => $sortBy['terms'], 'meta_value_num' => 'DESC')
Nothing seems to work. I've also tried hooking onto the various WP_Query filters but the problem is this query is part of a dynamically generated loop so I can't 'hack' or hard-code anything.
Use the meta query with arrays:
'meta_query' => array (
array (
'key' => '_visibility',
'value' => array('catalog', 'visible'),
'compare' => 'IN'
),
array (
'key' => '_price',
'value' => "VALUE WHAT YOU WANT, NOT ASC/DESC",
)
),