WooCommerce: Flat Rate Calculation Based on Weight (Without a Plugin!)

We already talked about weight based shipping and in this post we found out how to charge different flat rates based on shipping weight thresholds.

But now I want to show you how you can use the default “Flat Rate” to calculate shipping costs based on cart weight, thanks to a multiplier. For example, your shipping rate might be “$5 for each Kg” – as you know the default “Flat Rate” only allows you to define one rate e.g. $10.

So, what if you want to calculate shipping charges by weight? Well, here’s a simple workaround for you.

Shipping by Weight: first of all create a new “Flat Rate” with cost = 0 and get its ID

PHP snippet: Turn Flat Rate into a Weight Multiplier Shipping Rate

Before getting into coding, a few notes first. The following snippet won’t work unless you:

  • enter weight for every product in your store
  • create a Flat Rate and get its ID (“84” in the example below)
  • define your shipping by weight formula ($5 multiplied by rounded kilos in the example below. My snippet will return $5 if cart weight is 1.4Kg, $10 if cart weight is 1.6Kg, $15 if cart weight is 3.1Kg and so on… Adjust as per your project specifications)

The following snippet might not fully work if the Flat Rate is taxable and if you have tax enabled in your store. It might need a little tweak to make it work.

Also make sure to empty your Cart before testing – every time you work with shipping rates you need to clear your “session” and emptying the Cart should trigger that automatically.


/**
 * @snippet       Flat Rate = Shipping by Weight
 * @how-to        businessbloomer.com/woocommerce-customization
 * @sourcecode    https://businessbloomer.com/?p=114302
 * @author        Rodolfo Melogli, Business Bloomer
 * @compatible    WooCommerce 3.5.4
 * @community     https://businessbloomer.com/club/
 */

add_filter( 'woocommerce_package_rates', 'bbloomer_woocommerce_tiered_shipping', 999, 2 );
   
function bbloomer_woocommerce_tiered_shipping( $rates, $package ) {   
  	$cart_weight = WC()->cart->cart_contents_weight;
  	if ( isset( $rates['flat_rate:84'] ) ) {
		  $rates['flat_rate:84']->cost = 5 * round ( $cart_weight ); 
	}
  	return $rates;
}

Where to add custom code?

You should place custom PHP in functions.php and custom CSS in style.css of your child theme: where to place WooCommerce customization?

This code still works, unless you report otherwise. To exclude conflicts, temporarily switch to the Storefront theme, disable all plugins except WooCommerce, and test the snippet again: WooCommerce troubleshooting 101

Related content

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza. Follow @rmelogli

