Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking if customer has already bought something in WooCommerce

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.

like image 319
Mosi Avatar asked Aug 10 '16 13:08

Mosi


2 Answers

2021 UPDATE - Handling guests "billing email" - Improved and secured SQL query

Here is a much light and faster conditional function that will return true if a customer has already made a purchase.

It handles registered users guest from their user ID and guests from their billing email:

  • For registered users: If the optional argument is not set with a user ID, the current user id will be used.
  • For guests: the billing email will be required as an argument in the function.

This lighter and improved function (based partially on wc_customer_bought_product() function source code) will return a boolean value based on orders count (false for O orders and true when there is at least one paid order):

function has_bought( $value = 0 ) {
    if ( ! is_user_logged_in() && $value === 0 ) {
        return false;
    }

    global $wpdb;
    
    // Based on user ID (registered users)
    if ( is_numeric( $value) ) { 
        $meta_key   = '_customer_user';
        $meta_value = $value == 0 ? (int) get_current_user_id() : (int) $value;
    } 
    // Based on billing email (Guest users)
    else { 
        $meta_key   = '_billing_email';
        $meta_value = sanitize_email( $value );
    }
    
    $paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );

    $count = $wpdb->get_var( $wpdb->prepare("
        SELECT COUNT(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 = '%s'
        AND pm.meta_value = %s
        LIMIT 1
    ", $meta_key, $meta_value ) );

    // Return a boolean value based on orders count
    return $count > 0;
}

Code goes in functions.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 user has purchased specific products in WooCommerce


Usage example 1 (logged in customer)

if( has_bought() )
    echo '<p>You have already made 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 made 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.

Usage example 3 - For guests (setting the billing email)

// Define the billing email (string)
$email = '[email protected]';

if( has_bought( $email ) )
        echo '<p>customer have already made a purchase</p>';
    else
        echo '<p>Customer with 0 purchases</p>'

The code of this function is partially based on the built in WooCommerce function wc_customer_bought_product() source code.

like image 152
LoicTheAztec Avatar answered Oct 10 '22 16:10

LoicTheAztec


You can use built-in woocommerce order query to query by email/phone/etc...

$args = [
    //'customer_id' => $user_id, // can used for query by users
    'billing_phone'  => $phone, // you can also query by 'billing_email', 'billing_first_name' and etc.
    'status' => ['wc-processing', 'wc-completed'],
    'limit' => -1,
];

$query = new WC_Order_Query($args);
$orders = $query->get_orders();

return count($orders) > 1 ? true : false;

more details for WC_Order_Query found here: https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query

like image 41
Guy Ytzhak Avatar answered Oct 10 '22 16:10

Guy Ytzhak