• Resolved gerche

    (@gerche)


    Hello all,

    I have a woocommerce website with two tax classes.

    Standard (21%)
    Reduced rate (6%)

    • When I only have 21% products in my chart the shipping cost should be taxed 21%
    • When I only have 6% products in my chart the shipping cost should be taxed 6%
    • When i have products of both tax classes in my chart the flat shipping rate is taxed with 21% but should be taxed with 6%.

    It’s the last point that doesn’t seem to work, the shipping tax always defaults to 21% when i have mixed products. How can I make sure it uses the reduced tax rate?

Viewing 5 replies - 1 through 5 (of 5 total)
  • Plugin Support Shameem R. a11n

    (@shameemreza)

    Hi @gerche,

    In WooCommerce, the shipping tax class is based on the items in the cart. If you have multiple tax classes in the cart, the shipping tax class will default to the standard rate (in your case, 21%). This is the default behavior of WooCommerce and cannot be changed without custom coding.

    However, you can use a plugin to set the shipping tax class based on the products in the cart, such as the WooCommerce Table Rate Shipping or the WooCommerce Advanced Shipping plugin. This plugin allows you to set up different shipping methods based on the tax class of the products in the cart.

    I hope this helps! Please let us know how it goes or if you need further assistance.

    Thread Starter gerche

    (@gerche)

    Hi @shameemreza,

    Thank you for your reply.

    I checked out the plugins and it seems they can’t exactly achieve this (unless I’m missing something).

    Non of them allow me to manage the logic of the shipping tax class selection.

    The advanced shipping plugin has a “tax” option but this only uses the total tax amount not the classes of the products:

    And the table rate plugin also has no option to select the tax class. Even if this dropdown had the option it would allow me to set the cost of the shipping and not the tax class on it:

    I was hoping to perhaps achieve the result with some php code but am not sure how to overwrite the shipping tax class after checking if there is an item with the reduced tax in the chart. I got the following code working and logging “Applying 6% tax class to shipping.” but am missing the last step. Any ideas?

    add_action( 'woocommerce_cart_calculate_fees', 'custom_shipping_tax_class', 10, 1 );
    function custom_shipping_tax_class( $cart ) {
    
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
            error_log('Exiting Custom Shipping Tax Class function due to admin page or non-AJAX call.');
            return;
        }
    
        $tax_class_6 = false;
    
        // Check each cart item for their tax class
        foreach ( $cart->get_cart() as $cart_item ) {
            $product = $cart_item['data'];
            $tax_status = $product->get_tax_status();
            
            if ( 'taxable' === $tax_status ) {
                $product_tax_class = $product->get_tax_class();
                error_log('Product ID ' . $product->get_id() . ' is taxable with tax class: ' . $product_tax_class);
    
                if ( 'gereduceerd-tarief' === $product_tax_class ) {
                    $tax_class_6 = true;
                }
            }
        }
    
        error_log('Tax Class 6: ' . ($tax_class_6 ? 'true' : 'false'));
    
        // Determine the tax class for shipping based on the cart items
        $shipping_tax_class = '';
        if ( $tax_class_6 ) {
            $shipping_tax_class = 'gereduceerd-tarief';
        }
    
        
        if ( ! empty( $shipping_tax_class ) ) {
            error_log('Applying 6% tax class to shipping.');
            // Apply the reduced tax class to shipping
        } else {
            error_log('No shipping tax class applied.');
        }
    }
    Plugin Support Shameem R. a11n

    (@shameemreza)

    Hi @gerche,

    Thanks for sharing further information and letting me know the limitations of those plugins.

    The code you’ve shared is a good start, but it’s missing the final step: applying the tax class to the shipping cost. You can do this by using the woocommerce_package_rates filter, which allows you to modify the tax class of the shipping rates.

    Although writing or providing custom code is not within the scope of our support policy, you may try something like below:

    add_filter( 'woocommerce_package_rates', 'custom_shipping_tax_class', 10, 2 );
    function custom_shipping_tax_class( $rates, $package ) {
    $tax_class_6 = false;
    
    // Check each cart item for their tax class
    foreach ( $package['contents'] as $cart_item ) {
    $product = $cart_item['data'];
    $tax_status = $product->get_tax_status();
    
    if ( 'taxable' === $tax_status ) {
    $product_tax_class = $product->get_tax_class();
    
    if ( 'gereduceerd-tarief' === $product_tax_class ) {
    $tax_class_6 = true;
    }
    }
    }
    
    // Determine the tax class for shipping based on the cart items
    $shipping_tax_class = '';
    if ( $tax_class_6 ) {
    $shipping_tax_class = 'gereduceerd-tarief';
    }
    
    // Apply the reduced tax class to shipping
    if ( ! empty( $shipping_tax_class ) ) {
    foreach ( $rates as $rate ) {
    $rate->tax_class = $shipping_tax_class;
    }
    }
    
    return $rates;
    }

    If you are still having problems, we recommend asking development questions on the #developers channel of the WooCommerce Community Slack. Many of our developers hang out there and will be able to offer insights into your question. You can also seek help from the following:

    I wish I could help more, but hopefully, this gets you going in the right direction to get the job done.

    Thread Starter gerche

    (@gerche)

    Hi @shameemreza,

    Thanks for the feedback and apologies for going out of the support scope with my follow up question.

    The “tax_class” attribute didn’t seem to exist on the $rate object but I did find a “taxes” attribute with an array containing the total tax cost. This allowed me to calculate the actual shipping tax cost myself and overwrite it. I’ll post the code incase anybody else would ever need it:

    add_filter( 'woocommerce_package_rates', 'custom_shipping_tax_class', 10, 2 );
    function custom_shipping_tax_class( $rates, $package ) {
        $tax_class_6 = false;
        
        // Check each cart item for their tax class
        foreach ( $package['contents'] as $cart_item ) {
            $product = $cart_item['data'];
            $tax_status = $product->get_tax_status();
            
            if ( 'taxable' === $tax_status ) {
                $product_tax_class = $product->get_tax_class();
                
                if ( 'gereduceerd-tarief' === $product_tax_class ) {
                    $tax_class_6 = true;
                }
            }
        }
        
        $shipping_tax_class = '';
        if ( $tax_class_6 ) {
            $shipping_tax_class = 'gereduceerd-tarief';
        }
        
        if ( ! empty( $shipping_tax_class ) ) {
            foreach ( $rates as $rate_id => $rate ) {
                if ( 'flat_rate' === $rate->method_id ) {
                    $tax_rates = WC_Tax::get_rates( $shipping_tax_class );
                    
                    // Calculate the tax based on the cost
                    $taxes = WC_Tax::calc_shipping_tax( $rate->cost, $tax_rates );
                    
                    $rate->taxes = $taxes;
                    
                    // Update the rate in the array
                    $rates[ $rate_id ] = $rate;
                }
            }
        }
        
        return $rates;
    }

    Thanks for the help!

    • This reply was modified 8 months, 2 weeks ago by gerche.

    Hey, @gerche!

    Thank you for sharing the code and contributing to the WooCommerce community! This might help other users in the future.

    Please let us know if there’s anything else we can do to help or if you have any questions.

    Have a wonderful day!

Viewing 5 replies - 1 through 5 (of 5 total)
  • The topic ‘How to choose the tax class for shipping’ is closed to new replies.