Posted on 44 Comments

How to Add Cart Fees in WooCommerce with PHP

One of the reasons why WooCommerce is the most popular eCommerce platform is the great flexibility it offers. There is always a solution for whatever you are trying to achieve. There seems to be an API for almost anything that you want to do with WooCommerce. Have you ever wanted to add a custom fee in the cart total? Sometimes this is if a certain condition is met, for example, when customer selects a certain payment gateway. Sometimes payment gateways can be convenient for customers but inconvenient for store owners with their high fees. In such a situation you may decide to pass the payment gateway fees to the customer. You can also add custom fees to the cart based on the shipping location or based on the cart total. There are many other situations in which you might need to add custom cart fees.

WooCommerce has an integrated function for adding cart fees. You will need to use the correct hooks to get the right action. You will use the cart object to call a function to add a fee based on your condition. The fee will be added to a new row in the cart total and checkout page. You can specify any name you wish for the fee.

How to Add Cart Fees in WooCommerce with PHP - Frontend Cart Example

In this article, we will look at a few situations in which you will need to add specific fees to a user’s cart. You will need to add code to your functions.php file for these functionalities to work. If you are unsure about how to add code to the functions.php file, refer to our step by step guide.

If you need to add fee(s) to the cart in WooCommerce, you need woocommerce_cart_calculate_fees action. Action is called in calculate_fees() function of WC_Cart class, and has only one parameter – $cart.

To add the fee, you need to call add_fee() function. Function has four parameters: fee’s name, amount, is fee taxable and if so – which tax class:

* @param string $name Unique name for the fee. Multiple fees of the same name cannot be added. * @param float $amount Fee amount (do not enter negative amounts). * @param bool $taxable Is the fee taxable? (default: false). * @param string $tax_class The tax class for the fee if taxable. A blank string is standard tax class. (default: '').

In this article we will review how to add cart fees based on:

1. Adding cart fees based on a product’s custom field value

So let’s say, you want to add cart fee depending on some product custom field (i.e. meta) value:

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_meta' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_meta' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_product_meta.
     */
    function wpf_wc_add_cart_fees_by_product_meta( $cart ) {
        foreach ( $cart->get_cart() as $cart_item_key => $values ) {
            if ( 0 != ( $setup_fee = get_post_meta( $values['product_id'], 'setup_fee', true ) ) ) {
                $name      = 'Setup fee: ' . get_the_title( $values['product_id'] );
                $amount    = $setup_fee;
                $taxable   = true;
                $tax_class = '';
                $cart->add_fee( $name, $amount, $taxable, $tax_class );
            }
        }
    }
}

2. Adding cart fees based on product’s category

Certain product categories can have additional costs for you as a store owner. You can pass such costs to the customers and cover your costs. For example, if you are selling delicate items such as glassware, you may have additional packaging or handling charges imposed by your shipping provider. In such a case you can pass these additional charges to the customer. You can add such products to a new category and set up your store to charge a handling fee if the product purchased falls in that category. Here is the code you would need to add to add a cart fee based on the product category.

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_category' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_product_category.
     */
    function wpf_wc_add_cart_fees_by_product_category( $cart ) {
        // You need to enter your fees here, in `category slug` => `fee amount` format
        $fees = array(
            'hats'    => 5,
            'hoodies' => 10,
            'tshirts' => 15,
        );
        foreach ( $cart->get_cart() as $cart_item_key => $values ) {
            $product_categories = get_the_terms( $values['product_id'], 'product_cat' );
            if ( $product_categories && ! is_wp_error( $product_categories ) ) {
                $product_categories = wp_list_pluck( $product_categories, 'slug' );
                foreach ( $product_categories as $product_category ) {
                    if ( ! empty( $fees[ $product_category ] ) ) {
                        $name      = 'Category fee: ' . get_the_title( $values['product_id'] );
                        $amount    = $fees[ $product_category ];
                        $taxable   = true;
                        $tax_class = '';
                        $cart->add_fee( $name, $amount, $taxable, $tax_class );
                    }
                }
            }
        }
    }
}

3. Adding cart fees depending on the chosen payment gateway

Specific payment gateway fees are an excellent way of encouraging or discouraging users from using a certain payment method. Payment gateway fees can also ensure you are not being hit by unnecessary fees from the payment processor.

Consider PayPal for example, they sometimes charge up to 3.4% of transactions as fees. This can be a big chunk of your profits. The average net profit ratio for most industries is about 10% so if you are paying about 3% in transaction fees that is going to dent your profits.

Here are some reasons to charge customers based on the payment gateway they use

  • Credit card processors will usually charge a percentage of all your sales revenue as processing fees. If you wish, you could pass this on to the customer by using the code below. This can help reduce your transaction fees, thereby increasing overall profitability.
  • If you are using bank transfer as a payment gateway, banks often charge a fee per transaction. You can add a fixed fee to the cart to cover these transaction costs.
  • PayPal charges a percentage fee for every transaction. You can add this fee to the customer’s cart to recover this cost from the customer.

