1
votes

Case:

In checkout packages are splited by shipping class of products (different brands). Every package have own shipping method that customer can choose.

And finally when customer make an order I need to store chosen shipping method for every product in meta_data so I can see it in order details on admin panel and for the RESTAPI (I use some external services to manage orders).

I tried something like this but I know this is mess, I don't understand how to handle session data and store it in order data.

  add_action( 'woocommerce_checkout_create_order_shipping_item', 'order_shipping_item', 20, 4 );
  function order_shipping_item($cartItemData,$order){

    foreach ( WC()->cart->get_shipping_packages() as $package_id => $package ) {
        // Check if a shipping for the current package exist
        if ( WC()->session->__isset( 'shipping_for_package_'.$package_id ) ) {
            // Loop through shipping rates for the current package
            foreach ( WC()->session->get( 'shipping_for_package_'.$package_id )['rates'] as $shipping_rate_id => $shipping_rate ) {
                $method_id   = $shipping_rate->get_method_id(); // The shipping method slug
                $instance_id = $shipping_rate->get_instance_id(); // The instance ID
                $label_name  = $shipping_rate->get_label(); // The label name of the method

            }
        }
        foreach ($package['contents'] as $item) {
          $item->add_meta_data('_shipping_method',$label_name);
          # code...
        }
    }
  }

Right now I have no idea how to achieve this, any clues? help!

1

1 Answers

2
votes

Here is the way to save as custom order item meta data the chosen shipping method details for each order item:

// Custom function that get the chosen shipping method details for a cart item
function get_cart_item_shipping_method( $cart_item_key ){
    $chosen_shippings = WC()->session->get( 'chosen_shipping_methods' ); // The chosen shipping methods
    
    foreach( WC()->cart->get_shipping_packages() as $id => $package ) {
        $chosen = $chosen_shippings[$id]; // The chosen shipping method
        if( isset($package['contents'][$cart_item_key]) && WC()->session->__isset('shipping_for_package_'.$id) ) {
            return WC()->session->get('shipping_for_package_'.$id)['rates'][$chosen];
        }
    }
}

// Save shipping method details in order line items (product) as custom order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'add_order_line_item_custom_meta', 10, 4 );
function add_order_line_item_custom_meta( $item, $cart_item_key, $values, $order ) {
    // Load shipping rate for this item
    $rate = get_cart_item_shipping_method( $cart_item_key );

    // Set custom order item meta data
    $item->update_meta_data( '_shipping_rate_id', $rate->id ); // the shipping rate ID
    $item->update_meta_data( '_shipping_rate_method_id', $rate->method_id ); // the shipping rate method ID
    $item->update_meta_data( '_shipping_rate_instance_id', (int) $rate->instance_id ); // the shipping rate instance ID
    $item->update_meta_data( '_shipping_rate_label', $rate->label ); // the shipping rate label
    $item->update_meta_data( '_shipping_rate_cost', wc_format_decimal( (float) $rate->cost ) ); // the shipping rate cost
    $item->update_meta_data( '_shipping_rate_tax', wc_format_decimal( (float) array_sum( $rate->taxes ) ) ); // the shipping rate tax
}

Code goes in functions.php file of your active child theme (or active theme). Tested and works.