WooCommerce Shipping Zones are quite easy to override / customize. With a simple PHP (and jQuery, sometimes) snippet we can accomplish many advanced shipping rules, such as the one we’ll study today.
This time, I’ve tested a snippet to add a dropdown to the billing section where users go choose the pickup destination. As a result, the shipping address is automatically populated, and so is the shipping method. What do you think?
1. Shipping Zones Setup
The very first thing you need to do is setting up the WooCommerce shipping zones. In this case, each zone will correspond to a Local Pickup Address (e.g. shop #1, shop #2, etc).
In the following example, I’ve added 2 zones in Australia, with the same state (Australian Capital Territory) but 2 different postcodes.
Each zone has its unique shipping method (Local Pickup) with cost = $0:
2. Advanced Local Pickup – PHP/jQuery Snippet
Now that the zones are correctly setup, here comes the hard part. The following is a snippet that requires a lot of improvements, so if you spot anything or wish to contribute leave a comment below.
/**
* @snippet Advanced Local Pickup - WooCommerce
* @how-to businessbloomer.com/woocommerce-customization
* @author Rodolfo Melogli, Business Bloomer
* @compatible WooCommerce 6
* @community https://businessbloomer.com/club/
*/
//////////////////////////////////////////////////////////
// 1. Select field @ checkout billing section
add_filter( 'woocommerce_checkout_fields', 'bbloomer_display_pickup_locations' );
function bbloomer_display_pickup_locations( $fields ) {
$fields['billing']['pick_up_locations'] = array(
'type' => 'select',
'options' => array(
'option_1' => 'Select...',
'option_2' => 'Melbourne Road Shop',
'option_3' => 'Perth Road Shop'),
'label' => 'Pick Up Location',
'class' => array( 'form-row-wide' ),
'clear' => true,
);
return $fields;
}
//////////////////////////////////////////////////////////
// 2. Show field only when country == Australia @ checkout
add_action( 'woocommerce_after_checkout_form', 'bbloomer_conditionally_hide_show_pickup', 5 );
function bbloomer_conditionally_hide_show_pickup() {
wc_enqueue_js( "
$('select#billing_country').change(function(){
var country = $(this).val();
if ( country == 'AU' ) {
$('#pick_up_locations_field').fadeIn();
} else {
$('#pick_up_locations_field').fadeOut();
$('#pick_up_locations_field input').val('');
}
});
" );
}
//////////////////////////////////////////////////////////
// 3. "Ship to a different address" opened by default
add_filter( 'woocommerce_ship_to_different_address_checked', '__return_true' );
//////////////////////////////////////////////////////////
// 4. Change shipping address when local pickup location changes
add_action( 'woocommerce_after_checkout_form', 'bbloomer_checkout_update_pickup_address', 10 );
function bbloomer_checkout_update_pickup_address() {
wc_enqueue_js( "
$('select#pick_up_locations').change(function(){
var location = $(this).val();
if (location == 'option_2') {
$('select#shipping_country').val('AU').change();
$('select#shipping_state').val('ACT').change();
$('#shipping_city_field input').val('Sidney');
$('#shipping_address_1_field input').val('Melbourne Road');
$('#shipping_postcode_field input').val('34500');
$('.shipping_address input[id^=\'shipping_\']').prop('disabled', true);
$('.shipping_address select[id^=\'shipping_\']').prop('disabled', true);
} else if (location == 'option_3') {
$('select#shipping_country').val('AU').change();
$('select#shipping_state').val('ACT').change();
$('#shipping_city_field input').val('Sidney');
$('#shipping_address_1_field input').val('Perth Road');
$('#shipping_postcode_field input').val('79200');
$('.shipping_address input[id^=\'shipping_\']').prop('disabled', true);
$('.shipping_address select[id^=\'shipping_\']').prop('disabled', true);
} else {
$('.shipping_address input[id^=\'shipping_\']').prop('disabled', false);
$('.shipping_address select[id^=\'shipping_\']').prop('disabled', false);
}
});
" );
}
As a result, once you select the correct local pickup address form the billing section, you should automatically get the correct shipping method in the checkout:
Did you test this? Do you have anything useful to add? Let me know!
Thank you for the great information on your site!
I tried this one, and when I choose a pick up location from the drop down, it does not populate the appropriate shipping fields (address, city zip). Is it supposed to do that or do i have to modify something else on the script i cannot figure out?
Hello Joy, please share the code in case you customized anything
Hi There,
Thank you so much… works great!
Just one question… on the site I used the code on, it is limiting the amount of pick up locations to 29.
(I have 43)
If I add add any further locations over 29 it will stop working.
Any idea’s on what may be causing this?
Many Thanks
Scott
This doesn’t make much sense to me. Are you using other plugins for the locations?
Good evening Rodolfo
Quick Question?, Does the script allow for customers to receive an order email with the relevant pick location as well.
Hi Jason, you could customize the email content of course, but anyway users will see the “Shipping Details” in their email and they would be the ones you’ve defined in the local pickup settings
Hello,
Thanks for this code. Unfortunately, I can’t seem to get the selected “pickup” location on the order details, it doesn’t show for me and it doesn’t show on the order confirmation email that my customers receive. Also the “Pickup Location” on the checkout page is stated as “Optional”. Any suggestion on how I can fix this?
Hi Wendell, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Firstly thanks for the code, it worked for me.
I needed to have predefined sending adresses, and it works so brilliantly…but hopefully you can help me.
When an address is selected, It “greys” out the name….and it would be damn great either if it took the name from “invoice” name or if it allowed them to fill it out… any ideas how to make this happen?
Kind regards,
Gurmukh
Hi Gurmukh, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Hi there,
First of all I want to say an enormous THANK YOU for this code, it has helped me immensely – the one and only issue I am having is with this code here:
When I add that in to my ‘if’ statement (at the end) and then hit the ‘place order’ button, I get a big error message saying:
“Shipping First name is a required field.
Shipping Last name is a required field.
Shipping Country is a required field.
Shipping Street address is a required field.
Shipping Town / City is a required field.
Shipping Province is a required field.
Shipping Postcode / ZIP is a required field.
Please enter an address to continue.”
As soon as I remove those two lines of code, everything works properly. I would really really like to be able to disable those fields from being edited after they have been populated – can you think of any other way to do this?
Thank you!
Hey David, thanks so much for your comment! I revised the snippet and changed “elseif” to “else if” inside the JQuery script. Try to see if that fixes your errors 🙂
I have the same issue and the “else if” change is not working.
Seems like the value taken from the “live” checkout formula is not accepted in the shipping fields. Even if there are values written in the fields it still will not allow to complete check out.
Hi replacing with readonly prop works for me
And thank you Rodolfo your solution was insightfull. thanks again for sharing.
Cool!
After copy and pasting your code i noticed the following error in the console:
on this line:
i changed it to:
Ok, thank you Arnout 🙂
Hi Rodolfo,
I liked your work and thank you for the code. I tried to use it in my site but what I saw was that after order is placed I’m not able to find which pick up location user has selected and neither I’m able to disable the address text box for billing and shipping address. I have not installed child theme.
Sanket, thanks so much for your comment! Unfortunately this looks like custom troubleshooting work and I cannot help here via the blog comments. Thanks a lot for your understanding! ~R
I was able to modify and use it successfully for our site. I appreciate the code!
Awesome Bill! If you want to share your work I can then update the snippet – otherwise thanks anyway 🙂
Hi Rodolfo,
I love your work and really appreciate all your help.
I am trying to modify your above code. For the pick up location box to appear I want it to be dependent on the customer’s PostCode.
I am just having some trouble with the lines this is what i have so far… Would you mind showing how to add conditional statements for multiple postal code too? e.x M4J*, M4K* etc.. Thank you!
Paul, thanks so much for your comment! Unfortunately this is custom work and I cannot provide a complementary solution here on the blog. Thanks a lot for your understanding! ~R
Hi,
I want user to be able to select city from city field and the area of that city should get populated in area checkout field. I have 2 cities and specific delivery areas in that city. I tried above code but I am not able to achieve this. Can you please help me as how can I achieve this?
Radhika, thanks so much for your comment! Yes, this is possible – but unfortunately this is custom work and I cannot provide a complementary solution here on the blog. Hopefully I will have time to create a snippet soon 🙂 Thanks a lot for your understanding! ~R
I will test that soon, I really need this fuction and I’m glad you share this solution. Thank you.
Awesome, thanks very much Lp!
I tried it but there the info won’t pass from to the “Different Address” zone.
Is there any specific settings in WC for that to work ?
Thank you.
Pity! Would you send me a screenshot? Thank you 🙂