Add cart fees based on the product’s category in WooCommerce with PHP

/**
 * Adds cart fees based on the product's category.
 *
 * @see https://wpcodebook.com/cart-fees-product-category-woocommerce-php/
 * @see https://github.com/woocommerce/woocommerce/blob/8.0.1/plugins/woocommerce/includes/class-wc-cart.php#L1893
 * @see https://github.com/woocommerce/woocommerce/blob/8.0.1/plugins/woocommerce/includes/class-wc-cart.php#L1919
 * @see https://github.com/woocommerce/woocommerce/blob/8.0.1/plugins/woocommerce/includes/class-wc-cart.php#L597
 * @see https://github.com/woocommerce/woocommerce/blob/8.0.1/plugins/woocommerce/includes/abstracts/abstract-wc-product.php
 * @see https://developer.wordpress.org/reference/functions/get_term_by/
 */
add_action( 'woocommerce_cart_calculate_fees', function ( $cart ) {

	// Set your fees here, in `category slug` => `fee amount` format
	$fee_amounts = array(
		'shirts'      => 10.50,
		'jackets'     => 12.50,
		'accessories' => 15.00,
	);

	// Prepare fees
	$fees = array();
	foreach ( $cart->get_cart() as $cart_item_key => $values ) {
		if ( is_a( $values['data'], 'WC_Product' ) ) {
			$product = $values['data'];

			// Get product categories
			$category_ids = $product->get_category_ids();
			if (
				empty( $category_ids ) &&
				0 != ( $parent_id = $product->get_parent_id() ) &&
				( $parent_product = wc_get_product( $parent_id ) )
			) {
				$category_ids = $parent_product->get_category_ids();
			}

			// Product categories loop
			foreach ( $category_ids as $category_id ) {
				if (
					( $term = get_term_by( 'term_id', $category_id, 'product_cat' ) ) &&
					! empty( $fee_amounts[ $term->slug ] )
				) {
					$name = sprintf( esc_html__( '%s fee (%s)' ), $product->get_name(), $term->name );
					if ( ! isset( $fees[ $name ] ) ) {
						$fees[ $name ] = 0;
					}
					$fees[ $name ] += ( $fee_amounts[ $term->slug ] * $values['quantity'] );
				}
			}

		}
	}

	// Add fees
	if ( ! empty( $fees ) ) {
		foreach ( $fees as $name => $amount ) {
			/**
			 * - WooCommerce sorts fees by amount (see the `woocommerce_sort_fees_callback` filter).
			 * - Last two params are `taxable` and `tax_class`.
			 */
			$cart->add_fee( $name, $amount, true, '' );
		}
	}

} );

Leave a Comment