Here is the code you need to add to your functions.php file to add a custom cart fee based on the payment gateway a user selects.

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_payment_gateway' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_payment_gateway' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_payment_gateway.
     */
    function wpf_wc_add_cart_fees_by_payment_gateway( $cart ) {
        // You need to enter your fees here, in `payment gateway` => `fee amount` format
        $fees = array(
            'cod'    => 20,
            'cheque' => 15,
            'bacs'   => 10,
        );
        // Getting current chosen payment gateway
        $chosen_payment_method = false;
        $available_gateways    = WC()->payment_gateways->get_available_payment_gateways();
        if ( isset( WC()->session->chosen_payment_method ) ) {
            $chosen_payment_method = WC()->session->chosen_payment_method;
        } elseif ( ! empty( $_REQUEST['payment_method'] ) ) {
            $chosen_payment_method = sanitize_key( $_REQUEST['payment_method'] );
        } elseif ( '' != ( $default_gateway = get_option( 'woocommerce_default_gateway' ) ) ) {
            $chosen_payment_method = $default_gateway;
        } elseif ( ! empty( $available_gateways ) ) {
            $chosen_payment_method = current( array_keys( $available_gateways ) );
        }
        if ( ! isset( $available_gateways[ $chosen_payment_method ] ) ) {
            $chosen_payment_method = false;
        }
        // Applying fee (maybe)
        if ( $chosen_payment_method && ! empty( $fees[ $chosen_payment_method ] ) ) {
            $name      = 'Payment gateway fee (' . $chosen_payment_method . ')';
            $amount    = $fees[ $chosen_payment_method ];
            $taxable   = true;
            $tax_class = '';
            $cart->add_fee( $name, $amount, $taxable, $tax_class );
        }
    }
}

However, there is an additional problem that we need to solve here. When a user chooses a different payment gateway in the front-end, the page is not reloaded, hence the fees are not updated. To make sure the page is reloaded when a customer selects a different payment gateway, we need to trigger the update_checkout JavaScript event. There are several ways in which you can add JavaScript code to WordPress. You can use a plugin, or create .js file and load it with wp_enqueue_script() function, or use wp_footer action to add JavaScript code directly in your functions.php file:

add_action( 'wp_footer', 'wpf_wc_add_cart_fees_by_payment_gateway_script' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_payment_gateway_script' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_payment_gateway_script.
     */
    function wpf_wc_add_cart_fees_by_payment_gateway_script() {
        ?>
        <script>
        jQuery( function() {
            jQuery( 'body' ).on( 'change', 'input[name="payment_method"]', function() {
                jQuery( 'body' ).trigger( 'update_checkout' );
            } );
        } );
        </script>
        <?php
    }
}

Another way to add custom cart fees based on a user’s chosen payment gateway is by using a plugin.

Payment Gateway Based Fees and Discounts for WooCommerce

The Payment Gateway Based Fees and Discounts for WooCommerce plugin is an excellent solution to help you add fees and discounts based on a customer’s chosen payment gateway. The plugin works with both standard WooCommerce payment gateways and other payment gateways that you may have added using a plugin. The advantage of using this plugin over the code mentioned above is that with the code you can only add fees, however, with the plugin you can add fees or a discount for using a certain payment gateway. Discounts can encourage users to use your preferred payment gateway.

4. Adding cart fees based on cart min/max amount

To encourage customers to spend a certain minimum amount you can add a cart fee. For example, orders under $100 can attract a $10 fee for processing. This way products priced over $100 will not attract additional fees. However, smaller items that may cost $50 or $60 for example, will attract additional fees. You can charge customers a fee based on the minimum cart amount to encourage customers to spend more. For example, if a customer orders a $90 item and they see a fee for $10 they may spend an additional $10 to waive the fee, chances are they may end up spending more on the second item they buy just to avoid the additional fee. This will help boost your sales and average order value.

Here is the code to add cart fees based on the minimum cart amount.

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_cart_min_max_amount' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_cart_min_max_amount' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_cart_min_max_amount.
     */
    function wpf_wc_add_cart_fees_by_cart_min_max_amount( $cart ) {
        $cart_contents_total = $cart->get_cart_contents_total();
        if ( $cart_contents_total < 100 ) {
            $name      = 'Min cart amount fee';
            $amount    = 10;
            $taxable   = true;
            $tax_class = '';
            $cart->add_fee( $name, $amount, $taxable, $tax_class );
        }
    }
}

You can also add an additional fee to a customer’s cart based on the maximum cart amount. This can be useful in situations where you incur additional costs for processing large orders. Sometimes even payment processors will charge a higher fee for processing a higher amount. In such a case you can pass these additional costs to customers by adding an additional fee to their cart based on the maximum cart amount.

5. Adding extra fees based on total cart weight

Ideally, this can be set up using weight-based shipping methods. However, an alternative is to add an additional cart fee based on the total cart weight. If you would like to add an additional fee to a user’s cart based on their total cart weight, here is the code you would need to use.

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_cart_total_weight' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_cart_total_weight' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_cart_total_weight.
     */
    function wpf_wc_add_cart_fees_by_cart_total_weight( $cart ) {
        $weight = $cart->get_cart_contents_weight();
        if ( $weight > 100 ) {
            $name      = 'Weight fee';
            $amount    = 10;
            $taxable   = true;
            $tax_class = '';
            $cart->add_fee( $name, $amount, $taxable, $tax_class );
        }
    }
}

6. Adding extra fees based on total cart quantity

You may want to add fees to a customer’s cart based on the cart quantity.

For example, if you are selling event tickets and can print one ticket for 10 or 1 ticket for 1 person. On the ticket, you can print admit one or admit 10. This will save you printing costs of the ticket. To discourage customers from purchasing individual tickets you can use a cart fee. For example, an additional printing cost for a ticket that says admit one, but no additional costs for a ticket that says admit 10. Therefore, if a customer has one ticket in their cart, they will incur the fee. But if they have 10 tickets in their cart, they will not incur fees.

In such a situation you can add additional cart fees based on the cart quantity.

