GeneratorsWooCommerceCart Fee & Discount

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.

cart-fees.php
Saved just now
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' );