skip to Main Content

I need to change the normal behavior of the place_order button at checkout: if there’s already an order which is not completed (status = processing), WooCommerce should add items to that order instead of creating a new one. Otherwise, it should create a new order in the default way.

function custom_order() {
    $user_role = wp_get_current_user()->roles[0];
        
    $customer = new WC_Customer($user_id);
    $last_order = $customer->get_last_order();
        
    $last_order_id = $last_order->get_id();
    $last_order_data = $last_order->get_data();
    $last_order_status = $last_order->get_status();
                
    if ( $user_role === "administrator" ) {
        if ($last_order_status === "processing") {          
            foreach ( WC()->cart->get_cart() as $cart_item ) {
                $product = $cart_item['data'];
                $product_id = $product->get_id();
                $quantity = $product->get_quantity();
    
                $last_order->add_product($product, $quantity);
            }
        }

        else {
            // do the normal thing
        }
    }
}

I’ve tried the following hooks:

add_action('woocommerce_new_order', 'custom_order', 10, 3);
add_filter('woocommerce_create_order', 'custom_order', 10, 2);

Which is the right one and how to add this new condition to the default order function?

2

Answers


  1. add_filter('woocommerce_create_order', 'create_or_update_order', 10, 2);
    
    function create_or_update_order() {
        $user_obj = wp_get_current_user();
    
        $user_role = $user_obj->roles[0];
        $user_id = $user_obj->ID;
        $customer = new WC_Customer($user_id);
        $last_order = $customer->get_last_order();
        $last_order_id = $last_order->get_id();
        $last_order_data = $last_order->get_data();
        $last_order_status = $last_order->get_status();
    
        if ('administrator' === $user_role) {
            if ('processing' === $last_order_status) {
                foreach (WC()->cart->get_cart() as $cart_item) {
    
                    $product = $cart_item['data'];
                    $product_id = $product->get_id();
                    $quantity = $cart_item['quantity'];
    
                    $last_order->add_product($product, $quantity);
                }
              return $last_order_id;
            } else {
                return null;
            }
        }
        return null;
    }
    

    Inside the class class-wc-checkout.php, the create_order function provides a hook just before creating the order. It will not create another order if the order ID already exist. We will return the order ID if the conditions met.

    public function create_order( $data ) {
        // Give plugins the opportunity to create an order themselves.
        $order_id = apply_filters( 'woocommerce_create_order', null, $this );
        if ( $order_id ) {
            return $order_id;
        }......
    
    Login or Signup to reply.
  2. The woocommerce_create_order filter hook is indeed the right hook to use for your question.

    However, when just using $last_order->add_product( $product, $quantity ); you will notice 2 issues

    • When a product already exists in the last order, the function adds a new line instead of just increasing the quantity of the existing product
    • Totals are not recalculated and are therefore displayed incorrectly

    So what you need to do is, in addition to loop through the cart items, also loop through the existing order items and compare them.

    If the item already exist, update the item, if not, add the item to the order

    The second param $checkout enable you to compare and adjust billing information and such if desired

    So you get:

    function filter_woocommerce_create_order( $null, $checkout ) {
        // Get current user role
        $user = wp_get_current_user();
        $roles = ( array ) $user->roles;
    
        // Check user role
        if ( in_array( 'administrator', $roles ) ) {
            // Get last order
            $customer = new WC_Customer( get_current_user_id() );
            $last_order = $customer->get_last_order();
    
            // IS WC_Order
            if ( is_a( $last_order, 'WC_Order' ) ) {
                // Compare status
                if ( $last_order->get_status() == 'processing' ) {
                    // Get cart items quantities
                    $cart_item_quantities = WC()->cart->get_cart_item_quantities();
    
                    // Loop through last order
                    foreach ( $last_order->get_items() as $item ) {
                        // Get product id
                        $item_product_id = $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id();
    
                        // Product already exists in last order, update the product quantity
                        if ( array_key_exists( $item_product_id, $cart_item_quantities ) ) {
                            // Get order item quantity
                            $order_item_quantity = $item->get_quantity();
    
                            // Get order item price
                            $order_item_price = $last_order->get_item_subtotal( $item, true, false );
    
                            // Get cart item quantity
                            $cart_item_quantity = $cart_item_quantities[$item_product_id];
    
                            // Calculate new quantity
                            $new_quantity = $order_item_quantity + $cart_item_quantity;
                            
                            // The new line item price
                            $new_line_item_price = $order_item_price * $new_quantity;
    
                            // Update order item quantity
                            $item->set_quantity( $new_quantity );
                            
                            // Set the new price
                            $item->set_subtotal( $new_line_item_price ); 
                            $item->set_total( $new_line_item_price );
    
                            // Make new taxes calculations
                            $item->calculate_taxes();
    
                            // Save line item data
                            $item->save();
    
                            // Remove from array
                            unset( $cart_item_quantities[$item_product_id] );
                        }
                    }
    
                    // Then loop through remaining cart items
                    foreach ( $cart_item_quantities as $key => $cart_item_quantity ) {
                        // Product does not exist in last order, add the product
                        $last_order->add_product( wc_get_product( $key ), $cart_item_quantity );
                    }
    
                    // Recalculate and save
                    $last_order->calculate_totals();
    
                    // Return last order ID
                    return $last_order->get_id();
                }
            }
        }
    
        return $null;
    }
    add_filter( 'woocommerce_create_order', 'filter_woocommerce_create_order', 10, 2 );
    

    Related: Split a WooCommerce order and create a new order if the original order has products in backorder

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search