2
votes

I am trying to automatically add a product to an order in WooCommerce if the customer is a new one. I am using "Checking if customer has already bought something in WooCommerce" answer code to check if the customer has already completed an order and add the product to his current order. I think this should be just before the confirmation page but cannot make it work.

// Check if user has already bought

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
    " );
}

if( has_bought() )

function add_the_product() 
{   
   $order_id = intval($_POST['order_id']);

   $product_id = intval($_POST['product_id']);

   //getting order Object
   $order = wc_get_order($order_id); 

   // gettting the product
   $product = wc_get_product($product_id);

   $back_data = array('error' => 0, 'msg' => '');
   if($order !== false AND $product !== false)
   {   
       // Add the product to the order 
       $order->add_product($product, 1);

       // Save the order data
       $order->save(); 
1
Please note that I have answered first to your question, my answer code is based on your question code and it works. So the rule in StackOverFlow when people answer your question is to accept the first working answer. You didn't ask in your question about guests, but about customers (which are registered as "customer" user role).LoicTheAztec

1 Answers

1
votes

You can't get the current user ID using get_current_user_id(). Instead you will better get the user ID from the existing order (where you want to add a product).

Update: I have updated my original function has_bought() to handle guest customer orders from their billing email. Now as you don't ask in your question to handle guests, I haven't implemented that on the following answer.

// Check if user has already bought
function has_bought( $value = 0 ) {
    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() );

    print_pr($meta_key); print_pr($meta_value);

    $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
    ", $meta_key, $meta_value ) );

    // Return a boolean value based on orders count
    return $count > 0 ? true : false;
}

Here is your revisited function code:

function add_the_product() 
{   
    // Checking posted data
    if( ! ( isset($_POST['order_id']) && isset($_POST['product_id']) ) )
        return; // Exit

    $order_id   = intval($_POST['order_id']);
    $product_id = intval($_POST['product_id']);

    // Getting the order Object
    $order = wc_get_order($order_id); 

    // Getting the product Object
    $product = wc_get_product($product_id);

    $back_data = array('error' => 0, 'msg' => '');

    // Checking order and product objects
    if( ! is_a($order, 'WC_Order') || ! is_a($product, 'WC_Product') )
        return; // Exit

    // Checking that customer has not already bought something
    if( has_bought( $order->get_customer_id() ) )
        return; // Exit

    // Add the product to the order 
    $order->add_product($product, 1);

    // Calculate totals and save order data
    $order->calculate_totals(); // the save() method is included
}

It should better work now.