I am developing an online store that offers local delivery days according to zip code. I have limited the zip codes with a selection using this snippet
add_filter ('woocommerce_default_address_fields', 'custom_override_default_postcode_field');
function custom_override_default_postcode_field ($address_fields) {
// Zip codes
$postcode_array = array (
'28001' => '28001',
'28002' => '28002',
'28923' => '28923'
);
$address_fields['postcode']['type'] = 'select';
$address_fields['postcode']['options'] = $postcode_array;
return $address_fields;
}
I am using the plugin woocommerce checkout field editor and I've added field "delivery days", which is a select field with the values Monday, Tuesday, Wednesday ...
Now, I want to make the second field dependent on the first, according to my client's specifications, for example:
Zip code 28001 / Delivery Days Monday and Wednesday
Zip code 28002 / Delivery days Tuesday and Thursday
Zip code 28923 / Delivery Days Friday and Sunday
That is, when the buyer chooses a postal code, it only shows him to choose the corresponding days.
If there is a way to do that without the plugin I think it will be better
Thanks a lot for your help, Luis
This required a lots of customization. Try the below code. code goes to your active theme functions.php file.
add_filter ('woocommerce_default_address_fields', 'custom_override_default_postcode_field');
function custom_override_default_postcode_field ($address_fields) {
// Zip codes
$postcode_array = array (
'28001' => '28001',
'28002' => '28002',
'28923' => '28923'
);
$address_fields['postcode']['type'] = 'select';
$address_fields['postcode']['options'] = $postcode_array;
return $address_fields;
}
You can add a new dropdown field Delivery days
using the woocommerce_checkout_fields
filter hook.
add_filter( 'woocommerce_checkout_fields' , 'custom_delivery_days_woocommerce_billing_fields' );
function custom_delivery_days_woocommerce_billing_fields( $fields ) {
$fields['billing']['delivery_days'] = array(
'label' => __('Delivery days', 'woocommerce'),
'placeholder' => _x('dropdown', 'placeholder', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide'),
'clear' => true,
'priority' => 95,
'type' => 'custom_select',
'options' => array(
'monday' => array(
'label' => __('Monday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28001',
),
'tuesday' => array(
'label' => __('Tuesday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28002',
),
'wednesday' => array(
'label' => __('Wednesday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28001',
),
'thursday' => array(
'label' => __('Thursday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28002',
),
'friday' => array(
'label' => __('Friday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28923',
),
'sunday' => array(
'label' => __('Sunday', 'woocommerce' ),
'data_attr_name' => 'post-code',
'data_attr_value' => '28923',
)
)
);
return $fields;
}
Now as per your requirement I will use data attr for show hide select option based on another select option. but in woocommerce default select dropdown, there is now a way to add data attr to select. so for this, I created the custom_select
type so we can add data attr. so as you can see in above woocommerce_checkout_fields
filter hook i set 'type' => 'custom_select',
.
You can add new your custom field type using the woocommerce_form_field
filter hook.
add_filter( 'woocommerce_form_field', 'add_custom_select', 10 , 4 );
function add_custom_select( $field, $key, $args, $value ){
if( $args['type'] == 'custom_select' ){
if ( $args['required'] ) {
$args['class'][] = 'validate-required';
$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>';
} else {
$required = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
}
$field = '';
$options = '';
if ( ! empty( $args['options'] ) ) {
foreach ( $args['options'] as $option_key => $option_text ) {
if ( '' === $option_key ) {
// If we have a blank option, select2 needs a placeholder.
if ( empty( $args['placeholder'] ) ) {
$args['placeholder'] = $option_text['label'] ? $option_text['label'] : __( 'Choose an option', 'woocommerce' );
}
$custom_attributes[] = 'data-allow_clear="true"';
}
$options .= '<option value="' . esc_attr( $option_key ) . '" ' . selected( $value, $option_key, false ) . ' data-'.$option_text['data_attr_name'].'="'.$option_text['data_attr_value'].'" >' . esc_html( $option_text['label'] ) . '</option>';
}
$field .= '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" class="select ' . esc_attr( implode( ' ', $args['input_class'] ) ) . '" ' . implode( ' ', $custom_attributes ) . ' data-placeholder="' . esc_attr( $args['placeholder'] ) . '">
' . $options . '
</select>';
}
$field_container = '<p class="form-row %1$s" id="%2$s" data-priority="' . esc_attr( $sort ) . '">%3$s</p>';
if ( ! empty( $field ) ) {
$field_html = '';
if ( $args['label'] && 'checkbox' !== $args['type'] ) {
$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) . '">' . wp_kses_post( $args['label'] ) . $required . '</label>';
}
$field_html .= '<span class="woocommerce-input-wrapper">' . $field;
if ( $args['description'] ) {
$field_html .= '<span class="description" id="' . esc_attr( $args['id'] ) . '-description" aria-hidden="true">' . wp_kses_post( $args['description'] ) . '</span>';
}
$field_html .= '</span>';
$container_class = esc_attr( implode( ' ', $args['class'] ) );
$container_id = esc_attr( $args['id'] ) . '_field';
$field = sprintf( $field_container, $container_class, $container_id, $field_html );
}
return $field;
}
return $field;
}
Now on the billing_postcode
change, you have to get the billing_postcode
value that you need to compare with delivery_days
dropdown option data-post-code
and based on that you can show hide.
function add_custom_js(){
?>
<script type="text/javascript">
(function($){
$('#billing_postcode').on('change', function(){
var postcode = $(this).val();
var days = $('#delivery_days');
var i = 1;
$('option', days).filter(function(){
if ( $(this).attr('data-post-code') === postcode ) {
$(this).show();
if( i == 1 ){
$("#delivery_days").val($(this).val());
}
i++;
} else {
$(this).hide();
}
});
});
$('#billing_postcode').trigger('change');
})(jQuery);
</script>
<?php
}
add_action( 'wp_footer', 'add_custom_js', 10, 1 );
Tested and works.