Today’s snippet has been widely requested by many readers, clients and WooCommerce fans. We already saw in the past how to Limit State Dropdowns to One State Only (for both Shipping & Billing) and How to Sell to one State only (Billing).
However, we never covered a much more common setting: what happens when Billing is allowed to every state but Shipping is limited?
In order to get a little help, Iβve reached out to Diego Zanella, a WooCommerce genius who is also the author of the Aelia Currency Switcher plugin for WooCommerce.
PHP Snippet (1 of 2): Allow Shipping to Only One State @ WooCommerce Cart Shipping Calculator
/**
* @snippet Ship to One State @ WooCommerce Cart Shipping Calculator
* @how-to businessbloomer.com/woocommerce-customization
* @author Diego Zanella
* @compatible WooCommerce 3.6.4
* @community https://businessbloomer.com/club/
*/
add_filter( 'woocommerce_states', 'aelia_cart_filter_US_states' );
function aelia_cart_filter_US_states( $states ) {
if ( is_cart() ) {
$states['US'] = array(
'PA' => 'Pennsylvania',
);
}
return $states;
}

PHP Snippet (2 of 2): Allow Shipping to Only One State @ WooCommerce Checkout Page
Note: this will only work if you’ve limited shipping to a specific country via the WooCommerce settings. Also, this snippet might limit billing too – in this case check the alternative snippet below.
/**
* @snippet Ship to One State @ WooCommerce Checkout #1
* @how-to businessbloomer.com/woocommerce-customization
* @author Rodolfo Melogli, Business Bloomer
* @compatible WooCommerce 3.6.4
* @community https://businessbloomer.com/club/
*/
add_filter( 'woocommerce_countries_shipping_country_states', 'bbloomer_set_checkout_shipping_state' );
function bbloomer_set_checkout_shipping_state( $states ) {
$states[ 'US' ] = array( 'PA' => __( 'Pennsylvania', 'woocommerce' ) );
return $states;
}
Alternative snippet – in case everything else fails:
/**
* @snippet Ship to One State @ WooCommerce Checkout #2
* @how-to businessbloomer.com/woocommerce-customization
* @author Rodolfo Melogli, Business Bloomer
* @compatible WooCommerce 3.6.4
* @community https://businessbloomer.com/club/
*/
add_action( 'wp_footer', 'aelia_checkout_shipping_filter_US_states' );
function aelia_checkout_shipping_filter_US_states() {
if ( ! is_checkout() ) {
return;
}
?>
<script>
jQuery(document).ready(function($) {
$(document.body).on('country_to_state_changed', function() {
function set_shipping_state(state) {
var $shipping_state = $('#shipping_state');
var $shipping_state_option = $('#shipping_state option[value="' + state + '"]');
var $shipping_state_option_no = $('#shipping_state option[value!="' + state + '"]');
$shipping_state_option_no.remove();
$shipping_state_option.attr('selected', true);
}
var $shipping_country = $('#shipping_country');
var new_shipping_state = '';
switch($shipping_country.val()) {
case 'US':
new_shipping_state = 'PA';
break;
}
if( ! $.isEmptyObject(new_shipping_state)) {
set_shipping_state(new_shipping_state);
}
});
});
</script>
<?php
}

