zen
zen

Reputation: 1165

Calculate shipping methods/rates within an existing order in WooCommerce

I am essentially trying to replicate functionality like on the cart page where a user can add their zip code and it calculates available shipping rates, but I'm trying to do it from the back-end from within an already-created order.

I could not find a way to do it directly from WC_Order instance, so the next best thing I have is do clear cart session, add all items from within order to the cart session, and then try to calculate it.

Here's what I have so far. I'm always stuck on how to calculate the rates for the entire order.

$order_id       = isset($_POST['order_id'])?$_POST['order_id']:0;
$country        = isset($_POST['country'])?$_POST['country']:0;
$state          = isset($_POST['state'])?$_POST['state']:0;
$postcode       = isset($_POST['postcode'])?$_POST['postcode']:0;
$city           = isset($_POST['city'])?$_POST['country']:0;
$order          = wc_get_order( $order_id );
$order_items    = $order->get_items();

// Don't know if this would save country of logged in user, or only create a temporary guest user session which is what I'd need
if ( $country != '' ) {
    WC()->customer->set_billing_location( $country, $state, $postcode, $city );
    WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
} else {
    WC()->customer->set_billing_address_to_base();
    WC()->customer->set_shipping_address_to_base();
}

// Remove all current items from cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
    WC()->cart->empty_cart();
}

// Add all items from the order to the cart
foreach ($order_items as $order_item) {
    WC()->cart->add_to_cart($order_item['product_id'], $order_item['qty']);
}

$totals = WC()->shipping->get_packages();

// $totals returns rates but I believe it is per each "package". It's not a cumulative rate like the cart page shows.

Upvotes: 7

Views: 5440

Answers (3)

Abhishek
Abhishek

Reputation: 173

Note: this is not an answer, I can't comment hence I'm writing here. In my case, there is a problem with the accepted answer:

If the customer has already added some items in the cart they will be lost because of the following line of code:

WC()->cart->empty_cart()

and instead, the cart is filled by the items in the past order.

So far it seems like using the cart is necessary to perform the properly calculate the shipping packages. If so is there a way I can create a clone of the current cart and then calculate the shipping packages? I don't want to affect my customer's original cart when doing this calculation.

Upvotes: 0

zen
zen

Reputation: 1165

Ok so thanks to @mujuonly, I was able to figure it out.

Here's how to get all calculated shipping rates, the same way it's shown on the cart page.

// Post variables
$order_id   = isset($_POST['order_id'])?$_POST['order_id']:0;
$country    = isset($_POST['country'])?$_POST['country']:0;
$state      = isset($_POST['state'])?$_POST['state']:0;
$postcode   = isset($_POST['postcode'])?$_POST['postcode']:0;
$city       = isset($_POST['city'])?$_POST['city']:0;

// Order and order items
$order          = wc_get_order( $order_id );
$order_items    = $order->get_items();

// Reset shipping first
WC()->shipping()->reset_shipping();

// Set correct temporary location
if ( $country != '' ) {
    WC()->customer->set_billing_location( $country, $state, $postcode, $city );
    WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
} else {
    WC()->customer->set_billing_address_to_base();
    WC()->customer->set_shipping_address_to_base();
}

// Remove all current items from cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
    WC()->cart->empty_cart();
}

// Add all items to cart
foreach ($order_items as $order_item) {
    WC()->cart->add_to_cart($order_item['product_id'], $order_item['qty']);
}

// Calculate shipping
$packages = WC()->cart->get_shipping_packages();
$shipping = WC()->shipping->calculate_shipping($packages);
$available_methods = WC()->shipping->get_packages();

$available_methods[0]['rates'] will have all the shipping rates that are available to that location for products inside the order.

Upvotes: 8

BA_Webimax
BA_Webimax

Reputation: 2679

Try using:

// Calculate totals
WC()->cart->calculate_totals();
WC()->cart->calculate_shipping();

// Retrieve the shipping total
$shipping_total = WC()->cart->get_shipping_total();

The WC_Cart class should have all of the methods you would need to recreate any cart functionality you might need. I suggest that you should read through and familiarize yourself with the class definition here...

https://docs.woocommerce.com/wc-apidocs/class-WC_Cart.html

Upvotes: 3

Related Questions