Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

280
Vistas
Set a dynamic fee based on custom checkout radio buttons and text field in WooCommerce

I am trying to create a custom checkout radio button that calculates restaurant tip in percentage.

For the radio button, the static value is working fine.

However, I want to get the subtotal and calculate certain percentage on custom radio button click.

This is my code

add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( $checkout ) {

$chosen = WC()->session->get( 'tip' );
    $chosen = empty( $chosen ) ? WC()->checkout->get_value( 'tip' ) : $chosen;
    $chosen = empty( $chosen ) ? '0' : $chosen;
    
    $total = WC()->cart->get_subtotal();
$fivetip = $total * 0.05;

    woocommerce_form_field( 'tip',  array(
        'type'      => 'radio',
        'class'     => array( 'form-row-wide', 'update_totals_on_change' ),
        'options'   => array(
            $fivetip  => '5%',
            '10.00'     => '10%',
            '15.00'     => '15%',
        ),
    ), $chosen );
    
        woocommerce_form_field( 'add_tip', array(
        'type'          => 'text',
        'class'         => array('add_tipform-row-wide'),
        'placeholder'   => __('Enter Custom Tip Amount') 
        ), $checkout->get_value( 'add_tip' ));
    
}


add_action( 'woocommerce_cart_calculate_fees', 'checkout_tip_fee', 20, 1 );
function checkout_tip_fee( $cart ) {
    if ( $radio = WC()->session->get( 'tip' ) ) {
        $cart->add_fee( 'Tip', $radio );
    }
}

add_action( 'woocommerce_checkout_update_order_review', 'checkout_tip_choice_to_session' );

function checkout_tip_choice_to_session( $posted_data ) {
    parse_str( $posted_data, $output );
    if ( isset( $output['tip'] ) ){
        WC()->session->set( 'tip', $output['tip'] );
    }
}
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

You can get it like this:

  1. Add fields to checkout
  2. Empty/deselect the fields based on the field valued (so as to leave only the radio button or the text field valued)
  3. Calculate the cost based on the field and add the fee to the cart

So:

// add custom fields to checkout
add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( $checkout ) {

    woocommerce_form_field( 'tip',  array(
        'type'    => 'radio',
        'class'   => array( 'form-row-wide', 'update_totals_on_change' ),
        'options' => array(
            '5'  => '5%',
            '10' => '10%',
            '15' => '15%',
        ),
    ));
    
    woocommerce_form_field( 'add_tip', array(
        'type'        => 'text',
        'class'       => array('add_tipform-row-wide', 'update_totals_on_change'),
        'placeholder' => __('Enter Custom Tip Amount') 
    ));

}

Now a jQuery script will empty the text field when a radio button is selected and vice versa:

// uncheck radio buttons when text field is changed
add_action( 'wp_footer', 'uncheck_radio_buttons_when_text_field_is_changed' );
function uncheck_radio_buttons_when_text_field_is_changed() {
    if ( is_checkout() && ! is_wc_endpoint_url() ) {
    ?>
    <script type="text/javascript">
    // deselect radio buttons when an amount is entered in the text field
    jQuery('#add_tip').keyup(function(){
        jQuery('#tip_field input[name=tip]').prop('checked', false);
    });
    // clears the text field when a percentage is selected
    jQuery('input[name=tip]').change(function(){
        jQuery('#add_tip').val('');
    });
    </script>
    <?php
    }
}

Finally it calculates the amount of the fee based on the selected value calculated on the subtotal (excluding taxes) of the cart.

Make sure you use the same name for the fee to add to the cart in order to overwrite the same and display only one.

// adds a custom fee based on the field valued
add_action( 'woocommerce_cart_calculate_fees', 'add_custom_fee', 10, 1 );
function add_custom_fee( $cart ) {

    // get the subtotal (excluding taxes)
    $subtotal = WC()->cart->subtotal_ex_tax;

    if ( ! $_POST || is_admin() || ! is_ajax() ) {
        return;
    }

    if ( isset( $_POST['post_data'] ) ) {
        parse_str( $_POST['post_data'], $post_data );
    } else {
        $post_data = $_POST;
    }

    // adds the fee based on the checked percentage
    if ( isset( $post_data['tip'] ) ) {
        $percentage = $post_data['tip'];
        $fee = $subtotal * $percentage / 100;
        if ( $fee > 0 ) {
            WC()->cart->add_fee( 'Tip', $fee, true );
        }
    }

    // adds the fee based on the amount entered
    if ( isset( $post_data['add_tip'] ) ) {
        $fee = (float) str_replace( ',', '.', $post_data['add_tip'] );
        if ( $fee > 0 ) {
            WC()->cart->add_fee( 'Tip', $fee, true );
        }
    }

}

The code has been tested and works. Add it to your active theme's functions.php.

over 4 years ago · Santiago Trujillo Denunciar

0

The following is something advanced using Ajax and WC Sessions:

It will add a custom a tip (as a custom fee) based on selected radio buttons options: fixed percentages options or custom option that will show a text field to allow customer to input a fixed amount.

Displayed Fields are hand coded to get a better display than WooCommerce form fields for radio buttons (see the screenshots below).

