WooCommerce: Only Ship to Predefined “Local Pickup” Addresses

Woo 2.6 introduced Shipping Zones – and with that we can play with simple PHP (and JQuery) to accomplish lots of “advanced” shipping rules, such as local pickup.

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. Advanced Local Pickup – Shipping Zones/Methods Setup

The very first thing you need to do is setup 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/shops”in Australia, state = “Australian Capital Territory” and 2 specific postcodes.

Each zone has its unique a 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 tested snippet that – however – 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        Get CustomizeWoo.com FREE
 * @source        https://businessbloomer.com/?p=21534
 * @author        Rodolfo Melogli
 * @compatible    WC 3.4.2
 */

//////////////////////////////////////////////////////////
// 1. New select field @ 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', 'woocommerce'),
	'class'     => array('form-row-wide'),
    	'clear'     => true
     );

return $fields;

}

//////////////////////////////////////////////////////////
// 2. Field to show only when country == Australia

add_action( 'woocommerce_after_checkout_form', 'bbloomer_conditionally_hide_show_pickup', 5);

function bbloomer_conditionally_hide_show_pickup() {
  
  ?>
	<script type="text/javascript">
		jQuery('select#billing_country').live('change', function(){
			
			var country = jQuery('select#billing_country').val();
			
			var check_country = new Array(<?php echo '"AU"'; ?>);
			if (country && jQuery.inArray( country, check_country ) >= 0) {
				jQuery('#pick_up_locations_field').fadeIn();
			} else {
				jQuery('#pick_up_locations_field').fadeOut();
				jQuery('#pick_up_locations_field input').val('');
			}
			
		});
	</script>
	<?php
	  
}

//////////////////////////////////////////////////////////
// 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() {
        
  		?>
		<script type="text/javascript">

		jQuery('select#pick_up_locations').live('change', function(){

		var location = jQuery('select#pick_up_locations').val();
		
		if (location == 'option_2') {
		
		jQuery('select#shipping_country').val('AU').change();
		jQuery('select#shipping_state').val('ACT').change();
		jQuery('#shipping_city_field input').val('Sidney');
		jQuery('#shipping_address_1_field input').val('Melbourne Road');
		jQuery('#shipping_postcode_field input').val('34500');
		jQuery(".shipping_address input[id^='shipping_']").prop("disabled", true);
		jQuery(".shipping_address select[id^='shipping_']").prop("disabled", true);
		
		} else if (location == 'option_3') {

		jQuery('select#shipping_country').val('AU').change();
		jQuery('select#shipping_state').val('ACT').change();
		jQuery('#shipping_city_field input').val('Sidney');
		jQuery('#shipping_address_1_field input').val('Perth Road');
		jQuery('#shipping_postcode_field input').val('79200');
		jQuery(".shipping_address input[id^='shipping_']").prop("disabled", true);
		jQuery(".shipping_address select[id^='shipping_']").prop("disabled", true);

                } else {

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

		}
		
		});

		</script>
		<?php
                     
}

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 this snippet?

You can place PHP snippets at the bottom of your child theme functions.php file (delete "?>" if you have it there). CSS, on the other hand, goes in your child theme style.css file. Make sure you know what you are doing when editing such files - if you need more guidance, please take a look at my free video tutorial "Where to Place WooCommerce Customization?"

Does this snippet (still) work?

Please let me know in the comments if everything worked as expected. I would be happy to revise the snippet if you report otherwise (please provide screenshots). I have tested this code with Storefront theme, the WooCommerce version listed above and a WordPress-friendly hosting on PHP 7.3.

If you think this code saved you time & money, feel free to join 14,000+ WooCommerce Weekly subscribers for blog post updates or 250+ Business Bloomer supporters for 365 days of WooCommerce benefits. Thank you in advance :)

Need Help with WooCommerce?

Check out these free video tutorials. You can learn how to customize WooCommerce without unnecessary plugins, how to properly configure the WooCommerce plugin settings and even how to master WooCommerce troubleshooting in case of a bug!

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.

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

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

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

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

  4. 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 πŸ™‚

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

  6. 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 πŸ™‚

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

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

  9. 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? Support? Leave your Comment Now!
_____

If you are writing code, please wrap it between shortcodes: [php]code_here[/php]. Failure to complying with this (as well as going off topic, not writing in English, etc.) will result in comment deletion. 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 BloomerArmada to get blog comment reply priority, ask me 1-to-1 WooCommerce questions and enjoy many more perks. Thank you :)

Your email address will not be published.