Reputation: 1165
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
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
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
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