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        Get CustomizeWoo.com FREE
 * @sourcecode    https://businessbloomer.com/?p=114302
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 3.5.4
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */

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 PHP snippets at the bottom of your child theme functions.php file and CSS at the bottom of its style.css file. Make sure you know what you are doing when editing such files - if you need more guidance, please take a look at my guide "Should I Add Custom Code Via WP Editor, FTP or Code Snippets?" and my video tutorial "Where to Place WooCommerce Customization?"

Does this snippet (still) work?

Please let me know in the comments if everything went as expected. I would be happy to revise the snippet if you report otherwise (please provide screenshots). I have tested this code with Storefront theme, the WooCommerce version listed above and a WordPress-friendly hosting.

If you think this code saved you time & money, feel free to join 17,000+ WooCommerce Weekly subscribers for blog post updates and 250+ Business Bloomer supporters for 365 days of WooCommerce benefits. Thank you in advance!

Need Help with WooCommerce?

Check out these free video tutorials. You can learn how to customize WooCommerce without unnecessary plugins, how to properly configure the WooCommerce plugin settings and even how to master WooCommerce troubleshooting in case of a bug!

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.

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? Support? Leave your Comment Now!
_____

If you are writing code, please wrap it between shortcodes: [php]code_here[/php]. Failure to complying with this (as well as going off topic, not writing in English, etc.) will result in comment deletion. 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 BloomerArmada to get blog comment reply priority, ask me 1-to-1 WooCommerce questions and enjoy many more perks. Thank you :)

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