When adding radio button selections to each item in the WooCommerce cart on the checkout page the Ajax seems not to pass the correct radio button selection selection all the time. It works 75% of the time, the other time it just passes the prior selection.
There are only two options presented in the table for each item, by default the top option is selected as the default for the user. I am adding a somewhat redacted image so you get the idea. The table could contain 1 item like shown or 20+, but there is always one set of selections for each item in the cart.
https://i.stack.imgur.com/fZmuI.jpg
So far I have tried different several variations of the ajax code and reworked this thing twice over the last 4 days, I am really out of ideas. I did start with this question (link below) originally that got it to work most of the way. I just do not understand why it only works 75% of the time. BTW When I say 75% of the time, I mean I have one item that I pick and I click back and forth on the two selections, I am not talking quickly here either, maybe once every 5 or 6 seconds.
Update fee dynamically based on radio buttons in Woocommerce checkout
/***** Code to add radio buttons to site for guarantees ****/
// Customizing Woocommerce radio form field
add_action( 'woocommerce_form_field_radio', 'custom_form_field_radio', 20, 4 );
function custom_form_field_radio( $field, $key, $args, $value ) {
if ( ! empty( $args['options'] ) && is_checkout() ) {
$field = str_replace( '</label><input ', '</label><br><input ', $field );
$field = str_replace( '<label ', '<label style="display:inline;margin-left:8px;" ', $field );
}
return $field;
}
// ---------------------------
add_action( 'woocommerce_cart_calculate_fees' , 'multiple_radio_switch_fees', 20, 1 );
function multiple_radio_switch_fees( $cart ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( ! is_checkout() ) return;
foreach ( $cart->get_cart() as $cart_item ) {
$id = $cart_item['data']->get_id();
$fee = WC()->session->get( 'chosen_guarantee' . $id );
if ( (substr_count($fee, '_0')) ) {
$cart->add_fee( 'Included Guarantee: ' . $itemname, 0.00 );
} else {
$cart->add_fee( 'Upgraded Guarantee: ' . $itemname, 9.00 );
}
}
}
}
// Add a custom radio fields for packaging selection
add_action( 'woocommerce_after_order_notes', 'checkout_guarantee_addition', 20 );
function checkout_guarantee_addition( ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
global $woocommerce;
$tbl .= '<div class="divTable">';
$tbl .= '<div class="divTableBody">';
$tbl .= '<div class="divTableRow">';
$tbl .= '<div class="divTableCell"><span class="freeshipping-cart-notice">Item</span></div>';
$tbl .= '<div class="divTableCell"><span class="freeshipping-cart-notice">Upgrade Guarantee</span></div>';
$tbl .= '</div>';
foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
$itemname = null;
// get the product id (or the variation id)
$id = $cart_item['data']->get_id();
// Get the pricing we will need
$itemname = $cart_item['data']->get_name();
$quantity = $cart_item['quantity'];
$tbl .= '<div class="divTableRow">';
$lsitem = sprintf('<div class="divTableCell">%s <strong class="product-quantity">× %s</strong></div>', $itemname, $quantity);
$tbl .= $lsitem;
$chosen = WC()->session->get('chosen_guarantee' . $id);
$chosen = empty($chosen) ? WC()->checkout->get_value('radio_guarantee' . $id) : $chosen;
$chosen = empty($chosen) ? $id . '_0' : $chosen;
$radios = woocommerce_form_field( 'radio_guarantee' . $id, array(
'type' => 'radio',
'class' => array( 'radio_guarantee' . $id, 'form-row-wide' ),
'options' => array(
$id . '_0' => __('Included Guarantee '.wc_price(0.00), $domain),
$id . '_1' => __('Upgraded Guarantee '.wc_price(9.00), $domain),
),
'default' => $chosen,
), $chosen );
$lspricedif = sprintf('<div class="divTableCell">%s</div>', $radios );
$tbl .= $lspricedif; // 14day $tbl .= '</div>';
$tbl .= '</div>';
}
$domain = 'woocommerce';
$tbl .= '</div>';
$tbl .= '</div>';
$tbl2 .= '</div>';
$tbl2 .= '</div>';
echo '</br><h3><span class="blueTextCheckout">'.__('Guarantee Options').'</span></h3>';
echo $tbl;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_shipping_packing_script' );
function checkout_shipping_packing_script() {
if ( ! is_checkout() )
return; // Only checkout page
?>
<script type="text/javascript">
jQuery( function($){
// Added ^ to try to get what we need
$('form.checkout').on('change', 'input[name^=radio_guarantee]', function(e){
e.preventDefault();
var p = $(this).val();
$.ajax({
type: 'POST',
dataType: 'json',
url: wc_checkout_params.ajax_url,
data: {
'action': 'woo_get_ajax_data',
'guarantee': p,
},
success: function (result) {
$('body').trigger('update_checkout');
},
error: function(error){
}
});
});
});
</script>
<?php
}
// Php Ajax (Receiving request and saving to WC session)
add_action( 'wp_ajax_woo_get_ajax_data', 'woo_get_ajax_data' );
add_action( 'wp_ajax_nopriv_woo_get_ajax_data', 'woo_get_ajax_data' );
function woo_get_ajax_data() {
if ( isset( $_POST['guarante'] ) ){
$guarantee = sanitize_key( $_POST['guarantee'] );
$id = strtok( $guarantee, '_' ); // Trying to ensure that we set the correct item radio buttons
WC()->session->set('chosen_guarantee' . $id, $guarantee );
echo json_encode( $guarantee );
}
die();
}
What is the best way to solve this? Is this even the right way to go about solving the problem?
I did put some old school debug lines in and tailed the file and it always passed one of the two selections for an item every-time. It is just that 75% of the time it was what I selected and the other 25% was the prior radio buttons info and not the one I just selected.
The running system is the latest version of wordpress and woocommerce and the server runs php 7.3 under litespeed.