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()->customerobject) and for Pay for order page (we get the postal code fromWC_Orderobject). - 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.phpfile.
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 15 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)