How to Hide Payment Methods based on Postal Code
In this tutorial I will show you how you can disable or enable payment gateways in WooCommerce depending on customer shipping or billing postcode with the help of woocommerce_available_payment_gateways
filter hook.
If you need custom coding help with WooCommerce payment gateways – contact me.
Here is our goal:

add_filter( 'woocommerce_available_payment_gateways', 'rudr_gateway_by_postcode' );
function rudr_gateway_by_postcode( $gateways ) {
if( is_admin() ) {
return $gateways;
}
$zip_codes = array( // array of postal codes to check
'X0A',
'X0B',
'X0C',
);
if( is_wc_endpoint_url( 'order-pay' ) ) { // Pay for order page
$order = wc_get_order( wc_get_order_id_by_order_key( $_GET[ 'key' ] ) );
$zip_code = $order->get_shipping_postcode();
} else { // Cart/Checkout page
$zip_code = WC()->customer->get_shipping_postcode();
}
if ( in_array( strtoupper( $zip_code ), $zip_codes ) ) {
// if customer shipping postcode is in array, deactivate PayPal payment method
if ( isset( $gateways[ 'paypal' ] ) ) {
unset( $gateways[ 'paypal' ] );
}
} else {
// for everyone else deactivate Cash on Delivery
if ( isset( $gateways[ 'cod' ] ) ) {
unset( $gateways[ 'cod' ] );
}
}
return $gateways;
}
- For billing postcode you can use
WC()->customer->get_billing_postcode()
. - Remember that the way you get the postal code will be different for the Checkout page (we get it from
WC()->customer
object) and for Pay for order page (we get the postal code fromWC_Order
object). - Do not know where to get a payment gateway ID? If you are working on a live website and can not use
print_r( $gateways )
, I can suggest you to add a column with payment gateway ID in WooCommerce settings. - Th code can be inserted to your current or child theme
functions.php
file.
Trigger Checkout Update on Postal Code Change
One more thing.
By default WooCommerce doesn’t update checkout when we type in another postal code. Like it does for the state/country fields for example. If you google it, you can find a recommendation to add update_totals_on_change
CSS-class, but it doesn’t work for text fields.
So let’s add a small piece of jQuery code as well.
jQuery( function( $ ) {
$( '#billing_postcode, #shipping_postcode' ).blur( function() {
$( 'body' ).trigger( 'update_checkout' );
} );
} );
It is very basic, if you wish, you can use keyup
event and setTimeout()
.
// Delay function
// Change 500ms to any other delay value, e.g. 1000 (1s)
function rudr_delay( callback ) {
let timer = 0
return function( ...args ) {
clearTimeout( timer )
timer = setTimeout( callback.bind(this, ...args ), 500 || 0)
}
}
jQuery( function( $ ) {
$( '#billing_postcode, #shipping_postcode' ).keyup( rudr_delay( function (e) {
$( 'body' ).trigger( 'update_checkout' );
} ) );
} );
JavaScript code can be inserted into a separate .js
file or to the functions.php
as well inside wp_head
or wp_footer
action hook.

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Very helpful and well written. Thanks!
You may want to do some string manupulation as well, ie
$zipcode = str_replace(' ', '', $zipcode)