phpjquerywordpresswoocommerceradio-button

Add radio button selected value as custom cart item data via Ajax add to cart on WooCommerce products loop


I added a custom field to the product

function my_add_radio_field() { ?>
<div class="custom-field-wrap gender-field-wrap" style="margin: 10px;">
<h4>Gender?</h4>
<div class="form-check form-check-inline">
<label for="g-gender-boy">Boy</label>
<input type="radio" id="g-gender-boy" name="g_gender" value="boy" />
</div>
<div class="form-check form-check-inline">
<label for="g-gender-girl">Girl</label>
<input type="radio" id="g-gender-girl" name="g_gender" value="girl" />
</div>
</div>
<?php
}
add_action( 'woocommerce_before_add_to_cart_button', 'my_add_radio_field' );

Added validation

function my_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = null ) {
    if (empty( $_POST['g_gender'] )) {
        $passed = false;
        wc_add_notice( __( 'Gender is a required field.', 'my-theme' ), 'error' );
    }
    return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'my_add_to_cart_validation', 10, 4 );

Adding the custom field data

function myr_add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
    if ( isset( $_POST['g_gender'] ) ) {
        $cart_item_data['custom_data']['guest_gender'] = sanitize_text_field( $_POST['g_gender'] );
    }
    return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'myr_add_cart_item_data', 10, 3 );

Display in the cart

function display_custom_data_in_cart($item_data, $cart_item)
{
if (isset($cart_item['custom_data']['guest_gender']) && !empty($cart_item['custom_data']['guest_gender'])) {
            $item_data[] = array(
                'key' => 'Gender',
                'value' => $cart_item['custom_data']['guest_gender'],
            );
        }
    }
    return $item_data;
}
add_filter('woocommerce_get_item_data', 'display_custom_data_in_cart', 10, 2);

It all works. "AJAX add to cart buttons on archives" - enabled. When I click add to cart on the category page, I am redirected to the product page to fill out the field. How can I make it possible to select on the category page and buy without going to the product?

I can add field to the loop after product title but what next?
add_action( 'woocommerce_shop_loop_item_title', 'my_add_radio_field' );


Solution

  • To add custom required radio buttons to products on WooCommerce archive pages and add the selected value as custom cart item data, you can use the following:

    // Utility function: Custom radio buttons HTML output
    function custom_input_radio_field( $field_key ) { 
        printf( '<div class="custom-field-wrap gender-field-wrap" style="margin: 10px;">
            <h4>%s</h4><div class="form-check form-check-inline">
            <label for="g-gender-boy">%s</label>
            <input type="radio" id="g_gender-boy" name="%s" value="boy" />
            </div> <div class="form-check form-check-inline">
            <label for="g-gender-girl">%s</label>
            <input type="radio" id="g_gender-girl" name="%s" value="girl" />
        </div></div>', __('Gender?', 'woocommerce'), __('Boy', 'woocommerce'),  $field_key, __('Girl', 'woocommerce'), $field_key );
    }
        
    
    // On product loop (archive pages)
    add_action( "woocommerce_after_shop_loop_item", 'loop_product_add_custom_input_radio_field', 3 );
    function loop_product_add_custom_input_radio_field() { 
        global $product;
    
        if ( $product->supports( 'ajax_add_to_cart' ) && $product->is_purchasable() && $product->is_in_stock() ) {
            custom_input_radio_field( 'g_gender-'.$product->get_id() );
        }
    }
    
    // On single product
    add_action( 'woocommerce_before_add_to_cart_button', 'single_product_add_custom_input_radio_field', 10 );
    function single_product_add_custom_input_radio_field() { 
        custom_input_radio_field( 'g_gender' );
    }
    
    // Field validation
    add_filter( 'woocommerce_add_to_cart_validation', 'validate_custom_input_radio_field', 10, 1 );
    function validate_custom_input_radio_field( $passed ) {
        if ( isset($_REQUEST['g_gender']) && empty($_REQUEST['g_gender']) ) {
            wc_add_notice( __( 'Gender is a required field.', 'woocommerce' ), 'error' );
            return false;
        }
        return $passed;
    }
    
    // jQuery code add the radio button selected value to the request on Ajax add to cart
    add_action( "init", 'custom_radio_field_loop_jquery_script', 1 );
    function custom_radio_field_loop_jquery_script() {
        wc_enqueue_js( "$(document.body).on('adding_to_cart', function( e, btn, data ){
            const radio  = '[name=\"g_gender-'+data.product_id+'\"]',
                radioVal = $(radio+':checked').val();
                    
            data['g_gender'] = radioVal ? radioVal : 0;
            return data['g_gender'];
        });" );
    }
    
    // Add checked radio button value as custom cart item data
    add_action( 'woocommerce_add_cart_item_data', 'add_cart_item_radio_field_value', 10, 2 );
    function add_cart_item_radio_field_value( $cart_item_data, $product_id ) {
        if ( isset($_REQUEST['g_gender']) && !empty($_REQUEST['g_gender']) ) {
           $cart_item_data[ 'gender' ] = esc_attr($_REQUEST['g_gender']);
           $cart_item_data['unique_key'] = md5( microtime().rand() );
        }
        return $cart_item_data;
    }
    
    // Display Gender value in minicart, cart and checkout
    add_filter( 'woocommerce_get_item_data', 'display_cart_item_gender_value', 10, 2 );
    function display_cart_item_gender_value( $cart_data, $cart_item ) {
        if( isset($cart_item['gender']) ) {
            $cart_data[] = array( 
                'name'  => __('Gender', 'woocommerce'), 
                'value' => $cart_item['gender'] 
            );
        }
        return $cart_data;
    }
    
    // Save Gender value as custom order item data and display it on orders and emails
    add_action( 'woocommerce_checkout_create_order_line_item', 'add_order_item_gender_value', 10, 4 );
    function add_order_item_gender_value( $item, $cart_item_key, $values, $order ) {
        if( isset($values['gender']) ) {
            $item->add_meta_data( 'gender', $values['gender'], true );
        }
    }
    
    // Change Gender displayed meta key label to something readable
    add_filter('woocommerce_order_item_display_meta_key', 'filter_order_item_displayed_meta_key', 20, 3 );
    function filter_order_item_displayed_meta_key( $displayed_key, $meta, $item ) {
        if( $item->get_type() === 'line_item' && $meta->key === 'gender' ) {
            $displayed_key = __('Gender', 'woocommerce');
        }
        return $displayed_key;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Works with Ajax add to cart on product loops (and also on single product pages).

    The code also saves the selected Gender as custom order item metadata and display it on orders and email notifications.