WooCommerce: Per-Product Checkout Fees / Tariffs

If your WooCommerce store sells products that require extra charges — think tariffs, recycling fees, or packaging costs — you may want to apply those fees only to specific products or variations. Instead of using blanket fees at the cart level, this snippet gives you granular control by letting you toggle the fee on or off for each product directly from the edit screen.

Once enabled, the fee is calculated as a fixed percentage (e.g. 20%) and automatically added at checkout. This works for simple and variable products.

Whether you need to meet regulatory requirements or recover specific costs, this solution offers a flexible, admin-friendly way to charge per-product fees.

WooCommerce Checkout Page showing two products with a 20% tariff fee applied automatically as separate line items.

PHP Snippet: Add Optional Product Fees in WooCommerce

This snippet enables store owners to apply optional, per-product fees in WooCommerce, ideal for tariffs or special surcharges. First, it adds a checkbox to both simple products and single variations in the backend. This allows the admin to enable a fee manually for each item.

When a product with the fee enabled is added to the cart, the fee is calculated as a percentage of the product’s price before tax (and specifically a 20% tariff, hardcoded in the bbloomer_checkout_fee function). If a variation doesn’t have its own fee setting, the parent product’s setting is used.

Finally, during checkout, WooCommerce adds the fee as a separate line item, using a custom label (hardcoded in the bbloomer_checkout_fee function) and matching the product’s tax class.

/**
 * @snippet       Per-Product / Per-Variation Fee @ WooCommerce Checkout
 * @tutorial      https://businessbloomer.com/woocommerce-customization
 * @author        Rodolfo Melogli, Business Bloomer
 * @compatible    WooCommerce 9
 * @community     https://businessbloomer.com/club/
 */

// Add checkbox to simple products
add_action( 'woocommerce_product_options_general_product_data', 'bbloomer_product_fee' );
function bbloomer_product_fee() {
    woocommerce_wp_checkbox( [
        'id' => '_enable_custom_fee',
        'label' => 'Enable Fee',
        'description' => 'Apply fee at checkout for this product.',
    ] );
}

// Save checkbox for simple products
add_action( 'woocommerce_process_product_meta', 'bbloomer_product_fee_save' );
function bbloomer_product_fee_save( $post_id ) {
    update_post_meta( $post_id, '_enable_custom_fee', isset( $_POST['_enable_custom_fee'] ) ? 'yes' : 'no' );
}

// Add checkbox to product variations
add_action( 'woocommerce_variation_options_pricing', 'bbloomer_variation_fee', 10, 3 );
function bbloomer_variation_fee( $loop, $variation_data, $variation ) {
    woocommerce_wp_checkbox( [
        'id' => '_enable_custom_fee[' . $loop . ']',
        'label' => 'Enable Fee',
        'description' => 'Apply fee at checkout for this variation.',
        'value' => get_post_meta( $variation->ID, '_enable_custom_fee', true ),
    ] );
}

// Save variation checkbox
add_action( 'woocommerce_save_product_variation', 'bbloomer_variation_fee_save', 10, 2 );
function bbloomer_variation_fee_save( $variation_id, $i ) {
    $fee_value = isset( $_POST['_enable_custom_fee'][ $i ] ) ? 'yes' : 'no';
    update_post_meta( $variation_id, '_enable_custom_fee', $fee_value );
}

// Add fee at checkout
add_action( 'woocommerce_cart_calculate_fees', 'bbloomer_checkout_fee', 9999 );
function bbloomer_checkout_fee( $cart ) {
	
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
	
	 $tariff_percent = 20; // SET THE FEE PERCENTAGE
    $fee_label = 'Import Fee'; // SET THE LABEL

    foreach ( $cart->get_cart() as $cart_item ) {

		  $product_id = $cart_item['variation_id'] > 0 ? $cart_item['variation_id'] : $cart_item['product_id'];
		  $parent_id = $cart_item['product_id'];
        $enable_fee = get_post_meta( $product_id, '_enable_custom_fee', true );
		
		  // Fallback to parent product if variation doesn't have its own setting
        if ( $enable_fee !== 'yes' && $product_id !== $parent_id ) {
            $enable_fee = get_post_meta( $parent_id, '_enable_custom_fee', true );
        }

        if ( $enable_fee === 'yes' ) {
            $fee_amount = $tariff_percent / 100 * wc_get_price_excluding_tax( $cart_item['data'] ) * $cart_item['quantity'];
            $cart->add_fee( $fee_label . ' (' . $cart_item['data']->get_name() . ')', $fee_amount, true, $cart_item['data']->get_tax_class() );
        }
		
    }
	
}

Where to add custom code?

You should place custom PHP in functions.php and custom CSS in style.css of your child theme: where to place WooCommerce customization?

This code still works, unless you report otherwise. To exclude conflicts, temporarily switch to the Storefront theme, disable all plugins except WooCommerce, and test the snippet again: WooCommerce troubleshooting 101

Related content

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza. Follow @rmelogli

Questions? Feedback? Customization? Leave your comment now!
_____

If you are writing code, please wrap it like so: [php]code_here[/php]. Failure to complying with this, as well as going off topic or not using the English language will result in comment disapproval. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining the Business Bloomer Club to get quick WooCommerce support. Thank you!

Your email address will not be published. Required fields are marked *