Search code examples
phpwordpresswoocommerceordersshipping-method

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.

Solution

  • 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.