Change items tax rate in WooCommerce checkout based on radio buttons Change items tax rate in WooCommerce checkout based on radio buttons wordpress wordpress

Change items tax rate in WooCommerce checkout based on radio buttons


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 settingsfunction 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 senderadd_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 receiveradd_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 conditionallyadd_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 dataadd_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 pagesadd_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