enter image description here

How it works for the customer:

On checkout page load, a Tip of 5% (a fee) is applied (selected by default). When changing the selected option to something else, the applied fee changes.

If the "custom" option is selected, the fee is removed while a text field appears below:

enter image description here
Customer can input a fixed amount and a Tip (a fee) is applied with this amount.

Here is the code:

// Display custom checkout fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_box_option_to_checkout' );
function add_box_option_to_checkout( ) {
    // Here set your radio button options (Values / Labels pairs)
    $options = array( '5'  => '5%', '10' => '10%', '15' => '15%', 'custom' => __('Custom', 'woocommerce') );

    // Radio button fields
    echo '<style> #add_tip_field.form-row label { display:inline-block; margin-left:6px; } </style>
    <p class="form-row form-row-wide" id="add_tip_field"><span class="woocommerce-input-wrapper">
    <label for="add_tip"><strong>'.__('Add a tip', 'woocommerce'). ':</strong>&nbsp;</label>';

    foreach ( $options as $value => $label_name ) {
        $checked = $value == '5' ? ' checked="checked"' : '';

        echo '<label for="add_tip_'.$value.'" class="radio ">
            <input type="radio" class="input-radio " value="'.$value.'" name="add_tip" id="add_tip_'.$value.'"'.$checked.'>&nbsp'.$label_name.'
        </label>';
    }
    echo '</span></p>';

    // Text field (hidden by default)
    echo '<p class="form-row form-row-wide" id="custom_tip_field" style="display:none""><span class="woocommerce-input-wrapper">
        <input type="text" class="input-text " name="custom_tip" id="custom_tip" value="" placeholder="'.__('Input a tip amount', 'woocommerce').'">
    </span></p>';
}

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

        var addTip    = 'input[name="add_tip"]',
            customTip = 'input[name="custom_tip"]'

        function triggerAjaxEvent( amount, type = 'percent' ){
           $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action': 'tip_fee',
                    'amount': amount,
                    'type'  : type
                },
                success: function (result) {
                    $(document.body).trigger('update_checkout');
                    console.log(result);
                },
            });
        }

        triggerAjaxEvent( $(addTip+':checked').val() );

        $('form.checkout').on('change', addTip, function() {
            var textField = $('#custom_tip_field'),
                percent   = $(this).val();

            if( percent === 'custom' && textField.css('display') === 'none' ) {
                textField.show(200);
            } else if ( percent !== 'custom' && textField.css('display') !== 'none' ) {
                textField.hide(200, function(){
                    $(customTip).val('');
                });
            }
            triggerAjaxEvent( percent );
        });

        $('form.checkout').on('input change', customTip, function() {
            triggerAjaxEvent( $(this).val(), 'custom' );
        });
    });
    </script>
    <?php
}

// Get Ajax request and save data to WC session
add_action( 'wp_ajax_tip_fee', 'get_tip_fee' );
add_action( 'wp_ajax_nopriv_tip_fee', 'get_tip_fee' );
function get_tip_fee() {
    if ( isset($_POST['amount']) && isset($_POST['type']) ) {
        $fee  = is_numeric($_POST['amount']) && $_POST['amount'] > 0 ? floatval($_POST['amount']) : 0;

        WC()->session->set('fee_data', array(
            'type'   => esc_attr($_POST['type']),
            'amount' => $fee
        ) );

        print_r(WC()->session->get('fee_data'));
    }
    die();
}


// Add a dynamic fee from WC Session ajax data
add_action( 'woocommerce_cart_calculate_fees', 'checkout_custom_tip_fee' );
function checkout_custom_tip_fee( $cart ) {
    if ( is_admin() && !defined('DOING_AJAX') )
        return;

    $data = WC()->session->get('fee_data');
    $fee  = $total = 0;

    if ( isset($data['type']) && isset($data['amount']) ) {
        // 1. Fixed Fee amount
        if ( $data['type'] === 'custom' ) {
            $text  = $data['type'];
            $fee   = $data['amount'];
        } 
        // 2. Calculated percentage Fee amount
        elseif ( $data['type'] === 'percent' && $data['amount'] > 0 ) {
            $text  = $data['amount'] . '%';

            // Get cart subtotal excl. Taxes (discounted)
            foreach ( $cart->get_cart() as $cart_item ) {
                $total = $cart_item['line_total'];
            }
            // Calculate fee
            $fee   = $total * $data['amount'] / 100 ;
        }
        // Add the fee
        if ( $fee > 0 ) {
            $cart->add_fee( sprintf( __('Tip (%s)', 'woocommerce' ), $text ), $fee );
        }
    }
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.


Addition related to your comment:

To use cart items total including taxes replace in last function:

            // Get cart subtotal excl. Taxes (discounted)
            foreach ( $cart->get_cart() as $cart_item ) {
                $total = $cart_item['line_total'];
            }

with

            // Get cart subtotal Incl. Taxes (discounted)
            foreach ( $cart->get_cart() as $cart_item ) {
                $total = $cart_item['line_total'] + $cart_item['line_tax'];
            }
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda