Commit 827c92967b6 for woocommerce
commit 827c92967b6d3071d9a21f6a531ab01ea21dcc08
Author: SH Sajal Chowdhury <72102985+shsajalchowdhury@users.noreply.github.com>
Date: Thu Aug 27 15:38:28 2026 +0600
Fix: Non-taxable cart fees stored as taxable in order items due to missing tax_status (#66302)
* Fix: Non-taxable cart fees stored as taxable in order items (#53766)
When a non-taxable fee is added via WC_Cart::add_fee() with
= false, the order item created during checkout incorrectly
retained tax_status = 'taxable' (the default) with tax_class = '0'
(standard). Third-party tax plugins (e.g., TaxJar, Avatax) read
tax_status and calculated tax on these fees.
Root cause: create_order_fee_lines() in WC_Checkout omitted
tax_status from set_props(), so it defaulted to TAXABLE. Also,
tax_class was set to 0 (falsy but not empty) instead of the
standard-class value (empty string).
Fix: Set tax_status to 'none' and tax_class to '' when the fee is
not taxable.
* Align array assignment operators and add unit test for fee tax_status
- Align => operators in create_order_fee_lines per WordPress coding standards
- Add test_create_order_fee_lines_sets_correct_tax_status covering both
taxable and non-taxable cart fees
* Update plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Tom Cafferkey <tjcafferkey@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
diff --git a/plugins/woocommerce/changelog/fix-53766-fee-tax_status-non-taxable b/plugins/woocommerce/changelog/fix-53766-fee-tax_status-non-taxable
new file mode 100644
index 00000000000..feb7d07ec78
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-53766-fee-tax_status-non-taxable
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Set tax_status to 'none' when creating fee order items from non-taxable cart fees.
diff --git a/plugins/woocommerce/includes/class-wc-checkout.php b/plugins/woocommerce/includes/class-wc-checkout.php
index 1483ef4dc01..b24e632e3a9 100644
--- a/plugins/woocommerce/includes/class-wc-checkout.php
+++ b/plugins/woocommerce/includes/class-wc-checkout.php
@@ -9,6 +9,7 @@
*/
use Automattic\WooCommerce\Enums\OrderStatus;
+use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\Tax\TaxRateDataStore;
@@ -615,12 +616,13 @@ class WC_Checkout {
$item->legacy_fee_key = $fee_key; // @deprecated 4.4.0 For legacy actions.
$item->set_props(
array(
- 'name' => $fee->name,
- 'tax_class' => $fee->taxable ? $fee->tax_class : 0,
- 'amount' => $fee->amount,
- 'total' => $fee->total,
- 'total_tax' => $fee->tax,
- 'taxes' => array(
+ 'name' => $fee->name,
+ 'tax_class' => $fee->taxable ? $fee->tax_class : '',
+ 'tax_status' => $fee->taxable ? ProductTaxStatus::TAXABLE : ProductTaxStatus::NONE,
+ 'amount' => $fee->amount,
+ 'total' => $fee->total,
+ 'total_tax' => $fee->tax,
+ 'taxes' => array(
'total' => $fee->tax_data,
),
)
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php b/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php
index 9517be8f4cd..07db9678c6e 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php
@@ -689,6 +689,42 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
$this->assertSame( 19.0, $tax_item->get_rate_percent() );
}
+ /**
+ * @testdox create_order_fee_lines sets tax status to 'none' for non-taxable cart fees and 'taxable' for taxable ones.
+ *
+ * @testWith [true, "taxable", ""]
+ * [false, "none", ""]
+ *
+ * @param bool $taxable Whether the cart fee is taxable.
+ * @param string $expected_tax_status The expected tax status for the created fee order item.
+ * @param string $expected_tax_class The expected tax class for the created fee order item.
+ */
+ public function test_create_order_fee_lines_sets_correct_tax_status( $taxable, $expected_tax_status, $expected_tax_class ): void {
+ $product = WC_Helper_Product::create_simple_product();
+ WC()->cart->add_to_cart( $product->get_id(), 1 );
+
+ $add_fee = static function ( $cart ) use ( $taxable ) {
+ $cart->add_fee( 'Test fee', 10, $taxable );
+ };
+ add_action( 'woocommerce_cart_calculate_fees', $add_fee );
+
+ try {
+ WC()->cart->calculate_totals();
+ $order = wc_get_order( $this->sut->create_order( array( 'payment_method' => WC_Gateway_BACS::ID ) ) );
+ } finally {
+ remove_action( 'woocommerce_cart_calculate_fees', $add_fee );
+ }
+
+ $fee_items = $order->get_fees();
+
+ $this->assertCount( 1, $fee_items );
+
+ /** @var WC_Order_Item_Fee $fee_item */
+ $fee_item = array_values( $fee_items )[0];
+ $this->assertSame( $expected_tax_status, $fee_item->get_tax_status() );
+ $this->assertSame( $expected_tax_class, $fee_item->get_tax_class() );
+ }
+
/**
* @testdox Checkout page contains login form for guests.
*/