Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

303
Views
Change items tax rate in WooCommerce checkout based on radio buttons

In WooCommerce I use the plugin [WooCommerce checkout addon][1] and I have added to checkout page an additional field made of radio buttons (multiple choice). I would like to change the tax rate when customer selects a specific choice on that radio buttons field.

Based on Change Woocommerce cart items tax class based on chosen payment method answer code that change tax rate for specific payment method, I have tried to customized the code:

// Change Tax
add_action( 'woocommerce_before_calculate_totals', 'change_tax_class_based_on_radio_choice', 10, 1 );
function change_tax_class_based_on_radio_choice( $cart ) {
    $installation = WC()->session->get('wc_checkout_add_ons') ; // This code must be change 
    $value = 'pas-dinstallation' ; // the value of the radio button "woocommerce checkout addon" 
    $value2 = 'bacs' ; // value of payement methode
    $payement_methode = WC()->session->get('chosen_payment_method') ;
    //if ( $payement_methode !== $value2 ) //this one is ok for change tax if payement methode is bank transfert
        //return;
    if ( $installation !== $value ) // here i try to set the same condition with one of radio button "woocommerce checkout addon" 
    

    return;
    
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Loop through cart items
    foreach( $cart->get_cart() as $cart_item ){
        // We set "Zero rate" tax class
        $cart_item['data']->set_tax_class("Reduced rate");
    }
}

add_action('wp_footer', 'option_trigger_update_checkout');
function option_trigger_update_checkout() {
    if( is_checkout() && ! is_wc_endpoint_url() ) :
    ?>
    <script type="text/javascript">
        jQuery(function($){
            $( 'form.checkout' ).on('change', 'input[type="radio"]', function() {
                $(document.body).trigger('update_checkout');
            });
        });
    </script>
    <?php
    endif;
}

But I don't know how to make it work for my case yet. I understand that:

$installation = WC()->session->get('wc_checkout_add_ons')

is not well implemented. What I am missing?


Update - addition (related to the answer below):

As I don't need to payment method restrictions, I have removed this related line:

// Only for a specific defined payment method
if ( ! in_array( WC()->session->get('chosen_payment_method'), $payment_ids ) )
    return;

Then code works well indeed now as I expected.

However, with the "WooCommerce checkout addon" plugin, when a radio button is selected, I can see in administration in the summary of the order and in the email received, what choice has been made.

with this code, the tax is changed, but I have no information on the customer's radio choice in admin or by email.

Have you solution?


Something else:

I want to move the radio buttons before payment.

But when I replace this:

// Display radio buttons field (optional)
add_action( 'woocommerce_after_order_notes', 'installation_custom_radio_field' );
function installation_custom_radio_field( $checkout ) {

by

// Display radio buttons field (optional)
add_action( 'woocommerce_review_order_before_payment', 'installation_custom_radio_field' );
function installation_custom_radio_field( $checkout ) {

It doesn't work anymore. Can you explain why? How to make it work?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Update 2: It's much more complicated to make it work as it requires also Ajax and much more additional code…

So the following will allow to change cart items tax class on checkout page, depending on:

  • (optional) The chosen payment gateway (Here it's disabled with an empty array).
  • The chosen radio button value (from custom radio buttons).

As people don't use your WooCommerce checkout Add-ons commercial plugin, the code below displays some radio buttons on checkout page.

To make the code more dynamic, we start with a custom function that will handle all required settings:

// Custom function that handle your settings
function change_tax_class_settings(){
    return array(
        'payment_ids'   => array(), // (optional) Your targeted payment method Id(s) | Leave an empty array to disable.
        'tax_class'     => 'Reduced rate', // The desired tax rate
        'field_id'      => 'additonal_services', // the Field Id (from property name ="?????")
        'field_value'   => 'no-dinstallation', // The field targetted option key (value)

        // The below lines are optional (used for the radio buttons field display)
        'field_type'    => 'radio', // Field type
        'field_title'   =>  __('Additional services', 'woocommerce'),
        'field_default' => 'basic-installation', // The field targetted option key (value)
        'field_options' => array(
            'basic-installation' => __('Basic Installation', 'woocommerce'),
            'premium-installation' => __('Premium Installation', 'woocommerce'),
            'no-dinstallation' => __('No Installation', 'woocommerce'),
        ),
    );
}

Now we can load that settings on any function where it's required.


Then the radio buttons displayed before payment methods checkout section:

// Display radio buttons field (optional)
add_action( 'woocommerce_review_order_before_payment', 'installation_custom_radio_field' );
function installation_custom_radio_field() {
    extract( change_tax_class_settings() ); // Load settings and convert them in variables

    echo "<style>.$field_id-wrapper{padding:1em 1.41575em;background-color:#f5f5f5;margin-bottom:24px;}
    .form-row.$field_id-$field_type span label{display:inline-block;margin:0 18px 0 6px;}
    .$field_id-wrapper h3{font-weight:bold;}</style>";
    echo '<div class="'.$field_id.'-wrapper">
    <h3>'.$field_title.'</h3>';

    // Get WC Session variable value
    $value = WC()->session->get($field_id);

    woocommerce_form_field( $field_id, array(
        'type'     => $field_type,
        'label'    => '',
        'class'    => array('form-row-wide ' . $field_id . '-' . $field_type ),
        'options'  => $field_options,
        'default'  => $field_default,
        'required' => true,
    ), empty($value) ? WC()->checkout->get_value('_'.$field_id) : $value );

    echo '</div>';
}

enter image description here


The Ajax Part (jQuery Ajax and PHP Admin Wordpress Ajax sender and receiver + WC Session variable):

// jQuery code (client side) - Ajax sender
add_action('wp_footer', 'installation_checkout_js_script');
function installation_checkout_js_script() {
    if( is_checkout() && ! is_wc_endpoint_url() ) :
    // Load settings and convert them in variables
    extract( change_tax_class_settings() );

    // jQuery Ajax code
    ?>
    <script type="text/javascript">
    jQuery( function($){
        if (typeof wc_checkout_params === 'undefined')
            return false;

        var field = '#<?php echo $field_id; ?>_field input', fchecked = field+':checked';

        // Function that sen the Ajax request
        function sendAjaxRequest( value ) {
            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action': '<?php echo $field_id; ?>',
                    'value': value
                },
                success: function (result) {
                    $(document.body).trigger('update_checkout'); // Refresh checkout
                }
            });
        }

        // On ready (DOM loaded)
        sendAjaxRequest( $(fchecked).val() );

        // On change event
        $(document.body).on( 'change', field, function(){
            sendAjaxRequest( $(fchecked).val() );
        });

        // Refresh checkout on payment method change
        $( 'form.checkout' ).on('change', 'input[name="payment_method"]', function() {
            $(document.body).trigger('update_checkout'); // Refresh checkout
        });
    });
    </script>
    <?php
    endif;
}

