Search code examples
phpwordpresswoocommercehook-woocommerceorders

Link newly created split order to the customer from the original order in WooCommerce


I am using a nifty piece of code to split an order if it contains any backordered products from Split a WooCommerce order and create a new order if the original order has products in backorder answer code. This works great to create the second order at checkout, but the new order does not link to the user, instead, the order Customer is Guest.

How do I set the newly created order Customer to the user when the order is created?

function sa_woocommerce_checkout_order_on_backorder( $order_id, $posted_data, $order ) {
    // Initialize
    $check_for_back_orders = false;

    // Loop through order items
    foreach ( $order->get_items() as $item_key => $item ) {
        // Get product
        $product = $item->get_product();

        // Product is on backorder
        if ( $product->is_on_backorder() ) {
            // Will only be executed once if the order contains back orders
            if ( $check_for_back_orders == false ) {
                $check_for_back_orders = true;

                // Create new order with backorders
                $backorder_order = wc_create_order();
            }

            // Add product to 'backorder' order
            $backorder_order->add_product( $product, $item['quantity'] );

            // Delete item from original order
            $order->remove_item( $item->get_id() );
        }
    }

    // If current order contains backorders, retrieve the necessary data from the existing order and apply it in the new order
    if ( $check_for_back_orders ) {
        // Recalculate and save original order
        $order->calculate_totals();
        $order->save();
        
        // Obtain necessary information
        // Get address
        $address = array(
            'first_name' => $order->get_billing_first_name(),
            'last_name'  => $order->get_billing_last_name(),
            'email'      => $order->get_billing_email(),
            'phone'      => $order->get_billing_phone(),
            'address_1'  => $order->get_billing_address_1(),
            'address_2'  => $order->get_billing_address_2(),
            'city'       => $order->get_billing_city(),
            'state'      => $order->get_billing_state(),
            'postcode'   => $order->get_billing_postcode(),
            'country'    => $order->get_billing_country()
        );

        // Get shipping
        $shipping = array(
            'first_name' => $order->get_shipping_first_name(),
            'last_name'  => $order->get_shipping_last_name(),
            'address_1'  => $order->get_shipping_address_1(),
            'address_2'  => $order->get_shipping_address_2(),
            'city'       => $order->get_shipping_city(),
            'state'      => $order->get_shipping_state(),
            'postcode'   => $order->get_shipping_postcode(),
            'country'    => $order->get_shipping_country()
        );
        
        // Get order currency
        $currency = $order->get_currency();

        // Get order payment method
        $payment_gateway = $order->get_payment_method();
        
        // Required information has been obtained, assign it to the 'backorder' order
        // Set address
        $backorder_order->set_address( $address, 'billing' );
        $backorder_order->set_address( $shipping, 'shipping' );

        // Set the correct currency and payment gateway
        $backorder_order->set_currency( $currency );
        $backorder_order->set_payment_method( $payment_gateway );

        // Calculate totals
        $backorder_order->calculate_totals();

        // Set order note with original ID
        $backorder_order->add_order_note( 'Automated backorder. Created from the original order ID: ' . $order_id );

        // Optional: give the new 'backorder' order the correct status
        $backorder_order->update_status( 'processing' );
    }
}
add_action( 'woocommerce_checkout_order_processed', 'sa_woocommerce_checkout_order_on_backorder', 10, 3 );

Solution

  • In wc_create_order() function, you can define the customer ID (and the parent order) like:

    // Create new order with backorders
    $backorder_order = wc_create_order( array(
        'customer_id' => $order->get_user_id(),
        'parent'      => $order_id,
    ) );
    

    This way the created order will be linked to the user, so not anymore "guest".

    I have also simplified your current code. Try the following instead:

    add_action( 'woocommerce_checkout_order_processed', 'split_checkout_order_with_backorder_items', 10, 3 );
    function split_checkout_order_with_backorder_items( $order_id, $posted_data, $order ) {
        $last_order_id = false; // Initialize
    
        // Loop through order items
        foreach ( $order->get_items() as $item_id => $item ) {
            $product = $item->get_product(); // Get the product object
    
            // Is item is on backorder?
            if ( $product->is_on_backorder() ) {
                // Create new order with the backorder item
                $sub_order = wc_create_order( array(
                    'customer_id' => $order->get_user_id(),
                    'parent'      => $order_id,
                ));
    
                $sub_order->add_product( $product, $item->get_quantity() ); // Add item on newly created order
                $order->remove_item( $item_id ); // Remove item from current Order
    
                $last_order_id = $sub_order->get_id(); // Set the sub order ID
    
                $sub_order->set_currency( $order->get_currency() );
                $sub_order->set_payment_method( $order->get_payment_method() );
    
                $sub_order->set_address( $order->get_address('billing'), 'billing' );
                $sub_order->set_address( $order->get_address('shipping'), 'shipping' );
    
                $sub_order->add_order_note( sprintf( __('Automated backorder. Created from the original order ID: %d'), $order_id ) );
    
                // Calculate totals, set status and save
                $sub_order->calculate_totals();
                $sub_order->update_status( 'processing' );
            }
        }
    
        // If current order had backordered items
        if ( $last_order_id ) {
            // Set the last order ID as user metadata
            if ( $user_id = $order->get_user_id() ) {
                update_user_meta( $user_id, '_last_order', $last_order_id );
            }
    
            // Recalculate and save current order
            $order->calculate_totals();
            $order->save();
        }
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.