Search code examples
phpwordpresswoocommerceproductcart

Add a Shipping Class to WooCommerce product created dynamically on add to cart


We have a product creation wizard outside WooCommerce. When the product is added to the cart I want to add a shipping class based on the product dimensions.

I have this in custom-functions.php

function add_shipping_class_to_cart_item( $cart_item_data, $product_id, $variation_id )
{

    //snip conditionals
    $cart_item_data['shipping_class'] = 'test-small';

    return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_shipping_class_to_cart_item', 10, 3 );

Classes are set up in Shipping > Classes with the correct slug (test-small) and in the Shipping Method for the zone, in the Shipping class costs section.

I don't see the price change in the cart though. Maybe the shipping class can't be added like this?


Solution

  • To make your code work, you also need the following hooked function:

    add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_shipping_class', 30, 1 );
    function change_cart_item_shipping_class( $cart ) {
        if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) )
            return;
    
        // Loop through cart items
        foreach ( $cart->get_cart() as $item ) {
            // Check for 'shipping_class' custom cart item data
            if( isset($item['shipping_class']) && !empty($item['shipping_class']) ) {
                // Get the shipping class term Id from the term slug
                $term_id = get_term_by('slug', $item['shipping_class'], 'product_shipping_class')->term_id;
                // Set cart item shipping class ID
                $item['data']->set_shipping_class_id($term_id);
            }
        }
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). It should work.


    Now you could set directly in your function the shipping Class term Id instead of the slug like:

    add_filter( 'woocommerce_add_cart_item_data', 'add_shipping_class_as_custom_cart_item_data', 10, 3 );
    function add_shipping_class_as_custom_cart_item_data( $cart_item_data, $product_id, $variation_id )
    {
    
        //snip conditionals
        $cart_item_data['shipping_class_id'] = 33; // <== Here set the correct shipping class ID
    
        return $cart_item_data;
    }
    

    And then you will use instead:

    add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_shipping_class', 30, 1 );
    function change_cart_item_shipping_class( $cart ) {
        if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) )
            return;
    
        // Loop through cart items
        foreach ( $cart->get_cart() as $item ) {
            // Check for 'shipping_class_id' custom cart item data
            if( isset($item['shipping_class_id']) && !empty($item['shipping_class_id']) ) {
                // Set cart item shipping class ID
                $item['data']->set_shipping_class_id($item['shipping_class_id']);
            }
        }
    }
    

    It should also work.

    Related: WooCommerce: Change Shipping Class conditionally for specific Zone