Is there a way to use the JavaScrip but with multiple states? I can’t figure that out!
Hi Gracen, 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!
Now, I find out another simple workaround:
First, I’ve created a brand new select field with all the states i needed to show. In my country, Chile, they are “comunas”. Like this:
Then, I’ve linked the selected value in this field to shipping_state official field, like this:
Finally I hide the official shipping state field with CSS:
#shipping_state {display:none;}
et voila
Nice!
God, this was a nightmare!
Hi Rodolfo, as always very useful tip. But i tried both php snippet and the js version. The php changed my billing state field and using the later the selection is lost for shipping charge as other people comment. Then i tried the Dan version but nothing changes.
After hours i figured out a typo in Travis code:
$shipping_state.append(” + states[state] + ”);
should be
$shipping_state.append(” + states[state] + ”);
ΒΏHow is this possible?
Bye
part of the code transcription was missing in my comment. The thing was a missing “
Ok thank you!
Thanks for all the snippets you provide! I had the need to prevent shipping to specific states in MΓ©xico temporarily due to some COVID-19 reasons, so I came across this snippet and solve it in a different way.
I created a Shipping Zone in WooCommerce settings and choose the States I DO NOT WANT to ship to in the Region field.
Then I left the shipping methods empty. Not adding anything.
I also moved this new shipping zone to the top of my shipping zones.
This will show a message to the user if they choose the state I do not ship to that says something like: “No shipping is available. Please….” and won’t allow the user to pay unless the Shipping State is not the ones from my list.
I also added a message at the top of the checkout page to communicate to the user that we are not currently shipping to those states to make it clear they have a correct address but we temporarily do not ship to that region.
Nice!
Hello there. I have tried using the PHP snippet (2 of 2) which it works properly, however it affects the billing form as well.
The other snippets do not work on woocommerce 4.2.0.
The snippet I posted on 2016 does not work any longer as well.
Can anyone assist? I would like the billing form not to be affected. I would really appreciate.
Tried the alternative jQuery snippet?
I did and it does not work on latest version of woocommerce.
Actually, it does work but I cannot figure out how to add an array of multiple states in the
( new_shipping_state = ) line
Ah ok
I used the code at the link below and it worked fine. It seems much simpler, so I’m wondering if it’s doing the same thing.
https://www.ultimatewoo.com/restrict-sales-specific-u-s-states-woocommerce/
Hey Jodi, it’s much simpler because it completely remove those states from everywhere: yes – shipping – but also billing, dropdowns, reports, and everywhere a state selection is needed. My snippet is just for hiding them from the shipping form @ checkout, so that e.g. someone can buy from Hawaii but cannot ship to Hawaii
Hey, I added this code to my client’s website back in May 29 and just recently my client noticed some orders made from the front-end do not have taxes applied. After some testing I found this code was the cause. I have since switched my client’s WooCommerce setting to calculate tax based on their store address for now since they only ship within their province.
I want to ask has anyone encountered this particular issue with this code? And if there are other alternatives to limiting shipping checkout to one state/province? Any insight would be helpful, thank you!
Hey Wallace, thanks so much for your comment! Yes, this is definitely fixable, 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, any updates on this, I could not get it to work with current woocommerce version.
Hi there, just tested and it still works π
Hi,
First of all thank you for your help. I have found an error in your script, there is missing double quotes in state id attribute.
Thank you Sandeep! Is the error here:
I came up with a slightly different solution based on the work done here. It utilizes wp_localize_script to be able to populate the states from a PHP function. In this case, ssc_ship_states returns an array of states for multiple countries (Australia, US, Canada), so all three of those countries will have a restricted list of states/provinces.
Then I use a separate JS file that gets enqueued in the footer:
It should be noted that I also have removed Select2 scripts and styles from Woo because they seem pointless to me and cause more headache than they are worth:
Brilliant, thanks for sharing!
Hi! I’ve copied the 2nd snippet exactly (convenient that I need the PA option!) and it’s not having any impact on my site. It’s in my child theme functions .php.
Do you have any thoughts on this?
Hey Laurie, thanks for your comment! Yes, the 2nd snippet highly depends on your theme/custom coding so there is something there not triggering. Or, https://businessbloomer.com/woocommerce-allow-shipping-one-state-only/#comment-24806
Darn! Thanks for the info. I tried to go back to the first snippet, which was working and now it’s not. Do you have any advice on that? Thanks!
Laurie, are you using the exact same code? If not, can you show me your custom code?
Heads up to anyone trying snippet #2 to hide states on Checkout…
It *appears* to work and correctly replaces the shipping states, but I discovered it was preventing Woo from loading our shipping methods when somebody tried to “ship to a different address,” saying “There are no shipping methods available. Please double check your address, or contact us if you need any help.” Removing the snippet fixed the issue.
It’s happening because Woo uses Select2.js to replace the State dropdown with a bunch of custom ‘s, but the snippet here uses jQuery to put an back onto the page, breaking however Woo sends address info back to calculate shipping.
Hopefully I’ll have some time to fix it to work with Select2, but in the meantime you should probably remove snippet #2 from here Rodolfo. Thanks for all your helpful coding though!
Thank you so much for your feedback Justin π
i found the same thing. Also, this doesn’t affect the My Account Shipping address. If there’s a solution, please post.
thanks!
It’s happening to me also. OceanWP theme, Woo 3.1.2, WP 4.8.2.
The filter on shipping states dropdown *works* but the order cannnot be completed because the shippping methods aren’t displayed: βThere are no shipping methods available. Please double check your address, or contact us if you need any help.β
If someone have a workaround for this would be awesome.
Hi Rodolfo,
Thank you for your work. If I reside in Canada and im dealing with Provinces. Would i just need to modify the code from “US” to “Canada” and “states” to “provinces and PA to ON (Ontario) ? Thank you for your help.
Hey Paul, thanks for your comment! Correct – you only need to double check the exact 2-letters codes that WooCommerce uses. They’re in the /i18n/states/ folder π
Hi,
I realize a website for a client and he wants to limit shipping of his burgers to a perimeter of two miles so only people in this perimeter can order.
Is it possible to do that ?
Hey Romain, thanks so much for your comment! This is pretty complicated – how are you going to measure the “miles” on the checkout page? Maybe by ZIP code? You’ll need to find a rule first and then “translate” that in WooCommerce – not sure how you can manage to do so in this case π
Make sure the states are separated by a comma. The list with all the states is included in this code. Remove the states you do not want. Last state on the list does not require a comma.
Hi,
Thanks for the code!
If i add 2 states, seems not to work.
Do i need to change something else?
Hey Dan, thanks for your comment! Would you be able to paste your snippet here, as it should definitely work π Let me know!
Thanks for your replay.
Here it is:
If i leave only 1, it works fine!
Uhm, you might be missing a comma here:
Let me know π
Thanks again, but did not work.
If I add one more state, all of them appear in woocommerce.
With one state it works perfectly.
Its really strange.
Any other solution?
Hey π That’s the correct solution so maybe you have a snippet/plugin/theme conflict. Try troubleshooting this maybe – let me know!
Hi,
I have a client who has a Flower Shop in the UK. She only wants to sell her flowers to local customers within a 10 mile radius of her shop. I was able to generate a list of all the post codes that this includes.
However, how would I disable shipping for all customers of the UK outside of this post code list?.
Any help would be much appreciated.
tia,
Andy
Hey Andy, thanks for your comment! Are you on WooCommerce 2.6+ – the new shipping “zones” should help you do exactly that? Let me know