I would like to create a WooCommerce plugin to add some offers for customers (that have a purchase History).
How can I check a user bought something before?
Thanks.
I would like to create a WooCommerce plugin to add some offers for customers (that have a purchase History).
How can I check a user bought something before?
Thanks.
Update: New updated improved, light and faster version HERE
Yes it is possible creating a conditional function that return
true
when a customer has already at least one order with status completed.
Here is the code for this conditional function:
function has_bought() {
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
// Count number of orders
$count = count( $customer_orders );
// return "true" when customer has already one order
if ( $count > 0 )
return true;
else
return false;
}
This code is tested and works.
This code goes in function.php file of your active child theme or theme, or in a plugin php file.
USAGE (as a condition):
References
Here is a much light and faster conditional function that will return true if a customer has already maid a purchase.
There is an optional argument $user_id
, that will allow you to specify a defined user ID:
function has_bought( $user_id = 0 ) {
global $wpdb;
$customer_id = $user_id == 0 ? get_current_user_id() : $user_id;
$paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$results = $wpdb->get_col( "
SELECT p.ID FROM {$wpdb->prefix}posts AS p
INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $paid_order_statuses ) . "' )
AND p.post_type LIKE 'shop_order'
AND pm.meta_key = '_customer_user'
AND pm.meta_value = $customer_id
" );
// Count number of orders and return a boolean value depending if higher than 0
return count( $results ) > 0 ? true : false;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on Woocommerce 3+ and works (It should work on previous versions too).
For multiple products: Check if a customer has purchased a specific products in WooCommerce
Usage example 1 (logged in customer)
if( has_bought() )
echo '<p>You have already maid a purchase</p>';
else
echo '<p>Welcome, for your first purchase you will get a discount of 10%</p>';
Usage example 2 (setting the $user_id)
// Define the user ID
$user_id = 85;
if( has_bought( $user_id ) )
echo '<p>customer have already maid a purchase</p>';
else
echo '<p>Customer with 0 purchases</p>';
If the $user_id
is not defined and the current user is not logged in, this function will return false
.
The code of this function is partially based on the built in WooCommerce function
wc_customer_bought_product
source code.
Simplified version:
function has_bought() {
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
// return "true" when customer has already one order
return count( $customer_orders ) > 0 ? true : false;
}
If Guest Checking is enabled the this function might help
Just send $customer_email as argument and function will check in all the orders for that email and return true or false.
function has_bought($customer_email){
$orders = get_posts(array(
'numberposts' => -1,
'post_type' => 'shop_order',
'post_status' => array('wc-processing', 'wc-completed'),
));
$email_array = array();
foreach($orders as $order) {
$order_obj = wc_get_order($order->ID);
$order_obj_data = $order_obj->get_data();
array_push($email_array, $order_obj_data['billing']['email']);
}
if (in_array($customer_email, $email_array)) {
return true;
} else {
return false;
}
}
Enhanced version with paid state or just status agnostic query, also improved a bit code typing, for PHP 5.4+ :
function has_bought(int $user_id = 0, bool $paid = true ) {
global $wpdb;
$user_id = (empty($user_id)) ? get_current_user_id() : $user_id;
$sql_str = "
SELECT p.ID FROM ".$wpdb->posts." AS p
INNER JOIN
".$wpdb->postmeta." AS pm ON p.ID = pm.post_id
WHERE
p.post_type LIKE 'shop_order'
AND pm.meta_key = '_customer_user'
AND pm.meta_value = %d
";
$args = [(int) $user_id];
if ($paid === true) {
$paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$sql_str .= "AND p.post_status IN ( 'wc-" . implode( "','wc-", $paid_order_statuses ) . "' )";
}
$sql = $wpdb->prepare($sql_str, $args);
return (bool) $wpdb->get_var( $sql );
}