Here is the code that you would need to use to add additional cart fees based on a customer’s cart quantity.

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_cart_qty' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_cart_qty' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_cart_qty.
     */
    function wpf_wc_add_cart_fees_by_cart_qty( $cart ) {
        $qty = $cart->get_cart_contents_count();
        if ( $qty > 1 ) {
            $name      = 'Quantity fee';
            $amount    = 5;
            $taxable   = true;
            $tax_class = '';
            $cart->add_fee( $name, $amount, $taxable, $tax_class );
        }
    }
}

7. Adding cart fees based on a customer’s country

This can be useful in situations where you have to pay an export fee or a customs fee. Often governments will try to discourage exports of items that are in demand locally, by imposing levies, duties and customs fees.

If you are shipping outside your country and there are additional customs fees, duties or levies that you have to pay for shipping items out of your country, you can pass such charges to customers.

Here is another example of a situation in which you may want to add additional cart fees based on a customer’s country. It may be that shipping regulations in the customer’s country require all items shipped to that country to be insured. The additional cost you incur for shipping insurance can be passed to the customer.

These are just a few examples of situations in which you may want to add additional cart fees based on a customer’s country. There can be several other situations in which you may want to charge additional fees for shipping to certain countries. Whatever the scenario, if you wish to add additional fees to a customer’s cart based on the customer’s country, here is the code you would need to add.

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_customer_country' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_customer_country' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_customer_country.
     */
    function wpf_wc_add_cart_fees_by_customer_country( $cart ) {
        // You need to enter your fees here, in `country code` => `fee amount` format
        $fees = array(
            'US' => 10,
            'FR' => 15,
        );
        // Getting customer's country by IP
        $location = ( class_exists( 'WC_Geolocation' ) ? WC_Geolocation::geolocate_ip() : array( 'country' => '' ) );
        if ( empty( $location['country'] ) ) {
            // Base fallback
            $location = wc_format_country_state_string( apply_filters( 'woocommerce_customer_default_location', get_option( 'woocommerce_default_country' ) ) );
        }
        $customer_country = ( isset( $location['country'] ) ? $location['country'] : '' );
        // Applying fee (maybe)
        if ( ! empty( $fees[ $customer_country ] ) ) {
            $name      = 'Country fee (' . $customer_country . ')';
            $amount    = $fees[ $customer_country ];
            $taxable   = true;
            $tax_class = '';
            $cart->add_fee( $name, $amount, $taxable, $tax_class );
        }
    }
}

8. Adding cart fees based on a user’s role

There are many plugins available for user role-based pricing. They may be useful in some situations, however, what if you want to use the same prices for all users but just have an extra fee added to the cart for specific user roles? This is where the plugins that offer role-based pricings may not be useful. As these plugins will have different prices of products for different user roles. In such a case you will have to use the following code to add additional fees based on a user’s role.

add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_user_role' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_user_role' ) ) {
    /**
     * wpf_wc_add_cart_fees_by_user_role.
     */
    function wpf_wc_add_cart_fees_by_user_role( $cart ) {
        // You need to enter your fees here, in `user role` => `fee amount` format
        $fees = array(
            'customer'   => 10,
            'wholesaler' => 15,
        );
        // Getting user's role
        $user       = wp_get_current_user();
        $user_roles = $user->roles;
        // Applying fee (maybe)
        foreach ( $user_roles as $user_role ) {
            if ( ! empty( $fees[ $user_role ] ) ) {
                $name      = 'Role fee (' . $user_role . ')';
                $amount    = $fees[ $user_role ];
                $taxable   = true;
                $tax_class = '';
                $cart->add_fee( $name, $amount, $taxable, $tax_class );
            }
        }
    }
}

This will be especially useful in situations where you have got different groups of customers. For example, if you are running a subscription-based website and are selling products also. If customers have purchased a certain subscription you can assign a specific role to them. If you are selling products to them, you can waive the additional fees. If the customers have not purchased a subscription you can add the additional cart fees as they will have a different user role. These kinds of offers are usually referred to as “Subscribe and Save” where if the customer has an active subscription, they don’t pay the additional fees. However, if they don’t have an active subscription they are grouped on a different role and need to pay an additional fee. This can encourage users to purchase active subscriptions, thereby increasing sales.

Many websites that sell stock images implement subscribe and save policies, as they keep users coming back and help in generating constant cashflow.

Conclusion

Adding a custom fee to a user’s cart can be a great way to recover costs and increase profitability. Lower priced products are always attractive to customers. However, adding a cart fee and surprising customers can have an effect on your conversions. It is critical to monitor your cart abandonment rate when you add such fees and if you feel your conversions are taking a toll you should remove it. It is important to be upfront with customers about any additional charges and fees and avoid surprising them.

If your products are in demand though and needed by the customer your conversions may not be affected by adding a cart fee. It is therefore important to use cart fees carefully.

We have given various examples of situations in which you may need to add a specific extra fee. You need to be able to automate the whole process. Else, you will end up in a tiresome manual price review task. You may end up focusing on managing the extra fees rather than your core business.