// The Wordpress Ajax PHP receiver
add_action( 'wp_ajax_additonal_services', 'get_additonal_services' );
add_action( 'wp_ajax_nopriv_additonal_services', 'get_additonal_services' );
function get_additonal_services() {
    if ( isset($_POST['value']) ){
        // Load settings and convert them in variables
        extract( change_tax_class_settings() );

        // Update session variable
        WC()->session->set($field_id, esc_attr($_POST['value']));

        // Send back the data to javascript (json encoded)
        echo $_POST['value']; // optional
        die();
    }
}

Then the function that change cart item tax class conditionally depending on customer choices:

// Change the tax class conditionally
add_action( 'woocommerce_before_calculate_totals', 'change_tax_class_conditionally', 1000 );
function change_tax_class_conditionally( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    extract( change_tax_class_settings() ); // Load settings and convert them in variables

    // Only for a specific defined payment methods (can be disabled in the settings, with an empty array)
    if ( ! empty($payment_ids) && ! in_array( WC()->session->get('chosen_payment_method'), $payment_ids ) )
        return;

    $choice = WC()->session->get($field_id);

    // Loop through cart items
    foreach( $cart->get_cart() as $cart_item ){
        if( $choice === $field_value ) {
            $cart_item['data']->set_tax_class($tax_class);
        }
    }
}

Addition: Saving the customer choice to the order and displaying that everywhere on orders in front end, admin and on email notifications:

// Save custom field as order meta data
add_action( 'woocommerce_checkout_create_order', 'save_additonal_services_as_order_meta' );
function save_additonal_services_as_order_meta( $order ) {
    // Load settings and convert them in variables
    extract( change_tax_class_settings() );

    $choice = WC()->session->get($field_id);

    if( ! empty( $choice ) ) {
        $order->update_meta_data( '_'.$field_id, $choice );
    }
}

// Display additonal services choice before payment method everywhere (orders and emails)
add_filter( 'woocommerce_get_order_item_totals', 'display_additonal_services_on_order_item_totals', 1000, 3 );
function display_additonal_services_on_order_item_totals( $total_rows, $order, $tax_display ){
    // Load settings and convert them in variables
    extract( change_tax_class_settings() );

    $choice = $order->get_meta( '_'.$field_id ); // Get additonal services choice

    if( ! empty($choice) ) {
        $new_total_rows = [];

        // Loop through order total rows
        foreach( $total_rows as $key => $values ) {
            // Inserting the pickp store under shipping method
            if( $key === 'payment_method' ) {
                $new_total_rows[$field_id] = array(
                    'label' => $field_title,
                    'value' => esc_html($field_options[$choice]),
                );
            }
            $new_total_rows[$key] = $values;
        }
        return $new_total_rows;
    }
    return $total_rows;
}


// Display additonal services choice in Admin order pages
add_action( 'woocommerce_admin_order_data_after_billing_address', 'admin_order_display_additonal_services', 1000 );
function admin_order_display_additonal_services( $order ) {
    // Load settings and convert them in variables
    extract( change_tax_class_settings() );

    $choice = $order->get_meta( '_'.$field_id ); // Get additonal services choice

    if( ! empty($choice) ) {
        // Display
        echo '<p><strong>' . $field_title . '</strong>: ' . $field_options[$choice] . '</p>';
    }
}

All code goes on functions.php file of your active child theme (or theme). Tested and works.


Displayed choice on Orders and Email notifications (here on Order received page)

enter image description here


On Admin Single Orders pages:

enter image description here

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!