Add Fees to a Woocommerce Cart Based on Shipping Class

Recently a client needed to setup some conditions whereby certain fees would be applied to a customer’s cart depending on what items they were purchasing.

I thought the Table Rate plugin would do the job, but it turns out it’s not compoundable in the way that we needed. His requirements were like so:

  1. If the cart total was over $250, shipping is free.
  2. If the cart is under 80lbs, charge a flat $7.95 shipping.
  3. Otherwise, charge a flat $51.
  4. Some items would need an additional “Hazardous Material” fee of $17.
  5. Some items would need an additional “Handling Fee” of $9.
  6. Some items would need both of those additional fees.

The table rate plugin helped with items 1-3 with it’s default functionality. I set things up like so:

screenshot of Woocommerce Table Rates plugin setup, as described below

Firstly, I setup all products, regardless of Shipping Class, so that if the total cart amount was $250 or more, it’d be free.

He also had a Free Shipping Shipping Class, which would do the same if applied to products. I set both of these to “Break”, ie, don’t go on down the list.

Then I setup two “Weight” conditionals to set the price based on weight.

If you continue to try and setup the other rules as outlined above, though, they become additional shipping options, not compounded.

So I went the custom code route. What follows essentially looks for a few Shipping Classes which are applied to certain products, if they exist on any product, apply the additional fees as appropriate.

// Add additional fees based on shipping class
function woocommerce_fee_based_on_shipping_class() {

global $woocommerce;

// Setup an array of shipping classes which correspond to those created in Woocommerce
$shippingclass_handling_array = array( 'handling' );
$shippingclass_hazmat_array = array( 'hazmat' );
$shippingclass_both_array = array( 'handling-hazmat' );

// Get the cart total so that, if the order is greater than $250, none of the extra fees apply
$thiscarttotal = WC()->cart->get_cart_total(); // this gets the total
$thiscarttotal = preg_replace('/$/', '', $thiscarttotal); // remove the $ sign
if ($thiscarttotal >= 249) { // if it's less than $250, continue

// then we loop through the cart, checking the shipping classes

foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$shipping_class = get_the_terms( $values['product_id'], 'product_shipping_class' );

if ( isset( $shipping_class[0]->slug ) && in_array( $shipping_class[0]->slug, $shippingclass_handling_array ) ) {
$woocommerce->cart->add_fee( __('Miscellaneous Handling Fee', 'woocommerce'), 9 ); // each of these adds the appropriate fee
if ( isset( $shipping_class[0]->slug ) && in_array( $shipping_class[0]->slug, $shippingclass_hazmat_array ) ) {
$woocommerce->cart->add_fee( __('Hazardous Material Fee', 'woocommerce'), 17 );
if ( isset( $shipping_class[0]->slug ) && in_array( $shipping_class[0]->slug, $shippingclass_both_array ) ) {
$woocommerce->cart->add_fee( __('Miscellaneous Handling Fee', 'woocommerce'), 9 );
$woocommerce->cart->add_fee( __('Hazardous Material Fee', 'woocommerce'), 17 );
add_action( 'woocommerce_cart_calculate_fees', 'woocommerce_fee_based_on_shipping_class' ); // make it all happen when Woocommerce tallies up the fees

That brings it all together! Adjust as needed for your own shipping classes and necessary fees.

Up Next: Conditional Statement to Detect if a User has a Subscription with Woocommerce Subscriptions