Estoy tratando de crear un botón de opción de pago personalizado que calcule la propina del restaurante en porcentaje.
Para el botón de radio, el valor estático funciona bien.
Sin embargo, quiero obtener el subtotal y calcular cierto porcentaje al hacer clic en el botón de opción personalizado.
este es mi codigo
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'] ); } }Puedes conseguirlo así:
Entonces:
// 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') )); }Ahora, un script jQuery vaciará el campo de texto cuando se seleccione un botón de opción y viceversa:
// 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 } }Finalmente calcula el monto de la tarifa en base al valor seleccionado calculado sobre el subtotal (sin impuestos) del carrito.
Asegúrese de usar el mismo nombre para la tarifa para agregar al carrito para sobrescribir la misma y mostrar solo una.
// 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 ); } } }El código ha sido probado y funciona. Agréguelo a functions.php de su tema activo.
Lo siguiente es algo avanzado usando Ajax y WC Sessions :
Agregará una propina personalizada (como una tarifa personalizada) basada en las opciones de los botones de radio seleccionados: opciones de porcentajes fijos u opción personalizada que mostrará un campo de texto para permitir que el cliente ingrese una cantidad fija.
Los campos mostrados están codificados a mano para obtener una mejor visualización que los campos de formulario de WooCommerce para los botones de opción (vea las capturas de pantalla a continuación).
Cómo funciona para el cliente:
Al cargar la página de pago, se aplica una propina del 5 % (una tarifa) (seleccionada de forma predeterminada) . Al cambiar la opción seleccionada a otra, la tarifa aplicada cambia.
Si se selecciona la opción "personalizada", la tarifa se elimina mientras aparece un campo de texto a continuación:

El cliente puede ingresar una cantidad fija y se aplica una propina (una tarifa) con esta cantidad.
Aquí está el código:
// 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> </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.'> '.$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 ); } } }El código va en el archivo functions.php del tema secundario activo (o tema activo). Probado y funciona.
Adición relacionada con su comentario:
Para usar el total de artículos del carrito, including los impuestos, reemplace en la última función:
// Get cart subtotal excl. Taxes (discounted) foreach ( $cart->get_cart() as $cart_item ) { $total = $cart_item['line_total']; }con
// Get cart subtotal Incl. Taxes (discounted) foreach ( $cart->get_cart() as $cart_item ) { $total = $cart_item['line_total'] + $cart_item['line_tax']; }