Search code examples
phpwordpresswoocommercecartshipping-method

Conditional free shipping based on shipping class and minimal amount in Woocommerce


In woocommerce regarding Shipping methods, I am trying to have the following:

  • Products A only in cart: set with "Free shipping"
  • Products B only in cart: set with:
    • Flat rate amount of 15 if Products B purchased amount is less than 200
    • Free shipping if Products B purchased amount reaches 200 or more..
  • Products A + Products B are in cart at the same time: "Free Shipping" without any amount restriction.

I have tried by using flat rate and shipping classes I am getting like if product A and product B is there then if the cart doesn't reach 200 it is taking 15 shipping charge.

Any help is appreciated.


Solution

  • Updated: To make it work first you will need:

    • To add a "Free" shipping class (first),
    • To enable 2 shipping methods: "Free shipping" and "Flat rate",
    • In your products with Free shipping will need to be set with the shipping class "Free",
    • In your other product will not have any defined shipping class.
    1. For the "free shipping" method, you will not add any restrictions amount to it.

    2. For the "Flat rate" shipping method, you will set it as in this screen shot:

    enter image description here

    1. The magic will be done by the following code that will make the rest:

      add_filter('woocommerce_package_rates', 'conditional_free_shipping', 10, 2); function conditional_free_shipping( $rates, $package ){ if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return $rates;

       ## -- Your settings below -- ##
      
       $shipping_class  = 'free'; // "Free" shipping class products
       $min_free_amount = 200;    // Minimal Free shipping amount for normal products
      
       ## -- -- -- -- -- -- -- -- -- ##
      
       $has_free = false; // Initializing
       $products_total = 0; // Initializing
      
       // Loop through cart items
       foreach( $package['contents'] as $cart_item ) {
           if( $cart_item['data']->get_shipping_class() == $shipping_class ) {
               $has_free = true;
           } else {
               // Get the total purchased amount for normal product
               $products_total += $cart_item['line_total'] + $cart_item['line_tax'];
           }
       }
      
       foreach ( $rates as $rate_key => $rate ){
           // 1. Only Free shipping products in cart OR both products kind in cart
           if( $has_free ) {
               if( 'flat_rate' === $rate->method_id )
                   unset( $rates[$rate_key] ); // Remove flat rate
           }
           // 2. Only normal products in cart
           else {
               // A. If it's under the min amount
               if( 'free_shipping' === $rate->method_id && $products_total < $min_free_amount )
                   unset( $rates[$rate_key] ); // Remove Free shipping
               // B. When min amount is reached
               elseif( 'flat_rate' === $rate->method_id && $products_total >= $min_free_amount )
                   unset( $rates[$rate_key] ); // Remove flat rate
           }
       }
       return $rates;
      

      }

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

    You might need to refresh shipping cached data: disable, save and enable, save related shipping methods for the current shipping zone, in Woocommerce shipping settings.