Search code examples
phpwordpresswoocommercecountry

Custom free shipping for only UK and a specific product in Woocommerce 3


I have been trying to create a Free Shipping option for a client's promotional product that will be shipped worldwide but will only have Free Shipping option for orders from the UK. So when someone orders from the USA or Hong Kong, the usual rate will be applied. But somehow, I can't exclude these countries from Shipping Class. (I am not using Free Shipping Method because when I try, it applies to all products, that's why I created a Shipping Class for this)

Can someone help me with this?

Thanks a lot


Solution

  • You don't need to use shipping methods on your specific product for that particular case. Instead this custom function below will do the trick, defining your specific product id in it.

    When a customer from UK adds only your specific product to cart, the code will rename your flat rate shipping method to "Free shipping" setting the cost to ZERO.

    To test that code, you should first enable the debug mode in Woocommerce shipping settings under "Shipping options" tab.

    Also you will have to do again your settings for the "flat rate" shipping method, or to remove the shipping class from your specific product.

    The code:

    add_filter( 'woocommerce_package_rates', 'disable_shipping_methods', 20, 2 );
    function disable_shipping_methods( $rates, $package ) {
        // ==> HERE set your targeted product IDs in a coma separated array
        $products_ids = array(37);
    
        if( ! ( isset($package['destination']['country']) && isset($package['contents']) ) )
            return $rates; // If 'destination' country is not defined, we exit
    
        // Only for United kingdom customers
        if( $package['destination']['country'] != 'GB' )
            return $rates; // Non UK customers we exit.
    
        // Loop through cart items and checking if there is any other products than the targeted ones
        $found = false;
        foreach( $package['contents'] as $item ) {
            if( in_array( $item['data']->get_id(), $products_ids ) ){
                $found = true;
            } else {
                return $rates; // Other items found in cart, we exit.
            }
        }
    
        // When the customer is in UK and the target product is alone in cart we set the flat rate price to zero.
        foreach ( $rates as $rate_key => $rate ){
            // Targetting flat rate method
            if( $rate->method_id == 'flat_rate' && $found ){
                // We change the shipping label name
                $rates[$rate_key]->label = __("Free shipping", "woocommerce");
    
                // Set the rate cost to zero
                $rates[$rate_key]->cost = 0;
    
                // Taxes rate cost (if enabled)
                $taxes = array();
                foreach ($rates[$rate_key]->taxes as $key => $tax){
                    if( $rates[$rate_key]->taxes[$key] > 0 ){
                        $taxes[$key] = 0;
                        $has_taxes = true;
                    }
                }
                if( isset($has_taxes) && $has_taxes )
                    $rates[$rate_key]->taxes = $taxes;
            }
        }
        return $rates;
    }
    

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

    Customer form UK with this unique item in cart - Free shipping

    enter image description here

    Customer form UK with this item and others in cart - Normal shipping

    enter image description here

    Customer from other countries with this unique item in cart - Normal shipping

    enter image description here

    Once you get that working, don't forget to disable the debug mode in Woocommerce shipping settings under "Shipping options" tab.