WooCommerce: Ship to Predefined “Local Pickup” Addresses

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:

Advanced Local Pickup – WooCommerce Shipping Zones

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:

Advanced Local Pickup – WooCommerce Checkout

Did you test this? Do you have anything useful to add? Let me know!

Where to add custom code?

You should place custom PHP in functions.php and custom CSS in style.css of your child theme: where to place WooCommerce customization?

This code still works, unless you report otherwise. To exclude conflicts, temporarily switch to the Storefront theme, disable all plugins except WooCommerce, and test the snippet again: WooCommerce troubleshooting 101

Related content

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza. Follow @rmelogli

29 thoughts on “WooCommerce: Ship to Predefined “Local Pickup” Addresses

  1. 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?

    1. Hello Joy, please share the code in case you customized anything

  2. 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

    1. This doesn’t make much sense to me. Are you using other plugins for the locations?

  3. Good evening Rodolfo

    Quick Question?, Does the script allow for customers to receive an order email with the relevant pick location as well.

    1. 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

  4. 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?

    1. 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!

  5. 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

    1. 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!

  6. 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:

    jQuery(".shipping_address input[id^='shipping_']").prop("disabled", true);
    jQuery(".shipping_address select[id^='shipping_']").prop("disabled", true);
    

    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!

    1. 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 🙂

    2. 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.

      1. Hi replacing with readonly prop works for me

        $('.shipping_address input[id^=\'shipping_\']').prop('readonly', true);
        $('.shipping_address select[id^=\'shipping_\']').prop('readonly', true);
        

        And thank you Rodolfo your solution was insightfull. thanks again for sharing.

  7. After copy and pasting your code i noticed the following error in the console:

    Uncaught SyntaxError: Unexpected token {
    

    on this line:

            } elseif (location == 'option_3') {
    

    i changed it to:

            } else if (location == 'option_3') {
    
    1. Ok, thank you Arnout 🙂

  8. 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.

    1. 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

  9. I was able to modify and use it successfully for our site. I appreciate the code!

    1. Awesome Bill! If you want to share your work I can then update the snippet – otherwise thanks anyway 🙂

  10. 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!

    1. 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

  11. 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?

    1. 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

  12. I will test that soon, I really need this fuction and I’m glad you share this solution. Thank you.

    1. Awesome, thanks very much Lp!

      1. 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.

        1. Pity! Would you send me a screenshot? Thank you 🙂

Questions? Feedback? Customization? Leave your comment now!
_____

If you are writing code, please wrap it like so: [php]code_here[/php]. Failure to complying with this, as well as going off topic or not using the English language will result in comment disapproval. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining the Business Bloomer Club to get quick WooCommerce support. Thank you!

Your email address will not be published. Required fields are marked *