In a plugin I'm trying to not letting users placing similar orders with same billing information.
Imagine a user with John Doe billing first name and last name has placed an order which contains product1 and product2 and someone else tries to place same or similar order (for example containing product1,product2, product3) with same billing first name and last name while the previous order is still under processing.
So in order to avoid this behavior I'm trying to validate orders before placement.
If there are any running orders with same billing info I throw a Woocommerce error but I don't know how can I make sure if last orders contain similar items too!
Here is my code:
function check_for_duplicate_order($data)
{
$data['billing_last_name'];
$data['billing_first_name'];
$data['billing_postcode'];
$meta_query_args = array(
'relation' => 'OR', // Optional, defaults to "AND"
array(
'key' => '_billing_postcode',
'value' => '%' . $data['_billing_postcode'],
'compare' => 'LIKE'
),
array(
'key' => '_billing_phone',
'value' => '%' . $data['billing_phone'],
'compare' => 'LIKE'
),
array(
'relation' => 'AND',
array(
'key' => '_billing_first_name',
'value' => $data['billing_first_name'],
'compare' => '='
),
array(
'key' => '_billing_last_name',
'value' => $data['billing_last_name'],
'compare' => '='
)
)
);
$query_params = [
'post_type' => 'shop_order',
'posts_per_page' => 1,
'post_status' => array('wc-pending','wc-processing','wc-on-hold'),
'meta_query' => $meta_query_args
];
$cart_items_ids = [];
global $woocommerce;
$items = $woocommerce->cart->get_cart();
foreach($items as $item => $values) {
$cart_items_ids[] = $values['data']->get_id();
}
}
add_action('woocommerce_after_checkout_validation', 'check_for_duplicate_order');
In above code I get current order billing info, then finding other active orders with same billing info but from this point I don't know How can get found orders items and see if in previous orders there are same items too.
I managed to find a solution to match items in current cart with items in previous orders :
foreach ($billing_active_order_ids as $active_order_id){
$order = wc_get_order( $active_order_id );
foreach ($order->get_items() as $id => $order_item){
if(in_array($order_item->get_product_id(),$cart_items_ids)){
wc_add_notice($duplicate_order_message, 'error');
return;
}
}
}
Related
I'm having an issue with comparing values between two arrays in wp_query
I have the two roles administrator and forhandler_salg ($roles returns an array with these two values), but it only queries posts with the "public" key set to true
I got more posts when I changed the "allowed_userroles" key compare value to "LIKE", but those aren't the right posts
$roles = "";
if (is_user_logged_in()) {
$user = wp_get_current_user();
$roles = (array) $user->roles;
}
$args = array(
'post_type' => 'downloads',
'posts_per_page' => '-1',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'public',
'value' => true,
'compare' => '=',
),
# Not working
array(
'key' => 'allowed_userroles',
'value' => $roles,
'compare' => 'IN',
),
),
);
print_r($args) returns
Array
(
[post_type] => downloads
[posts_per_page] => -1
[meta_query] => Array
(
[relation] => OR
[0] => Array
(
[key] => public
[value] => 1
[compare] => =
)
[1] => Array
(
[key] => allowed_userroles
[value] => Array
(
[16] => administrator
[17] => forhandler_salg
)
[compare] => IN
)
)
)
And a post with the "public" custom field as true and some added roles returns this, when I print_r() the allowed_userroles for the post:
Array
(
[0] => role1
[1] => role2
[2] => role3
)
How would I go about checking if allowed_userroles in the query has values that are also present in $roles?
EDIT: "like" works if I put in a role manually
Ok, for these kinds of problems, it's easier to start with your basic array of arguments and then modify it.
Since this question is tagged with ACF, ACF is likely storing this as a single meta entry. Furthermore, if this is an array of values, ACF is very likely storing it as a serialized PHP string in the database (e.g., a:2:{i:0;s:4:"1234";i:1;s:3:"qed";}).
Let's start with the base code:
$roles = [];
if (is_user_logged_in()) {
$user = wp_get_current_user();
$roles = (array) $user->roles;
}
$args = array(
'post_type' => 'downloads',
'posts_per_page' => -1,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'public',
'value' => "1",
'compare' => '=',
),
),
);
In this case, you'll need to use a LIKE to attempt a sub-string match.
foreach($roles as $role) {
$args['meta_query'][] = [
'key' => 'allowed_userroles',
'value' => $role, // can't remember if wp will wrap value with %
'compare' => 'LIKE',
];
}
Ideally, you'd want to match based on the string length as well, but that might be a bit prohibitive. If you keep running into issues getting the exact results out, you could run two separate queries. The first query would be for all public items, and the second query would be for non-public items. You could then take the results of the second query and then filter out values that do not have the correct meta, since it'll be easier to process using get_field('allowed_userroles').
I'm running a query on users and want to include only users who have meta data (page_history) with a specific value. The problem I'm having is that the meta data is an object, and I can't seem to get the query to check the value of the object:
$role = isset($_GET['role'] && $_GET['role'] !== '');
$args = array(
'role' => $role ?? '',
'orderby' => 'user_nicename',
'order' => 'ASC',
'meta_query' => array(
'relation' => 'OR',
$search_term[0] ? array(
'key' => 'first_name',
'value' => $search_term[0],
'compare' => 'LIKE'
) : '',
$search_term[1] ? array(
'key' => 'last_name',
'value' => $search_term[1],
'compare' => 'LIKE'
) : '',
array(
'key' => 'page_history',
'value' => 'custom_post_type',
'compare' => 'EXISTS'
)
),
);
$users = get_users($args);
foreach ($users as $user) {
// Do stuff
}
Here is my meta object:
Array
(
[date] => 1655387457
[post-type] => custom_post_type
[page] => Page title here
)
So I just want to get users if they have the meta data page_history set as 'custom_post_type'.
Thank you
This meta object will be serialized before being stored in the database column.
The post-type field after serialization will be like that in DB s:9:"post-type";s:16:"custom_post_type";
You can use LIKE compare to filter it.
array(
'key' => 'page_history',
'value' => 's:9:"post-type";s:16:"custom_post_type";',
'compare' => 'LIKE'
)
You will need to change the number 16 to the custom post type name count.
I need to include children comments (replies) to comments which I'm filtering with a meta query.
If I'm filtering comments that have a rating 3/5, I need to include their children with the query (even though the children don't match the meta query).
$comments = get_comments( array (
//'meta_key' => 'rating',
'order' => 'ASC',
'orderby' => 'date',
'post_id' => $_POST['post_id'],
'status' => 'approve',
'meta_query' => array(
array(
'key' => 'rating',
'value' => $_POST['rating']
)
)
) );
Is there a way to "force include" children that don't match initial query?
(To see the issue live, try to filter the reviews by 3 stars on this page, and notice how the review reply is not included in the filter: https://herbalnitro.com/product/extreme-energy/)
The issue that you get the only comment with specific meta but children comments do not inherit this meta obviously. So you need to do it in two steps: 1) get comments with meta. 2) get children comments for a parent with which is with meta.
// get comments with meta
$comments = get_comments( array (
'order' => 'ASC',
'orderby' => 'date',
'post_id' => $_POST['post_id'],
'status' => 'approve',
'meta_query' => array(
array(
'key' => 'rating',
'value' => $_POST['rating']
)
)
) );
// find children comments
$comments_children = array();
foreach ( $comments as $comment ) {
$comments_children += get_comments(array('parent' => $comment->comment_ID, 'status' => 'approve', 'hierarchical' => true));
}
// combine all comments
$comments = array_merge($comments, $comments_children);
// print comments template if needed
wp_list_comments(array(), $comments);
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
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
)