Reputation: 105
I've been looking for a solution to this for a while now... I am trying to show or hide specific shipping rates based on a radio button option added to the Woocommerce checkout page. But I don't know anything about Ajax & JQuery which I believe it requires.
Basically if a user selects radio option_1 it will ONLY show 'flat_rate:1' & 'flat_rate:2'. If the user selects radio option_2 it will ONLY show 'flat_rate:3' & 'flat_rate:4'
Click here for example of checkout screen
Here is the code for my radio buttons displayed on checkout page:
add_action( 'woocommerce_review_order_before_payment','tc_checkout_radio_choice' );
function tc_checkout_radio_choice() {
$businesstype = array(
'type' => 'radio',
'class' => array( 'business_residential' ),
'required' => true,
'options' => array(
'option_1' => 'Business',
'option_2' => 'Residential',
),
);
echo '<div id="checkout-radio">';
echo '<h3>Select Your Business Type</h3>';
woocommerce_form_field( 'radio_choice', $businesstype );
echo '</div>';
}
The closest example I've seen comes from an answer provided by 'LoicTheAztec' in this post here: Show/hide shipping methods based on a WooCommerce checkout field value
I'm completely lost with this and the more I try to solve it, the more I get confused.
Upvotes: 2
Views: 1389
Reputation: 253919
Here is the correct way to show hide shipping methods based on multiple radio buttons choice on checkout page, that requires to use PHP, Ajax, jQuery and WC Session.
When "Business" radio button is selected (default choice), flat_rate:3
and flat_rate:4
shipping methods will be hidden, so customer will only be able to choose flat_rate:1
or flat_rate:2
shipping methods.
If "Residential" radio button is selected then flat_rate:1
and flat_rate:2
shipping methods will be hidden, so customer will only be able to choose flat_rate:3
or flat_rate:4
shipping methods.
The code:
// Display a Custom radio buttons fields for shipping options
add_action( 'woocommerce_review_order_before_payment','checkout_customer_type_radio_buttons' );
function checkout_customer_type_radio_buttons() {
$field_id = 'customer_type';
echo '<div id="customer-type-radio">';
echo '<h3>' . __("Select Your Business Type", "woocommerce") . '</h3>';
// Get the selected radio button value (if selected)
$field_value = WC()->session->get( $field_id );
// Get customer selected value on last past order
if( empty($field_value) )
$field_value = WC()->checkout->get_value( $field_id );
// The default value fallback
if( empty($field_value) )
$field_value = 'Business';
woocommerce_form_field( $field_id, array(
'type' => 'radio',
'class' => array( $field_id ),
'required' => true,
'options' => array(
'Business' => __('Business', 'woocommerce'),
'Residential' => __('Residential', 'woocommerce'),
),
), $field_value );
echo '</div>';
}
// Conditionally show/hide shipping methods
add_filter( 'woocommerce_package_rates', 'shipping_package_rates_filter_callback', 100, 2 );
function shipping_package_rates_filter_callback( $rates, $package ) {
$customer_type = WC()->session->get( 'customer_type' ); // Get the customere type
if ( $customer_type === 'Business' ) {
if( isset( $rates['flat_rate:3'] ) )
unset( $rates['flat_rate:3'] );
if( isset( $rates['flat_rate:4'] ) )
unset( $rates['flat_rate:4'] );
}
elseif ( $customer_type === 'Residential' ) {
if( isset( $rates['flat_rate:1'] ) )
unset( $rates['flat_rate:1'] );
if( isset( $rates['flat_rate:2'] ) )
unset( $rates['flat_rate:2'] );
}
return $rates;
}
// function that gets the Ajax data
add_action( 'wp_ajax_get_customer_type', 'wc_get_customer_type' );
add_action( 'wp_ajax_nopriv_get_customer_type', 'wc_get_customer_type' );
function wc_get_customer_type() {
$field_id = 'customer_type';
if ( isset($_POST[$field_id]) && ! empty($_POST[$field_id]) ){
WC()->session->set($field_id, $_POST[$field_id] );
}
echo json_encode( WC()->session->get( $field_id ) );
die(); // (required)
}
// The Jquery Ajax script
add_action( 'wp_footer', 'custom_checkout_ajax_jquery_script' );
function custom_checkout_ajax_jquery_script() {
$field_id = 'customer_type';
if( WC()->session->__isset($field_id) )
WC()->session->__unset($field_id);
// Only on checkout when billing company is not defined
if( is_checkout() && ! is_wc_endpoint_url() ):
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
var fieldId = 'p#customer_type_field input';
function userTypeTriggerAjax( customerType ){
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'get_customer_type',
'customer_type': customerType,
},
success: function (result) {
// Trigger refresh checkout
$('body').trigger('update_checkout');
console.log(result);
}
});
}
// On start
if( $(fieldId).val() != '' ) {
userTypeTriggerAjax( $(fieldId).val() );
}
// On change
$(fieldId).change( function () {
userTypeTriggerAjax( $(this).val() );
});
});
</script>
<?php
endif;
}
// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( in_array( WC()->session->get('customer_type' ), ['Business', 'Residential'] ) )
$bool = false;
// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Code based on this related threads:
Upvotes: 3
Reputation: 105
If anyone wants to know how to make this a required option with an error notification before payment, this is what I did...
To de-select the radio buttons I removed the value from:
//if( empty($field_value) )
$field_value = '';
And added this code to the checkout process at the end of the code from Loic, which adds a notification message if a radio button has not been selected:
// Show notice if customer does not select a business type
add_action( 'woocommerce_checkout_process', 'business_type_error_message' );
function business_type_error_message() {
if ( ! (int) isset( $_POST['customer_type'] ) ) {
wc_add_notice( __( 'Please select an order type to calculate the correct shipping and proceed with your order.' ), 'error' );
}
}
Hope this helps others out there!
Upvotes: 1