Search code examples
phpwordpresswoocommercecartshipping-method

Change shipping class based on cart items shipping class count in Woocommerce


I'm having trouble with the default WooCommerce shipping class settings. We have a small webshop with 2 shipping costs. One for products that fit in the mailbox, and other that don't.

We would like to make a setting that if there are 2 products with mailbox shipping class, than the price becomes a package price.

Now on default WooCommerce only charges 1x the mailbox shipping class.


Solution

  • First you will need to make your shipping settings as in the below screen, for "Flat rate" shipping method and only one shipping class named "Mailbox" (setting the desired amounts for "Mailbox" or No shipping class):

    enter image description here

    So some of your products will have the "Mailbox" shipping class and all others no shipping class. The products without shipping class (No shipping class) will be your "package.

    The following code will remove the cart items shipping class, if there is more than one item with the "Mailbox" shipping class:

    // Updating cart item price
    add_action( 'woocommerce_before_calculate_totals', 'change_change_shipping_class', 30, 1 );
    function change_change_shipping_class( $cart ) {
        if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) )
            return;
    
        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
            return;
    
        // HERE define your shipping class SLUG
        $mailbox_shipping_class = 'mailbox';
    
        $mailbox_count = 0;
    
        // 1st cart item Loop: Counting "mailbox" shipping classes cart items
        foreach ( $cart->get_cart() as $cart_item ) {
            // Set the new price
            if( $cart_item['data']->get_shipping_class() == $mailbox_shipping_class ) {
                $mailbox_count += $cart_item['quantity'];
            }
        }
    
        // If there is more than one item we continue
        if( $mailbox_count <= 1 )
            return; // Exit
    
        // 2nd cart item Loop: Reset the cart items with shipping class "mailbox"
        foreach ( $cart->get_cart() as $cart_item ) {
            if(  $cart_item['data']->get_shipping_class() == $mailbox_shipping_class ){
                $cart_item['data']->set_shipping_class_id('0');
            }
        }
    }
    

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