Today we take a look at the WooCommerce Checkout Page and specifically at how to disable a payment gateway (for example PayPal) when a specific shipping method is selected (e.g. “local_pickup”).
Specifically, you will learn how to “get” the selected shipping method on the go (thanks to “sessions”), and also how to “unset” a payment gateway. Enjoy!
PHP Snippet: Disable Payment Gateway For Specific Shipping Method – WooCommerce
In this example, I will disable “COD” payment gateway for all “local pickup” shipping rates in whatever shipping zone. You can also target a specific shipping rate (in a single zone).
/**
* @snippet Disable Payment Gateway For Specific Shipping Method
* @how-to businessbloomer.com/woocommerce-customization
* @author Rodolfo Melogli, Business Bloomer
* @testedwith WooCommerce 7
* @community https://businessbloomer.com/club/
*/
add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_gateway_disable_for_shipping_rate' );
function bbloomer_gateway_disable_for_shipping_rate( $available_gateways ) {
if ( ! is_admin() && WC()->session ) {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
if ( isset( $available_gateways['cod'] ) && 0 === strpos( $chosen_shipping, 'local_pickup' ) ) {
unset( $available_gateways['cod'] );
}
}
return $available_gateways;
}
Mini-Plugin: Business Bloomer WooCommerce Toggle Payments By Shipping
You don’t feel confident with coding? You need more control over your payment/shipping exclusions? You don’t want to purchase yet another bloated, expensive plugin? Great!
Business Bloomer WooCommerce Toggle Payments By Shipping is a mini WooCommerce plugin, without the usual hassles. One feature. Lifetime license. No annoying subscriptions. 1 plugin file. A few lines of code. No banners. No up-sells. No WP notifications. Use it on as many websites as you like. Lifetime support. 1-page documentation. A single and easy admin dashboard.
Screenshot of the settings:
Quick demo:
As you can see the settings are pretty straight forward. Select a payment method you wish to hide/show from the left, and the shipping method that should trigger that from the right. Add more rules if needed. Simple!
Advanced Plugin: WooCommerce Conditional Payment Gateways
If you require a more advanced premium plugin, I decided to look for a reliable plugin that achieves the same result of this snippet (and more).
In this case, I found the WooCommerce Conditional Payment Gateways plugin to be the most complete when you need to enable/disable payment gateways based on certain criteria. You can create unlimited “rules” and use, for example, cart totals, billing country, shipping country, user role and much more to define which payment gateway shows and which not.
But in case you don’t want to use plugins and wish to code (or wish to try that), then keep reading 🙂
Dear Rodolfo,
I have used this code for years on, and it worked well.
Thank you very much for your work!
Now, with the new Woo 7.7.2 and WordPress 6.2.2 it just doesn’t.
Actually it just starts, and than the cart is not loading, the website health tool shows that there’s a Rest API problem. As I remove the code from the functions.php all is nice, and working well…
What should get wrong?
Thanks for that Katalin. This checks if WC()->session exists before trying to get the current shipping method so that error makes not much sense to me. Are you using the exact snippet as per this page?
Hi Rudolfo, Do you have any tips how to handle the WooCommerce PayPal Payments module “ppcp-gateway”? It loads the PP button as an iframe at page load which is hidden if the module is not selected. Scenario: PP is disabled for USA. Customer with country USA comes to checkout, PP module is hidden. Customer changes country to UK, PP is shown, but payment button is missing as the JS that loads the button wasn’t triggered on page load. If the customer refreshes the page, the button appears. I’m trying to find a solution for this, but hitting a brick wall.
Hello Edith! Did you talk to the plugin developers already?
Hi, the code on PHP 8.0 causes an error:
Warning: Trying to access array offset on value of type null in…/functions.php on line 33
line 33:
Are you also having this error? For me it appears on the login page – /wp-admin
I think the following code will fix it:
Regards
Thank you!
Pin this addition at start.
It saved me, and since the the php is going to 8+ i belive it should be mentioned.
Many thanks again 🙂
Thank you! How do I “pin” a comment?
Is there an plugin conflict with the latest woocommerce 7.0.0 . it stoped wokrking after the update
Hi Michel, and sorry for the delay! I haven’t tested it with Woo 7 yet, but I don’t see why it won’t work. Have you tried with just 2022 theme + Woo + the plugin active only?
hi, how to disable payment gateway when choose a flat_rate:10?
Instead of:
try use:
Hi,
code works pefect, but in backen returns woocommerce error “Call to a member function get() on null in…” on line:
“$chosen_methods = WC()->session->get( ‘chosen_shipping_methods’ );”.
Is it possible that it is not compatible with the theme I’m using
My code only runs in the frontend (!is_admin conditional). If, on the other hand, that error comes from the frontend, you may add a check:
it works for me, thanks!
I had the same problem with API calls. The snippet worked well, but API response returned an error.
This solution solved my issue too!
Thanks
For some reason it doesnt work for me , i installed te plugin and set payment and shipping method. Nothing happens its stays availible. cleared cache also etc.
Thanks for your feedback Michel! Please email me your site credentials at rodolfo@businessbloomer.com and I’ll take a look. Otherwise, please email me screenshots and steps to reproduce the error. Cheers
Thanks, i send you a mail
br Michel
HI all, it is working perfect now. It was my mistake 🙂 Thanks Rodolfo for quickly helping me .
Awesome!
hi i am currently building my site and its not been transferred over to my domain yet but i am trying to disable the paypal checkout when there are no shipping options to zones out of our delivery areas. when i select the hide paypal checkout and then drop the other checkbox down it only shows my delivery zones, it doesnt show an option for no shipping options available.
Hi Gary! Sorry, this is not 100% clear to me. If there are “no shipping options available”, how does WooCommerce let you complete the checkout? It should be blocked, right?
Also, which PayPal plugin are you using, and are you referring to the PayPal “Express” buttons that display in the product, cart and checkout pages – or the default PayPal gateway option at the bottom of the checkout page?
Thank you!
I Purchased the plugin for product categories! Thank You, it works fine! BUT, it’s quite hard if there is lot of categories. It’s not working with main categories if there are sub categories under it. I have to insert rows for each sub category individualy and i have LOT of them 🙁 and after EACH row insert plugin rafresh the page, it takes long time to insert more then 100 caregoties
Critical plugin error :((( after 2 hours of work inserting MULTIPLE rows for sub categories :((((
Thanks so much for your valuable feedback Janis. But first, let’s fix the critical error – can you please describe the error you see in the logs so that I can send you an immediate fix? Thanks for your patience
purchased the plugin, it doesn’t work. Critical error.
Thanks for that Anze! Can you send me a screenshot and also the description of the error, or the steps to replicate it? Thank you!
Oh, never mind, I found the bug. I will upload the revised plugin ZIP into your My Account dashboard in a few minutes. For now, if you are familiar with code, you simply need to add this line on line 16:
Anyway, I will let you know when the new version is up. Sorry for the issue
Plugin updated, you find it under My Account. Let me know if everything is ok now please.
If you can’t remove the plugin because your site crashed and can’t access WP dashboard, go to your FTP or Hosting Control Panel > File Manager, look for /wp-content/plugins folder and delete “woocommerce-disable-payments-by-shipping” folder, then install the new version.
Hey,
It works, I didn’t expect it’s that easy. Thanks!
Great!
Hello Rodolfo,
It is possible to modify this snippet to be able to activate a payment method via coupon?
For example. Paypal would be disabled until the usser place the “PAYPALMSI” coupon.
Hey Omar, 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!
Hi Rodolfo,
It works like a charm for me.
Thank you so much!
Great!
Still working fine. You always have the answer for my questions.
Thank you so much!
Great!
Hi Rodolfo, thanks for the snippet.
I am wondering, why the
part in the if statement?
Would this not work without that and just check for the shipping method?
Thanks again
Cheers
Ciao Luca, it would work but I first check if it exists, so that PHP errors are not generated
hello,
is there a custom code avialable where i can disable cash on delivery if coupon code is entered
Hello Crusin, 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!
What a great piece of work, it works perfectly except on my health status menu I have the following error, any idea what’s happening? TIA!
The REST API is one way WordPress, and other applications, communicate with the server. One example is the block editor screen, which relies on this to display, and save, your posts and pages.
The REST API call gave the following unexpected result: (500) Fatal error: Uncaught Error: Call to a member function get() on null in /home/clients/c7b2592800afc300b90d509d8e57be78/web/wp-content/themes/oceanwp-child02/functions.php:65 Stack trace: #0 /home/clients/c7b2592800afc300b90d509d8e57be78/web/wp-includes/class-wp-hook.php(287): bbloomer_gateway_disable_shipping_326(Array) #1
Hi Fanny, not sure, sorry
I have the same problem. Otherwise the snippet works fine. Theme Astra.
Works fine as of today november 2020, Great snippets!
Thanks!
Hi, also working for me, but I have two shipping methods and while I choose one of those need to disable one payment. So how to add one more shipping ID into snippet? Thanks
Hi Migino, 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!
Hello.
From a mobile device only, in every product, apears a button “buy now” that send the buyer to an other payment option (by woocommece) and the button “ad to basket” is underneath. I think i’ve made a conection with woo, sometime, and i want to disable it. I see no option for that in settings.
Thanks!!!
Try disabling all plugins but WooCommerce
Thanks for the great snippet.
However, it doesn’t work for me .. this is my code:
unlike you, i want to disable the payment methods, I have three options, cash on delivery, Benefit, and credimax
I want to disable Benefit and credimax when choosing smsa express cash on delivery option
but the snippet did not work for me
This will require custom troubleshooting, sorry
Hi Rodolfo,
Thank you so much for your website and recommendations on WooCommerce customisation.
I have physical and virtual products. The virtual products do not allow for a Shipping option to be set.
Your code above though disables the payment gateway for my virtual products as well.
Can this be remedied somehow?
i look forward to hearing from you.
Kind regards,
Hey Dale, try with https://www.businessbloomer.com/woocommerce-conditional-logic-ultimate-php-guide/
Hi Rodolfo,
I ended up purchasing “WooCommerce Conditional Payment Gateways”, which works great for many of the other scenarios I face.
This link you shared is invaluable though. Thank you so much.
Cool
I just want to say thank you! Your small snippet is much better than all others plugins. It is so easy now!
Thank you!
Hi
How can I check when a payment method is selected? I’m asking this question because I would like to change the button url based on the payment selected. I tried the following code but doesn’t seem to work:
I also tried the following but didn’t work either:
Would you know how I can check when a payment option is selected?
Thank you
Hello Gauthier, 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!
Hello
The code prevents contact form 7 functionning properly.
error 500
Hello Nina. Do you have a CF7 on the checkout page?
please tell me, how can I disable cash on delivery when customers billing address and shipping address is different?
Hey Mimo, 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!
Hello,
How can I do the following:
I have 2 shipping methods and 2 payment methods
When I select Cash on Delivery = it shows only specific Shipping Method
and if I select Paypal = it shows the other Shipping Method.
Thank you
Hello Mizo, 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!
Hi Rodolfo
Is there anyway to disable specific payment gates if shipping and billing addresses are different (Billing zip code not same as shipping zip code)
Alex, 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!
Big thanks for your snippet!!!!!
You’re welcome!
Great Thank you, I modified it to display specific payment method only if one of the shipping methods is selected and it is working fine,
Great!
Hi,
I am going inform users why payment method was removed. I use woocommerce_review_order_before_payment action to display a notice when local pickup selected. Unfortunately this action runs only on initial page load. If shipping method is being changed on checkout page, notice doesn’t appear/disappear.
It is possible to force to refresh the action?
Attila, 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!
Thank you! Just what I needed and it works perfectly 😀
Fantastic 🙂
Looks like it doesn’t work in the newest version of Woocommerce, could you please take a look?
Hi there, thanks for your comment! Just tested on Woo 3.5 and it still works 🙂
Hello Rodolfo, thank you for a great work here. The snippet works wonderfully except for one shipping method. I have “easypack parcel mechines” shipping method with and without ‘COD’. When I disable ‘COD’ payment gateway for standard e.p.m it also disables COD for.. COD e.p.m. How is this possible? Shall I contact easypack parcels support or can you help me anyhow?
All the best,
Joanne
Yes Joanne, try getting their help first 🙂 Thank you!
Thanks for this, this stopped working on the latest version of woocommerce 🙁
Hey Rob, thanks for your comment! I just tested this again with Storefront theme and it works perfectly. Maybe your theme (or another plugin) is messing/conflicting with my snippet?
To troubleshoot, go to WP Dashboard > WooCommerce > System Status: what errors do you see in red font?
Also, take a look at this tutorial to see how to troubleshoot: https://businessbloomer.com/woocommerce-troubleshooting-mistakes-to-avoid/
Finally, can you try switching temporarily to “Twentyseventeen” or “Storefront” theme and let me know if it works?
Hope this helps!
R
Hi Rodolfo,
your snippet works for hiding selected payment methods BUT it totally breaks the menus under Appearance → Menus screen… I tested it with Storefront on Woocommerce 3.2.6.
It looks like the lines:
$chosen_methods = WC()->session->get( ‘chosen_shipping_methods’ );
$chosen_shipping = $chosen_methods[0];
cause load-scripts.php error
Thank you Anna and Natalie! Snippet has now been fixed 🙂
Hi there, just got on your blog entry here, having the same issue. I pasted your code into the function on my child theme. I’m not sure if I entered the parameters correctly. I just pasted this one:
Maybe I just get the ID term wrong? Any Idea?
Thank you
Jonathan
Hey Jonathan, thanks so much for your comment! I think you left a comment on the wrong blog post, and also I don’t provide custom troubleshooting here via the blog comments I’m afraid. Little hint – check the “$values[‘product_id’]” part, you shouldn’t have a “9” in there, you should leave it as is 🙂
Hi Rodolfo,
Thanks for the great snippet! I’ve developed it a bit and created a basic plugin where you can select available payment gateways for each shipping method on woocommerce admin panel, no coding is required. Feel free to use it: https://github.com/piotr-urbanowicz/woo-payments-by-shipping
Thank you so much 🙂
How about the other way around, disabling a shipping method based on specific payment gateway?
Hey Jeboy, thanks so much for your comment! Yes, this is possible – but unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. Thanks a lot for your understanding! ~R
would be interested in that solution as well
Thank you sooooo much for your tips. I do not like to install plugins for every costumization, you had helped me a lot!
Thank you Ricardo 🙂
Thank you for this code, but on my website, it disables Menus gestion/ creation (Appearance > Menus) when i add your code, and everything is allright when i delete your code.
My version : Woocommerce 3.1.2 ; Divi-child (Divi on last version)
Here is my code :
Thank you for your help 🙂
Nathalie, thanks so much for your comment! Unfortunately this is custom troubleshooting work and I cannot help here via the blog comments. Thanks a lot for your understanding! ~R
Thank you Rodolfo, I undestand, of course :).
After contact with Divi developpers, here is the issue :
“Your code was included on all the pages, including on the dashboard, and for some reason, WooCommerce variables weren’t loaded there, on the menu page, and it was returning a fatal error.
So I added a conditional check to include the code just on front-end and it seems to work fine” :
if(!is_admin() ) add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_gateway_disable_shipping_30' );
I don’t know why, but it works !
Good to know, thanks a lot 🙂
Thanks Nathalie for your snippet, it resolved my issue as well 🙂
Hello..
not working with wc 3.0. Changed local_delivery name local_pickup but not working.
Thanks Bulent! I just added a new version of the snippet, let me know if it works 🙂
Hi Rodolfo.
I succeeded with your snippet for disabling cod for product class. Thanks for that. This one is a bit puzzle.
I have a shipping method Česká pošta (czech post). I found its id=16. What should I put instead of your ‘local_delivery’ to the snippet?
I tried the name ‘Česká pošta’ ,but it does not work. Could I use the ID somehow?
thanks
Lasercat
Hey Zdenek, thanks for your comment! Go to WooCommerce > Settings > Shipping > Shipping Zone > Shipping Method and see where the Shipping ID is by using “Inspect Element” in Chrome. I believe it will be something like “ceska-posta” or “ceska_posta” 🙂
WooCommerce 2.6.4 The code does not work ((Please, update!! 🙂
I get an error 500 when I go to the /wp-admin
Hey Voltik, thanks for your comment! I pasted this function in my test website and it doesn’t give me error at all – can you please check again? Then we will go through the fact that WooCommerce changed how the shipping works in 2.6, but for now at least let me know if it doesn’t break your theme! 🙂
Hi Rudolfo,
I’ve only just encountered this code and it seems to be very close to what I’m after.
With our site though, the customer can’t choose their shipping method. Instead, it is set based on their country. How would I alter your code to look at the shipping method, without first checking to see if it has been chosen?
I hope that was clear!
Hello Mark, thanks for your comment 🙂 WooCommerce provides already a geolocation functionality – you could find out how that works and use that instead of using conditional logic by shipping method! Hope this helps a little 🙂
Hi Rudolfo,
Nice one, can you put an example with two gateways and two shipping methods
🙂 thanks
Hey Lubo thanks for your comment! It’s quite simple actually – under this code:
you can add another if statement:
Hope this helps 🙂
Hi Rodolfo !
Thank you for your snippet.
Everything is working fine but when I choose another shipping method the filter does not apply any more (cod comes back). Do you have also this issue with storefront ?
Woocommerce version 2.6.14
Hey Marc thanks for your comment! I’m not sure I fully understand your point – this snippet disables a gateway only for 1 specific shipping method, so if you change shipping the gateway should come back. Let me know!