1. Documentation /
  2. Introduction to Woo Subscriptions /
  3. Introduction to Subscriptions Developer Documentation /
  4. Developer Guide to Cart and Recurring Cart Fees

Developer Guide to Cart and Recurring Cart Fees

The following guide is written for developers who want to add fees to the WooCommerce cart and would like to learn about how these fees interact with WooCommerce Subscriptions.

The guide explains how fees added to the cart act by default, and how they can be customized to be applied only to the initial order or recurring orders.

Understanding Cart Fees

↑ Back to top

Unlike cart items, cart fees are non-persistent, this means third-party plugins which add fees need to be constantly hooked into the cart calculations, adding their fees each time the cart totals are calculated.

To do that WooCommerce provides the woocommerce_cart_calculate_fees hook, which third parties can use to add their fees.

For example, to add a $10 engraving fee to the cart, you could use the following code snippet:

add_filter( 'woocommerce_cart_calculate_fees', 'add_engraving_fees', 10, 1 );

function add_engraving_fees( $cart ) {
     $cart->add_fee( 'Engraving', '10' );
}

This fee will appear like this in the cart totals section of the cart page:

Cart fees displayed on Cart Page
Cart fees displayed in Edit Totals section of the Cart Page

WooCommerce Subscriptions’ recurring carts use the same cart calculations and so the code snippet above also applies the fees to any recurring cart. That is to say, by default, any cart fees added using the woocommerce_cart_calculate_fees hook will be applied both to both the initial order, and any subscriptions created for that transaction. Those fees are then also applied to subsequent transactions.

So for example, using the same code snippet above, customers purchasing subscriptions would see the following cart totals:

Recurring Cart Fee shown in Recurring Totals Section of Cart Page
Recurring Cart Fee shown in Recurring Totals Section of Cart Page

Recurring Only Fees

↑ Back to top

As mentioned above, by default, fees applied to the cart are applied to be the initial and recurring carts.

In some cases, you may require the fee to only apply to the on-going recurring payment for any subscriptions. To achieve this, you need to tweak the code snippet from above and add a condition to check whether the cart being passed into your callback is a recurring cart, or the standard WooCommerce cart.

Recurring carts have a $recurring_cart_key property we can use to determine if the cart is a recurring cart.

For example:

add_filter( 'woocommerce_cart_calculate_fees', 'add_recurring_postage_fees', 10, 1 );

function add_recurring_postage_fees( $cart ) {
    if ( ! empty( $cart->recurring_cart_key ) ) {
        $cart->add_fee( 'Postage', 5 );
    }
}
Recurring Only Cart Fees displayed in Cart Totals
Recurring Only Cart Fees displayed in Cart Totals
There was a bug with WooCommerce 3.2 where fees were displayed on the initial cart totals even though they were not included in the order’s total. This issue has been fixed with WooCommerce 3.3 via this pull request. If you encounter this issue, please update WooCommerce to the latest version.

Initial Order Only Fees

↑ Back to top

For situations where fees should only be charged on the initial order when the customer signs up, there are two options to add a fee only to the initial order:

Option 1: Invert check for recurring cart

add_filter( 'woocommerce_cart_calculate_fees', 'add_administration_fees', 10, 1 );

function add_administration_fees( $cart ) {
    if ( empty( $cart->recurring_cart_key ) ) {
        $cart->add_fee( 'Processing Fee', 2.5 );
    }
}

In this example, we’ve reversed the logic from the previous code example. This code now only applies fees to the initial purchase cart.

Option 2: Apply fee to global cart

add_filter( 'woocommerce_cart_calculate_fees', 'add_administration_fees', 10 );

function add_administration_fees() {
    WC()->cart->add_fee( 'Processing Fee', 2.5 );
}

In this example, we’re applying the fee to the global WooCommerce cart object. This is the default cart object and so only applies fees to the initial purchase.

Fee for Initial Order Only Displayed in Cart Totals
Fee for Initial Order Only Displayed in Cart Totals
There was a bug with WooCommerce 3.2 where fees were the fee was applied to both the initial purchase’s order and recurring orders. This issue has been fixed with WooCommerce 3.3 via this pull request. If you encounter this issue, please update WooCommerce to the latest version.

The Recurring Fee Filter

↑ Back to top

WooCommerce Subscriptions 2.2.16 introduced the woocommerce_subscriptions_is_recurring_fee filter. This filter allows developers who have applied fees to the initial cart to also apply the fees to the recurring cart.

For example, if the cart fees have been applied using WC()->cart->add_fee( 'Fee', '10' );, you could use this filter to also apply it to all recurring carts.

By default, the return value of this filter is set to false, so that all fees applied using WC()->cart are non-recurring fees by default.

// All fees are recurring
add_filter( 'woocommerce_subscriptions_is_recurring_fee', '__return_true' );

add_filter( 'woocommerce_cart_calculate_fees', 'add_fees', 10 );

function add_fees() {
    WC()->cart->add_fee( 'Fee', '10' );
}

If only certain fees are recurring or you would like to apply more complex conditions, you can use the $fee and $cart filter arguments.
For example:

add_filter( 'woocommerce_cart_calculate_fees', 'add_fees', 10 );

function add_fees() {
    WC()->cart->add_fee( 'Personal Engraving', 10 );
    WC()->cart->add_fee( 'Postage', 5 );
}

add_filter( 'woocommerce_subscriptions_is_recurring_fee', 'apply_recurring_fees', 10, 3 );

function apply_recurring_fees( $is_recurring, $fee, $cart ) {

    // Personal engraving fees should be charged on a recurring basis
    if ( 'personal-engraving' === $fee->id ) {
        $is_recurring = true;
    // Subscriptions with a recurring total less than $30 are required to pay on-going postage charges
    } elseif ( 'postage' === $fee->id && 30 > $cart->get_subtotal() ) {
        $is_recurring = true;
    }

    return $is_recurring;
}