WooCommerce: Disable Payment Gateway For Specific Shipping Method

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”). Enjoy!

WooCommerce: disable gateway based on shipping method
WooCommerce: disable gateway based on shipping method

PHP Snippet: Disable Payment Gateway For Specific Shipping Method – WooCommerce

/**
 * @snippet       Disable Payment Gateway For Specific Shipping Method
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @testedwith    WooCommerce 3.6.2
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
 
add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_gateway_disable_shipping_326' );
 
function bbloomer_gateway_disable_shipping_326( $available_gateways ) {
    
   if ( ! is_admin() ) {
       
      $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;
    
}

Is There a WooCommerce “Payment Gateways by Shipping Method” Plugin?

If you don’t feel 100% confident with coding, 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 ๐Ÿ™‚

Where to add this snippet?

You can place PHP snippets at the bottom of your child theme functions.php file (before "?>" if you have it). 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+.

If you think this code saved you time & money, please join other Business Bloomer supporters and avail of 365 days of WooCommerce benefits. Thank you in advance :)

Need Help with WooCommerce Customization?

Check out these free video tutorials. You can start learning how to customize WooCommerce without unnecessary plugins. Watch me code and learn by example!

  • how-to-edit-woocommerce-with-php-snippets
  • woocommerce-hooks-add_action-list-visual
  • woocommerce-customize-single-product-page-PHP

Rodolfo Melogli

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as a 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.

52 thoughts on “WooCommerce: Disable Payment Gateway For Specific Shipping Method

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

    if(isset( $available_gateways['pay_by_the_month'] )) {
    		$button_html = '<a href="/contact/" title="Contact us">Enquire now</a>';
    		return $button_html;
    	}

    I also tried the following but didn’t work either:

    if($available_gateways['pay_by_the_month']->chosen == true ) {
    		$button_html = '<a href="/contact/" title="Contact us">Enquire now</a>';
    		return $button_html;
    	}

    Would you know how I can check when a payment option is selected?
    Thank you

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

  2. Hello
    The code prevents contact form 7 functionning properly.

    error 500

    1. Hello Nina. Do you have a CF7 on the checkout page?

  3. please tell me, how can I disable cash on delivery when customers billing address and shipping address is different?

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

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

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

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

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

  6. Big thanks for your snippet!!!!!

    1. You’re welcome!

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

    1. Great!

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

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

  9. Thank you! Just what I needed and it works perfectly ๐Ÿ˜€

    1. Fantastic ๐Ÿ™‚

  10. Looks like it doesn’t work in the newest version of Woocommerce, could you please take a look?

    1. Hi there, thanks for your comment! Just tested on Woo 3.5 and it still works ๐Ÿ™‚

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

    1. Yes Joanne, try getting their help first ๐Ÿ™‚ Thank you!

  12. Thanks for this, this stopped working on the latest version of woocommerce ๐Ÿ™

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

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

    1. Thank you Anna and Natalie! Snippet has now been fixed ๐Ÿ™‚

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

    /**
     * @snippet       Disable Payment Method for Specific Category
     * @how-to        Get CustomizeWoo.com FREE
     * @sourcecode    https://businessbloomer.com/?p=19892
     * @author        Rodolfo Melogli
     * @testedwith    WooCommerce 2.5.2
     */
     
    add_filter('woocommerce_available_payment_gateways','bbloomer_unset_gateway_by_category');
     
    function bbloomer_unset_gateway_by_category($available_gateways){
    global $woocommerce;
    $category_IDs = array(316,317);
    foreach ($woocommerce->cart->cart_contents as $key => $values ) {
    $terms = get_the_terms( $values['9'], 'Appointments' );    
    foreach ($terms as $term) {        
    if(in_array($term->term_id, $category_IDs)){
        unset( $available_gateways['cheque'] );
                break;
            }
        break;
        }
     }
        return $available_gateways;
    }
    

    Maybe I just get the ID term wrong? Any Idea?

    Thank you
    Jonathan

    1. 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 ๐Ÿ™‚

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

    1. Thank you so much ๐Ÿ™‚

  16. How about the other way around, disabling a shipping method based on specific payment gateway?

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

    2. would be interested in that solution as well

  17. Thank you sooooo much for your tips. I do not like to install plugins for every costumization, you had helped me a lot!

    1. Thank you Ricardo ๐Ÿ™‚

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

     
    function bbloomer_gateway_disable_shipping_30( $available_gateways ) {
    global $woocommerce;
    $chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
    $chosen_shipping = $chosen_methods[0];
    if ( isset( $available_gateways['paypal'] ) && 0 === strpos( $chosen_shipping, 'local_pickup' ) ) {
    	unset( $available_gateways['paypal'] );
    }
    if ( isset( $available_gateways['cheque'] ) && 0 === strpos( $chosen_shipping, 'local_pickup' ) ) {
    	unset( $available_gateways['cheque'] );
    }
    return $available_gateways;
    }
    add_filter( 'woocommerce_available_payment_gateways', 'bbloomer_gateway_disable_shipping_30' );
    

    Thank you for your help ๐Ÿ™‚

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

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

      1. Good to know, thanks a lot ๐Ÿ™‚

    3. Thanks Nathalie for your snippet, it resolved my issue as well ๐Ÿ™‚

  19. Hello..

    not working with wc 3.0. Changed local_delivery name local_pickup but not working.

    1. Thanks Bulent! I just added a new version of the snippet, let me know if it works ๐Ÿ™‚

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

    1. 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” ๐Ÿ™‚

  21. WooCommerce 2.6.4 The code does not work ((Please, update!! ๐Ÿ™‚
    I get an error 500 when I go to the /wp-admin

    1. 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! ๐Ÿ™‚

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

    1. 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 ๐Ÿ™‚

  23. Hi Rudolfo,

    Nice one, can you put an example with two gateways and two shipping methods

    ๐Ÿ™‚ thanks

    1. Hey Lubo thanks for your comment! It’s quite simple actually – under this code:

      if ( isset( $available_gateways['cod'] ) && $chosen_shipping == 'local_delivery' ) {
      unset( $available_gateways['cod'] );
      }
      

      you can add another if statement:

      if ( isset( $available_gateways['cod'] ) && $chosen_shipping == 'local_delivery' ) {
      unset( $available_gateways['cod'] );
      }
      if ( isset( $available_gateways['paypal'] ) && $chosen_shipping == 'flat_rate' ) {
      unset( $available_gateways['paypal'] );
      }
      

      Hope this helps ๐Ÿ™‚

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

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

Questions? Feedback? Support? Leave your Comment Now!
_____

If you are writing code, please wrap it between: [php]code_here[/php]. Failure to complying with this (as well as going off topic) will result in comment deletion. You should expect a reply in about a week - this is a popular blog but I need to get paid work done first. Please consider joining #BloomerArmada to ask me 1-to-1 WooCommerce questions. Thank you :)

Your email address will not be published. Required fields are marked *