6

I've been trying numerous solutions to programmatically set the price of shipping (per order) via Woocommerce. I'm having no luck

I have tried overwriting the meta value for the item:

            update_post_meta( $woo_order_id, '_order_shipping', $new_ship_price );

Also tried something along the lines of this [Question/Answer][1]

                    $item_ship = new WC_Order_Item_Shipping();

                    $item_ship->set_name( "flat_rate" );
                    $item_ship->set_amount( $new_ship_price );
                    $item_ship->set_tax_class( '' );
                    $item_ship->set_tax_status( 'none' );


                    // Add Shipping item to the order
                    $order->add_item( $item_ship );

But neither seem to work. Any pointers most welcome.


Similar thread: Add a fee to an order programmatically in Woocommerce 3

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Callum
  • 554
  • 2
  • 7
  • 18

1 Answers1

21

To handle this in Woocommerce 3+ use the following (from a WC_Order Order object $order):

## ------------- ADD SHIPPING PROCESS ---------------- ##

// Get the customer country code
$country_code = $order->get_shipping_country();

// Set the array for tax calculations
$calculate_tax_for = array(
    'country' => $country_code,
    'state' => '', // Can be set (optional)
    'postcode' => '', // Can be set (optional)
    'city' => '', // Can be set (optional)
);

// Optionally, set a total shipping amount
$new_ship_price = 5.10;

// Get a new instance of the WC_Order_Item_Shipping Object
$item = new WC_Order_Item_Shipping();

$item->set_method_title( "Flat rate" );
$item->set_method_id( "flat_rate:14" ); // set an existing Shipping method rate ID
$item->set_total( $new_ship_price ); // (optional)
$item->calculate_taxes($calculate_tax_for);

$order->add_item( $item );

$order->calculate_totals();

$order->update_status('on-hold');

// $order->save(); // If you don't update the order status

Tested an works.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Beautiful. Thank you once again for your help, so clear and concise. – Callum Dec 07 '18 at 17:49
  • @LoicTheAztec I was searching this code. Really superb man! 100% worked. – Nidhishanker Modi Jul 16 '20 at 11:20
  • Is it also possible to replace a shipping method? I have try this but now I get 2 shipping methods on each order `function myfunc($order_id){ $order = wc_get_order( $order_id ); $item = new WC_Order_Item_Shipping(); $item->set_method_title( "Ophalen" ); $item->set_method_id( "local_pickup:2" ); $order->remove_item('flat_rate:1'); $order->add_item( $item ); $order->save(); } add_action( 'woocommerce_checkout_order_processed', 'myfunc');` – Jop Mar 11 '21 at 12:30
  • @Jop Get the data from the shipping method you want to change, to insert it as a new one( with your changes), then remove the old one before inserting the new one. It's easier this way. – LoicTheAztec Mar 11 '21 at 12:32
  • Great, this is what I needed for my unit testing. When you say: $item->set_method_id( "flat_rate:14" ); // set an existing Shipping method rate ID How can I add a shipping method? In my unit test I do not have a shimming method defined. – StR May 12 '21 at 20:27