Cart Fee & Discount Generator
Conditional surcharges and negative-fee discounts on woocommerce_cart_calculate_fees — with a sample cart to prove the arithmetic before it reaches a shopper.
Setup
Percentage fees read get_subtotal(). Coupons do not affect it. Fees never compound — they are not part of the subtotal, so a second percentage fee is taken from the same figure as the first.
Fees & discounts
3 rules · 0 negative
Handling feefee id: handling-fee
%
Apply only when
Added when the basis is at least 25.00.
Oversized item surchargefee id: oversized-item-surcharge
per item
Apply only when
Added when an item is in oversized.
Cash on delivery feefee id: cash-on-delivery-fee
£
Apply only when
Added when cod is the chosen gateway.
Output
Skip the admin
is_admin() && ! DOING_AJAX — keeps the callback out of order-edit screens where there is no session.
Only add fees above zero
Guards each add_fee() with $amount > 0 so an empty row never reaches the cart totals.
Refresh checkout on gateway change
wc_enqueue_js() that triggers update_checkout — required for any payment-method condition.
Style negative fee rows
A woocommerce_cart_totals_fee_html filter that wraps discount amounts in their own span.
Include the coupon alternative
Appends the commented programmatic-coupon approach when the file adds a discount.
A complete single-file plugin that declares WooCommerce as a dependency.
<?php // Generated with WP CodeKit — powered by GrowQuest (https://growquest.io). /** * Plugin Name: Cart fees and discounts * Description: Conditional fees and negative-fee discounts on the WooCommerce cart. * Version: 1.0.0 * Requires PHP: 7.4 * Requires Plugins: woocommerce * Text Domain: acme */ defined( 'ABSPATH' ) || exit; /** * Whether the cart holds a product in one of the categories. * * @param WC_Cart $cart Cart object. * @param array $slugs product_cat slugs. * @return bool */ function acme_cart_has_category( $cart, $slugs ) { foreach ( $cart->get_cart() as $item ) { if ( has_term( $slugs, 'product_cat', $item['product_id'] ) ) { return true; } } return false; } /** * Add the cart fees and discounts. * * @param WC_Cart $cart Cart object, passed by reference. */ function acme_add_cart_fees( $cart ) { if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return; } if ( ! $cart instanceof WC_Cart || $cart->is_empty() ) { return; } $subtotal = (float) $cart->get_subtotal(); $items = $cart->get_cart_contents_count(); $payment = (string) WC()->session->get( 'chosen_payment_method' ); $decimals = wc_get_price_decimals(); // Handling fee — 3.5% of get_subtotal(). $amount = round( $subtotal * ( 3.5 / 100 ), $decimals ); $amount = min( $amount, 12.00 ); if ( $amount > 0 && $subtotal >= 25.00 ) { $cart->add_fee( __( 'Handling fee', 'acme' ), $amount, true, '' ); } // Oversized item surcharge — 4.00 per item in the cart. $amount = round( 4.00 * $items, $decimals ); if ( $amount > 0 && acme_cart_has_category( $cart, array( 'oversized' ) ) ) { $cart->add_fee( __( 'Oversized item surcharge', 'acme' ), $amount, true, '' ); } // Cash on delivery fee — a flat 2.50. $amount = 2.50; if ( $amount > 0 && in_array( $payment, array( 'cod' ), true ) ) { $cart->add_fee( __( 'Cash on delivery fee', 'acme' ), $amount, false ); } } add_action( 'woocommerce_cart_calculate_fees', 'acme_add_cart_fees' ); /** * Recalculate the checkout totals when the shopper switches payment method. */ function acme_refresh_checkout_on_payment_change() { if ( ! is_checkout() ) { return; } wc_enqueue_js( "jQuery( document.body ).on( 'change', 'input[name=payment_method]', function() { jQuery( document.body ).trigger( 'update_checkout' ); } );" ); } add_action( 'wp_footer', 'acme_refresh_checkout_on_payment_change' );