44 thoughts on “How to Add Cart Fees in WooCommerce with PHP

  1. This Tutorial is works fine if the discount amount is less than or equal $999 (which means 3 digit number)
    If discount amount is more than $999 like $1050,$1099 then it return $1 as discount.
    Why? Whats wrong in this code

  2. Hi Tom,

    If have found your examples very helpful. I tried to combine multiple examples to get exactly what i want but i can’t get it to work. The situation: for certain products (determined by an attribute value) i would like to add a fee for crates that the products are delivered on. To make even more difficult the fee costs should be based on the number of products but are not following an exponential format.

    Example
    If attribute pa_cratefee = crates_x —> a fee of €20 should be added for 0 – 40 products but for 41 – 80 a fee of € 70 should be added, etc

    or

    If attribute pa_cratefee = crates_y —> a fee of €30 should be added for 0 – 20 products but for 21 – 40 a fee of € 60 should be added, and for 41-70 a fee of € 80 should be added, etc

    etc

    Can you give me some tips on how i should structure the code?

  3. How would you combine adding a fee based on State, Shipping Method, & Product ID in the cart? I am trying to add a retail delivery fee of $.27 if the State is CO, the shipping method doesn’t equal ‘flexible_shipping_single:14’ & if select product IDs are in the cart & haven’t been able to figure out how to combine all 3 things to work for adding in the fee.

    I have this working for just State & Shipping:

    // Add the $0.27 fee based on state & shipping method
    add_action( 'woocommerce_cart_calculate_fees','ecommercehints_colorado_retail_delivery_fee' );
    function ecommercehints_colorado_retail_delivery_fee() {
        global $woocommerce;
        if (is_admin() && !defined('DOING_AJAX'))
            return;
    
        $state = array('CO'); // CO is the select option value for Colorado
        $chosen_shipping_method = WC()->session->get('chosen_shipping_methods')[0]; // Get the shipping method
    
    /* 
         * If shipping state equals Colorado AND shipping method is your flat rate options, add the fee
         * You will need to change 'flat_rate:10' to your flat rate shipping method radio button value
         */
        if ( in_array( $woocommerce->customer->get_shipping_state(), $state ) && 'flexible_shipping_single:14' !== $chosen_shipping_method): 
            $woocommerce->cart->add_fee( 'Retail Delivery Fee', 0.27, true, '' );
        endif;
    }
    
    // JavaScript to update the totals on state selection
    add_action( 'wp_footer', 'ecommercehints_update_checkout_totals' );
    function ecommercehints_update_checkout_totals() { ?>
    
        jQuery( function( $ ) {
        $( 'form.checkout' ).on( 'change', 'select[name^="billing_state"]', function() {
            $( 'body' ).trigger( 'update_checkout' );
        });
    });
    
    get_cart() as $cart_item_key => $values ) {
                $product_id = ( ! empty( $values['variation_id'] ) ? $values['variation_id'] : $values['product_id'] );
                if ( in_array( $product_id, $product_ids )) {
                    $total_qty += $values['quantity'];
                }
            }
    
            // Add fee
            if ( $total_qty > 0 ) {
                $name      = 'Retail Delivery Fee';
                $amount    = .27;
                $taxable   = true;
                $tax_class = '';
                $cart->add_fee( $name, $amount, $taxable, $tax_class );
            }
    
        }
        add_action( 'woocommerce_cart_calculate_fees', 'wpfactory_wc_add_cart_fees_by_selected_product_qty' );
    }
    1. Hi Brie,

      It looks like your code was “sanitized” by our site; I think it’s incomplete now. However, I already have one suggestion – you are using the same name for all fees, i.e., “Retail Delivery Fee”. You have to make it unique for all your fees, e.g., Retail Delivery Fee #1, Retail Delivery Fee #2, etc., as otherwise, WooCommerce will overwrite it.

      Please give it a try and let me know if that helped.

    2. Is there a way to combine it all into one Retail Delivery Fee, I need it to just be 1 fee but has to meet the 3 criteria. So if the state is CO, shipping method isn’t ‘flexible_shipping_single:14’ & at least one of those selected products is in the cart then the fee is applied; otherwise, the fee won’t be applied.

    3. Sure, that’s doable. You will need to restructure your code a bit – instead of calling the $cart->add_fee() function multiple times, we’ll call it only once, at the end of the code:

      add_action( 'woocommerce_cart_calculate_fees', function ( $cart ) {
      
          $fee_amount = 0;
      
          /**
           * TODO: Go through all your conditions here,
           * and modify the `$fee_amount` if needed, e.g.:
           * `$fee_amount += 0.27;`
           */
      
          if ( 0 != $fee_amount ) {
              // Add fee
              $name      = 'Retail Delivery Fee';
              $taxable   = true;
              $tax_class = '';
              $cart->add_fee( $name, $fee_amount, $taxable, $tax_class );
          }
      
      } );
      

      Please give it a try and let me know what you think.

  4. Hi Tom
    I want to be able to add a surcharge of say $40 if customers do not spend a minimum spend of say $200. But I only want this to apply to a user role “wholesale customer”.

    Many thanks

    1. Hi, Danny,

      I think this should solve it:

      add_action( 'woocommerce_cart_calculate_fees', function( $cart ) {
          /**
           * @see https://wpfactory.com/blog/how-to-add-cart-fees-in-woocommerce-with-php/
           */
      
          // Variables
          $user_role     = 'wholesale_customer';
          $cart_total    = 200;
          $fee_name      = esc_html__( 'Fee' );
          $fee_amount    = 40;
          $fee_taxable   = true;
          $fee_tax_class = '';
      
          // Check user role
          $user = wp_get_current_user();
          if ( ! in_array( $user_role, $user->roles ) ) {
              return;
          }
      
          // Check order amount
          if ( $cart->get_cart_contents_total() >= $cart_total ) {
              return;
          }
      
          // Add fee
          $cart->add_fee( $fee_name, $fee_amount, $fee_taxable, $fee_tax_class );
      
      } );

      Please give it a try and let me know if there are any issues or questions.

  5. Hi Tom

    Thank you for the provided code snippets. They are great. By reading your post and commentaries I’m so close to have what I need but still something is missing, like always :))

    I’m trying to add fixed fee to 2 different categories products. I removed the tax part and showing product’s name as I only need the name “Pantti” and how much is the cost of it summarized. The problem is that it returns the extra fee for only first added product. Quantity works as well but only for that first added product. Code doesn’t count in next products I add. Could you please point me in the right direction? Thank you in advance.

    /**
     * Extra fee "Pantti" @ Checkout Page
     */
    add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category' );
    if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_category' ) ) {
        function wpf_wc_add_cart_fees_by_product_category( $cart ) {
            // You need to enter your fees here, in `category slug` => `fee amount` format
            $fees = array(
                'oluet'                => 2.40,
                'siiderit-ja-lonkerot' => 2.40,
            );
            foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                $product_categories = get_the_terms( $values['product_id'], 'product_cat' );
                if ( $product_categories && ! is_wp_error( $product_categories ) ) {
                    $product_categories = wp_list_pluck( $product_categories, 'slug' );
                    foreach ( $product_categories as $product_category ) {
                        if ( ! empty( $fees[ $product_category ] ) ) {
                            $name      = 'Pantti ';
                            $amount    = $fees[ $product_category ] * $values['quantity'];
                            $cart->add_fee( $name, $amount );
                        }
                    }
                }
            }
        }
    }
    
    1. Hi,

      I think I know where the problem is – WooCommerce will not add fees with the same name. So you need to either add some unique text to the “Pantti” for each fee, e.g., something like 'Pantti ' . $product_category, or, if you want to merge it all into one fee, you can pre-calculate it and add it only once in the end, like this:

      /**
       * Extra fee "Pantti" @ Checkout Page
       */
      add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category' );
      if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_category' ) ) {
          function wpf_wc_add_cart_fees_by_product_category( $cart ) {
              // You need to enter your fees here, in `category slug` => `fee amount` format
              $fees = array(
                  'oluet'                => 2.40,
                  'siiderit-ja-lonkerot' => 2.40,
              );
              $fee = 0;
              foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                  $product_categories = get_the_terms( $values['product_id'], 'product_cat' );
                  if ( $product_categories && ! is_wp_error( $product_categories ) ) {
                      $product_categories = wp_list_pluck( $product_categories, 'slug' );
                      foreach ( $product_categories as $product_category ) {
                          if ( ! empty( $fees[ $product_category ] ) ) {
                              $fee += $fees[ $product_category ] * $values['quantity'];
                          }
                      }
                  }
              }
              if ( 0 != $fee ) {
                  $cart->add_fee( 'Pantti ', $fee );
              }
          }
      }

      Please give it a try and let me know what you think.

  6. Hi Tom!
    Thank you so very much for the code, it’s exactly what I was looking for. One question, is there any way to tell it to only add the fee once? For example I only want a $10 fee to be added once per cart that contains a certain category item (say a t-shirt for example). But I don’t want to charge $10 on every t-shirt if the person has multiple t-shirts in their cart. Hope I’m making sense and thank you SO MUCH in advance!

    1. Hi Tati,

      If you want to limit it to only one fee per cart, then the easiest way probably would be to simply add return right after the add_fee() function, like this:

      ...
      $name      = 'Category fee: ' . get_the_title( $values['product_id'] );
      $amount    = $fees[ $product_category ];
      $taxable   = true;
      $cart->add_fee( $name, $amount, $taxable, $tax_class );
      return;
      ...

      If you want to limit it to only one fee per category (e.g., one for the t-shirts category, one for the hoodies category, etc.), then you can simply unset the corresponding $fees key, like this:

      ...
      $name      = 'Category fee: ' . get_the_title( $values['product_id'] );
      $amount    = $fees[ $product_category ];
      $taxable   = true;
      $cart->add_fee( $name, $amount, $taxable, $tax_class );
      unset( $fees[ $product_category ] );
      ...

      Hope this helps. Please let me know if you have any questions.

  7. Hi,

    I want the code for optional fee charges Means I want a checkbox that when checked the fee apply if not checked then fee will not apply.Please help
    My code is :

    add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category' );
    if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_category' ) ) {
        /**
         * wpf_wc_add_cart_fees_by_product_category.
         */
    	 	 
        function wpf_wc_add_cart_fees_by_product_category( $cart ) {
            // You need to enter your fees here, in `category slug` => `fee amount` format
           /* $fees = array(
                'live-fish'    => 5,
               
            );*/
            foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                $product_categories = get_the_terms( $values['product_id'], 'product_cat' );
    			if(strpos($product_categories, 'live-fish') !== false) {
    			 $price_amt = get_post_meta($values['product_id'] , '_price', true);
    			 $fees = array(
                'live-fish'    => 0.25 * $price_amt,
               
    			);
    			}
                if ( $product_categories && ! is_wp_error( $product_categories ) ) {
                    $product_categories = wp_list_pluck( $product_categories, 'slug' );
                    foreach ( $product_categories as $product_category ) {
                        if ( ! empty( $fees[ $product_category ] ) ) {
                            $name      = 'DOA Premium: ' . get_the_title( $values['product_id'] );
                            $amount    = $fees[ $product_category ];
                            $taxable   = false;
                            $tax_class = '';
                            $cart->add_fee( $name, $amount, $taxable, $tax_class );
    						
    						
                        }
                    }
                }
            }
        }
    
    }
    

    Thanks

    1. Hi Divya,

      Do you mean you’ve added some custom checkbox to the checkout page? If that’s the case – here is my solution:

      I’ve added a custom checkbox with our Custom Checkout Fields for WooCommerce plugin. By the way, this plugin already has this feature built-in, i.e. it can add cart fees based on enabled/disabled checkbox, and you can do it with the free plugin version as well. If you still prefer to use the snippet instead – first of all we need to know the name of the checkbox you’ve added. The plugin I used, added it with the billing_alg_wc_checkout_field_1 name.

      Now we need to make sure that checkout is updated, if the value of the checkbox is changed:

      add_action( 'wp_footer', 'wpfactory_wc_add_cart_fee_script' );
      if ( ! function_exists( 'wpfactory_wc_add_cart_fee_script' ) ) {
          /**
           * wpfactory_wc_add_cart_fee_script.
           */
          function wpfactory_wc_add_cart_fee_script() {
              ?>
              <script>
              jQuery( function() {
                  jQuery( 'body' ).on( 'change', 'input[name="billing_alg_wc_checkout_field_1"]', function() {
                      jQuery( 'body' ).trigger( 'update_checkout' );
                  } );
              } );
              </script>
              <?php
          }
      }
      

      And after that, we can get the checkbox value from the $_REQUEST['post_data']:

      add_action( 'woocommerce_cart_calculate_fees', 'wpfactory_wc_add_cart_fee' );
      if ( ! function_exists( 'wpfactory_wc_add_cart_fee' ) ) {
          /**
           * wpfactory_wc_add_cart_fee.
           */
          function wpfactory_wc_add_cart_fee( $cart ) {
      
              $post_data = array();
              if ( isset( $_REQUEST['post_data'] ) ) {
                  parse_str( $_REQUEST['post_data'], $post_data );
              }
      
              if ( ! empty( $post_data['billing_alg_wc_checkout_field_1'] ) ) {
                  $cart->add_fee( 'Fee', 10, true, '' );
              }
      
          }
      }
      

      Hope this helps. Please let me know if you have any questions.

    2. Hey when I login to wordpress then the we check the check box to apply fee it’s not working.And the error is coming in console

  8. Hi Tom! Thank you so much for the code!

    However, there is one thing I am not able to add to the code and that is the product quantity.
    I would like to add cart fees based on product’s category and based on the quantity of an individual product. At the moment if I add two different products to checkout based on the category “iPhone” the fee is added twice (which is perfect) but when I have a quantity of 2 from the same product, the fee is only added once. Is there a way to add the fee based on the quantity of one product as well?

    1. Hi Lisa,

      Happy to help 🙂

      What you need is $values['quantity']. Here is the modified “adding cart fees based on product’s category” snippet:

      add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category' );
      if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_category' ) ) {
          /**
           * wpf_wc_add_cart_fees_by_product_category.
           */
          function wpf_wc_add_cart_fees_by_product_category( $cart ) {
              // You need to enter your fees here, in `category slug` => `fee amount` format
              $fees = array(
                  'hats'    => 5,
                  'hoodies' => 10,
                  'tshirts' => 15,
              );
              foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                  $product_categories = get_the_terms( $values['product_id'], 'product_cat' );
                  if ( $product_categories && ! is_wp_error( $product_categories ) ) {
                      $product_categories = wp_list_pluck( $product_categories, 'slug' );
                      foreach ( $product_categories as $product_category ) {
                          if ( ! empty( $fees[ $product_category ] ) ) {
                              $name      = 'Category fee: ' . get_the_title( $values['product_id'] );
                              $amount    = $fees[ $product_category ] * $values['quantity'];
                              $taxable   = true;
                              $tax_class = '';
                              $cart->add_fee( $name, $amount, $taxable, $tax_class );
                          }
                      }
                  }
              }
          }
      }

      Hope this helps. Please let me know if you have any questions.

  9. Hi Tom ,
    Love what you do and thank you, I was wondering how to combine a qty based fee to specific products.
    Thanks in advance!

    1. Hi Phil,

      Thank you 🙂

      To give you an exact solution, I would need to know more about the task. For example, how does quantity affects the fee, will the fee be the same for all products, etc.

      To give you a general example, here is a snippet that will add a $25 fee if there are more than 10 of the selected products in the cart:

      if ( ! function_exists( 'wpfactory_wc_add_cart_fees_by_selected_product_qty' ) ) {
          /**
           * Add a $25 fee if there are more than 10 of the selected products in the cart.
           */
          function wpfactory_wc_add_cart_fees_by_selected_product_qty( $cart ) {
      
              // TODO: Set your product IDs here
              $product_ids = array( 110, 220, 320 );
      
              // Get total qty (selected products only)
              $total_qty = 0;
              foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                  $product_id = ( ! empty( $values['variation_id'] ) ? $values['variation_id'] : $values['product_id'] );
                  if ( in_array( $product_id, $product_ids ) ) {
                      $total_qty += $values['quantity'];
                  }
              }
      
              // Add fee
              if ( $total_qty > 10 ) {
                  $name      = 'Fee';
                  $amount    = 25;
                  $taxable   = true;
                  $tax_class = '';
                  $cart->add_fee( $name, $amount, $taxable, $tax_class );
              }
      
          }
          add_action( 'woocommerce_cart_calculate_fees', 'wpfactory_wc_add_cart_fees_by_selected_product_qty' );
      }
      

      Hope that helps. Please let me know if you have any questions.

  10. Hi Tom,
    thank you for providing the code! Is there a way to add a fee based on an attributes name (e.g. only blue t-shirts will have a fee).
    Thanks!

    1. Hi Chris,

      Happy to help 🙂

      Sure, here it is:

      if ( ! function_exists( 'wpfactory_wc_add_cart_fees_by_product_attribute' ) ) {
          /**
           * Adding cart fees based on a product's attribute value.
           */
          function wpfactory_wc_add_cart_fees_by_product_attribute( $cart ) {
              /****************************************/
              // TODO: Set your attribute fees here
              $fees = array(
                  array(
                      'attribute'       => 'pa_color',
                      'attribute_value' => 'Blue',
                      'fee'             => 10,
                  ),
                  array(
                      'attribute'       => 'pa_color',
                      'attribute_value' => 'Green',
                      'fee'             => 20,
                  ),
                  array(
                      'attribute'       => 'pa_size',
                      'attribute_value' => 'Large',
                      'fee'             => 15,
                  ),
              );
              /****************************************/
              foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                  $product = $values['data'];
                  if ( is_a( $product, 'WC_Product' ) ) {
                      foreach ( $fees as $fee ) {
                          if ( $fee['attribute_value'] === $product->get_attribute( $fee['attribute'] ) ) {
                              $name      = 'Fee (' . $fee['attribute_value'] . ')';
                              $amount    = $fee['fee'];
                              $taxable   = true;
                              $tax_class = '';
                              $cart->add_fee( $name, $amount, $taxable, $tax_class );
                          }
                      }
                  }
              }
          }
          add_action( 'woocommerce_cart_calculate_fees', 'wpfactory_wc_add_cart_fees_by_product_attribute' );
      }
      

      Please give it a try and let me know if you have any questions.

  11. Hello, my name is Cristian Aguilera, I liked this pot, but there is a detail, it is that when I add the corresponding code, everything is perfect, but at the moment of making the conversion, it does not make it an example, I want to pass it from dollars to Argentine pesos and it does not make the conversion.

    1. Hi Cristian,

      As I understand you are using some currency switcher plugin on your site? If that’s the case – the conversion code will depend on the currency switcher plugin itself. I would suggest asking the developers if there is some function you can use to convert the price. So for example, if there would be some convert_price() function, then when adding the fee, you would simply do this:

      $amount = convert_price( 10 );

      instead of this:

      $amount = 10;

      Hope that helps. Please let me know if you have any questions.

  12. Hi Tom, thank u so much!!
    I would apply them only for all european countries, it’s possible?

    1. Hi Santiago,

      Happy to help 🙂

      Yes, it’s definitely possible to add fees for European customers only. Before I can provide a snippet, a couple of questions:

      1. Do you want customer’s country to be detected by IP, or by what is entered manually on the checkout page? And if it’s the latter – do you want to use billing or shipping country?

      2. Will the fee be fixed, i.e. the same, for all countries? Or will it be different for each country? Or maybe it will also depend on something else, like selected payment gateway?

      3. Just to be sure – you need all European countries, not European Union (EU) countries, correct?

    2. P.S. Generally, if you’d need to check if some country is in Europe or European Union, you could use one of these functions:

      function wpfactory_is_europe_country( $country ) {
          $europe = array( 'AD', 'AL', 'AT', 'AX', 'BA', 'BE', 'BG', 'BY', 'CH', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FO', 'FR', 'FX', 'GB', 'GG', 'GI', 'GR', 'HR', 'HU', 'IE', 'IM', 'IS', 'IT', 'JE', 'LI', 'LT', 'LU', 'LV', 'MC', 'MD', 'ME', 'MK', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'RS', 'RU', 'SE', 'SI', 'SJ', 'SK', 'SM', 'TR', 'UA', 'VA' );
          return in_array( $country, $europe );
      }
      function wpfactory_is_european_union_country( $country ) {
          $european_union = array( 'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HU', 'HR', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK' );
          return in_array( $country, $european_union );
      }

      So after you get your customer’s country (by IP or from the manually entered field), you could check if it’s in Europe (or European Union), and return in case if it’s not:

      if ( ! wpfactory_is_europe_country( $country ) ) {
          return;
      }

      Hope that helps.

      Again, I could provide the exact snippet, if I have more info about the task.

  13. Hi, Tom. Code works fine. I made some changes to your code to zero fee if the cart amount is above 50 euros.
    It is working fine , but i would like to ask you if has correct syntax and if will cause problems anywhere else in functionallity.
    Thanks Nik

     function wpf_wc_add_cart_fees_by_payment_gateway( $cart ) {
            // You need to enter your fees here, in `payment gateway` => `fee amount` format
            // 
            $cart_contents_total = $cart->get_cart_contents_total();
    		if ( $cart_contents_total  1.69,
    			);
    		} else {
    			$fees = array(
    				'cod'    => 0.0,
    			);
    		}
    
    1. Hi Nik,

      Sorry for the late reply. I think your code got filtered by our site somehow, doesn’t look like a correct PHP code. Anyway, I would add cart total check right at the beginning of the function, something like this:

      function wpf_wc_add_cart_fees_by_payment_gateway( $cart ) {
          if ( $cart->get_cart_contents_total() > 50 ) {
              return;
          }
          // TODO: Copy the original snippet code here...
      }
      

      Hope that helps. Please let me know if you have any questions.

  14. Hi Tom, thankssss 😀
    Adding extra fees based on total cart quantity work fine but I would apply them for all countries except 1 it’s possible?

    1. Hi Davide,

      This should do the trick – in this example the fee is not applied to the customers from the United States (US):

      add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_cart_qty' );
      if ( ! function_exists( 'wpf_wc_add_cart_fees_by_cart_qty' ) ) {
          /**
           * wpf_wc_add_cart_fees_by_cart_qty.
           */
          function wpf_wc_add_cart_fees_by_cart_qty( $cart ) {
              // Getting customer's country by IP
              $location = ( class_exists( 'WC_Geolocation' ) ? WC_Geolocation::geolocate_ip() : array( 'country' => '' ) );
              if ( empty( $location['country'] ) ) {
                  // Base fallback
                  $location = wc_format_country_state_string( apply_filters( 'woocommerce_customer_default_location', get_option( 'woocommerce_default_country' ) ) );
              }
              $customer_country = ( isset( $location['country'] ) ? $location['country'] : '' );
              // Getting total cart quantity
              $qty = $cart->get_cart_contents_count();
              // Applying fee (maybe)
              if ( $qty > 1 && ! in_array( $customer_country, array( 'US' ) ) ) { // TODO: set your countries here
                  $name      = 'Quantity fee';
                  $amount    = 5;
                  $taxable   = true;
                  $tax_class = '';
                  $cart->add_fee( $name, $amount, $taxable, $tax_class );
              }
          }
      }
      

      Hope that helps. Please give it a try and let me know if you have any questions.

  15. Hello,

    I would like to add fee on product’s category, i try your code but it add the fee for each product of the category.

    example of what i want :
    Product 1 of category 1
    Product 2 of category 1
    Product 3 of category 1
    I want 4€ of fee to be added on the shopping cart, but not 4€ for each product.

    How can i do that ?

    Thank you

    1. Hi,

      Sorry for the late reply.

      We can add $is_fee_added array to track if fee was already added for the category. This should solve your task:

      add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category' );
      if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_category' ) ) {
          /**
           * wpf_wc_add_cart_fees_by_product_category.
           */
          function wpf_wc_add_cart_fees_by_product_category( $cart ) {
              // You need to enter your fees here, in `category slug` => `fee amount` format
              $fees = array(
                  'hats'    => 5,
                  'hoodies' => 10,
                  'tshirts' => 15,
              );
              $is_fee_added = array();
              foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                  $product_categories = get_the_terms( $values['product_id'], 'product_cat' );
                  if ( $product_categories && ! is_wp_error( $product_categories ) ) {
                      foreach ( $product_categories as $product_category ) {
                          if ( ! empty( $fees[ $product_category->slug ] ) && empty( $is_fee_added[ $product_category->slug ] ) ) {
                              $name      = 'Category fee: ' . $product_category->name;
                              $amount    = $fees[ $product_category->slug ];
                              $taxable   = true;
                              $tax_class = '';
                              $cart->add_fee( $name, $amount, $taxable, $tax_class );
                              $is_fee_added[ $product_category->slug ] = true;
                          }
                      }
                  }
              }
          }
      }
      

      Hope that helps. Please give it a try and let me know if you have any questions.

  16. Hi is it possible to add a cart fee on ex “on sale” category products if ONLY one sale products is added to the cart? – If the customer is adding on sale products togther with other products – no fee will be added – hope it make sense 🙂

    1. Hi,

      If I got it correctly, this should do the trick:

      add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_on_sale_only' );
      if ( ! function_exists( 'wpf_wc_add_cart_fees_on_sale_only' ) ) {
          /**
           * wpf_wc_add_cart_fees_on_sale_only.
           */
          function wpf_wc_add_cart_fees_on_sale_only( $cart ) {
              $do_add_fee = true;
              foreach ( $cart->get_cart() as $cart_item_key => $values ) {
                  $product = $values['data'];
                  if ( ! $product->is_on_sale() ) {
                      // at least one product in the cart is NOT on sale
                      $do_add_fee = false;
                      break;
                  }
              }
              if ( $do_add_fee ) {
                  $name      = 'Fee';
                  $amount    = 10;
                  $taxable   = true;
                  $tax_class = '';
                  $cart->add_fee( $name, $amount, $taxable, $tax_class );
              }
          }
      }
      

      Please give it a try and let me know what you think.

  17. Hi,
    First, thanks for providing this code.

    Im working with the “Adding cart fees depending on the chosen payment gateway” php file. It states in the paragraph above the code that you can add the percentage that the payment processor fee charges. But, when I try to enter 3.2 it add $3.20 to the subtotal. I can’t find away to make it into a percentage. Any guideance?
    Thank you,

    1. Hi David,

      To make it a percentage from cart contents total, you need to replace this:

      $amount    = $fees[ $chosen_payment_method ];

      with this:

      $amount    = $cart->get_cart_contents_total() / 100 * $fees[ $chosen_payment_method ];

      * It’s in the end of wpf_wc_add_cart_fees_by_payment_gateway() function, in “Applying fee (maybe)” section.

      Hope that helps. Please let me know if you have any questions.

    2. Hi Tom,
      You’re awesome! I’m a Python developer and just starting to dip into PHP. I tried every way I know how using my Python knowledge and it didn not like what I was doing.
      Thank you!

    3. Hi Tom,
      I need your help again 🙂
      I went on Amazon and purchased a PHP book. I can’t figure this out lol 🙂
      The percentage is working great! I’m trying to add a flat fee to it as well. Ex. 2.9% + $0.30
      I tried creating a new array called $ffees and then adding it to that section. But, I can’get it to work.
      Can you help me add the flat fee on top of the percentage?
      Also, do you have a donate button for your help?
      Thanks

    4. Hi David,

      There is a number of ways you can do this. For example, you can define it all in array of arrays:

      $fees = array(
          'cod'    => array(
              'percent' => 2.9,
              'fixed'   => 0.3,
          ),
          'bacs'   => array(
              'percent' => 3.5,
              'fixed'   => 0.9,
          ),
      );
      

      and then use it like this:

      $amount = $cart->get_cart_contents_total() / 100 * $fees[ $chosen_payment_method ]['percent'] + $fees[ $chosen_payment_method ]['fixed'];
      

      Hope that helps.

  18. Hi,
    How can I add an ACF field for the fee value?
    Thanks in advance.

    1. Hi Michael,

      Sorry for the late reply.

      Could you please give me a bit more details? Is this field displayed on the checkout page?

    2. no problem.
      I solved it in the meantime, but thanks for your answer.

    3. Glad to hear you’ve figured it out.

Leave a Reply

Your email address will not be published.