16 thoughts on “WooCommerce: Flat Rate Calculation Based on Weight (Without a Plugin!)

  1. I was looking at how you can modify a shipping method from the core of woocommerce, and while reading the article, it occurs to me to ask you, maybe you know something, about a solution that I have been looking for a long time and cannot find.

    For a project, I need to recalculate the tax.
    Woocommerce by default calculates the tax according to the sale price, be it the regular price or the sale price, and allows to calculate the tax by applying the shipping cost.

    I need it for a special project, it is to calculate the tax, on the cost price.

    I have a plugin for cost price, and I need the tax to be calculated on the cost price, and not on the sale price.

    And so, the tax based on the cost price should be shown in the cart and at checkout, instead of showing the tax on the sale price.

    Do you think woocommerce could do this?

    Kind regards,
    Alex

    1. Yes, with custom coding you can do anything you like!

  2. Spot on – thanks brother

    1. Great!

  3. Hi Rodolfo,

    Thank you for this article, it is getting me one step closer to what I am really needing for my client. Their courier charges a handling fee per product plus weight based shipping of anything over 5kgs. I see Joe did a work around to multiply per kg. My question is, Is there a way to incorporate the flate rate formula Price*[qty] and add the weight shipping rule. for instance 125*[qty]+1.5 per 1 kg over 5 kg.

    1. Yes I’m pretty sure this can be custom coded

  4. Very Good Really so happy,

    I have a question, I have limited flat rates options so after the last option I would like to show a message to customers but its not working can you please help me.
    Thanks

    /*Shipping Method*/
        add_filter( 'woocommerce_package_rates', 'bbloomer_woocommerce_tiered_shipping', 9999, 2 );
        
        function bbloomer_woocommerce_tiered_shipping( $rates, $package ) {
            
            echo "<pre>";
            print_r(WC()->cart->cart_contents_weight);
            echo"</pre>";
            
            if ( WC()->cart->cart_contents_weight <= 2500 ) {
                
                if ( isset( $rates['flat_rate:2'] ) ) unset( $rates['flat_rate:3'], $rates['flat_rate:4'], $rates['flat_rate:5'], $rates['flat_rate:6'], $rates['flat_rate:7'], $rates['flat_rate:8'] );
                
            } elseif ( WC()->cart->cart_contents_weight >= 2501 && WC()->cart->cart_contents_weight <= 4000) {
                
                if ( isset( $rates['flat_rate:3'] ) ) unset( $rates['flat_rate:2'], $rates['flat_rate:4'], $rates['flat_rate:5'], $rates['flat_rate:6'], $rates['flat_rate:7'], $rates['flat_rate:8'] );
            } elseif ( WC()->cart->cart_contents_weight >= 4001 && WC()->cart->cart_contents_weight <= 6000) {
                
                if ( isset( $rates['flat_rate:4'] ) ) unset( $rates['flat_rate:2'], $rates['flat_rate:3'], $rates['flat_rate:5'], $rates['flat_rate:6'], $rates['flat_rate:7'], $rates['flat_rate:8'] );
            } elseif ( WC()->cart->cart_contents_weight >= 6001 && WC()->cart->cart_contents_weight <= 8000) {
                
                if ( isset( $rates['flat_rate:5'] ) ) unset( $rates['flat_rate:2'], $rates['flat_rate:3'], $rates['flat_rate:4'], $rates['flat_rate:6'], $rates['flat_rate:7'], $rates['flat_rate:8'] );
            } elseif ( WC()->cart->cart_contents_weight >= 8001 && WC()->cart->cart_contents_weight <= 10000) {
                
                if ( isset( $rates['flat_rate:6'] ) ) unset( $rates['flat_rate:2'], $rates['flat_rate:3'], $rates['flat_rate:4'], $rates['flat_rate:5'], $rates['flat_rate:7'], $rates['flat_rate:8'] );
            } elseif ( WC()->cart->cart_contents_weight >= 10001 && WC()->cart->cart_contents_weight <= 12000) {
                
                if ( isset( $rates['flat_rate:7'] ) ) unset( $rates['flat_rate:2'], $rates['flat_rate:3'], $rates['flat_rate:4'], $rates['flat_rate:5'], $rates['flat_rate:6'], $rates['flat_rate:8'] );
            } elseif ( WC()->cart->cart_contents_weight >= 12001 && WC()->cart->cart_contents_weight <= 15000) {
                
                if ( isset( $rates['flat_rate:8'] ) ) unset( $rates['flat_rate:2'], $rates['flat_rate:3'], $rates['flat_rate:4'], $rates['flat_rate:5'], $rates['flat_rate:6'], $rates['flat_rate:7'] );
            } else {
                
                    echo "Vid vikt &ouml;ver 15000 kg, v&auml;nligen kontakta oss f&ouml;r offert";
                    unset( $rates['flat_rate:2'], $rates['flat_rate:3'], $rates['flat_rate:4'], $rates['flat_rate:5'], $rates['flat_rate:6'], $rates['flat_rate:7'], $rates['flat_rate:8'] );
            }
            
            return $rates;
            
        }
    1. Hi Sami, you can’t echo inside an add_filter function. You’ll need a workaround

  5. this code multiply amount per kg in cart

    add_filter( 'woocommerce_package_rates', 'bbloomer_woocommerce_tiered_shipping', 999, 2 );
        
    function bbloomer_woocommerce_tiered_shipping( $rates, $package ) {   
         $cart_weight = WC()->cart->cart_contents_weight;
    
    	foreach($rates as $key => $rate ) {
            $rates[$key]->cost = $rates[$key]->cost * round ( $cart_weight );
        }
         return $rates;
    }
    
    1. Nice 🙂

  6. Great. It works.
    What code to add if I want that if the Cart value is over a certain value (let’s say 75 $ or EUR) it will apply a free shipping option?
    Thank you in advance.

    1. Ciao Giacomo 🙂 You can do that via the settings: https://docs.woocommerce.com/document/free-shipping

  7. How to get the weight from a group of products in a specific shipping class only? So the weight of only that products which have that one specified shipping class?

    1. Hello Andre, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  8. Greetings Rodolfo!
    Great… you’re not so far from what I’m looking for 😉
    I’m looking for add a fixed amount to the shipping costs. As example, if UPS plugin (which is connected to the UPS API) return $10 for the cart, I want to be able to add $2, so $12 for the shipping cost. (or a %). The operate (for 1% more + $2) can be ShippingCost = ShippingCost*1.01 + $2.
    Maybe for the next post 🙂
    Have a good continuation
    Great posts!
    Rémi

    1. Thank you Remi!

Questions? Feedback? Customization? Leave your comment now!
_____

If you are writing code, please wrap it like so: [php]code_here[/php]. Failure to complying with this, as well as going off topic or not using the English language will result in comment disapproval. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining the Business Bloomer Club to get quick WooCommerce support. Thank you!

Your email address will not be published. Required fields are marked *