Disable Payment Method for a Specific Product
In this tutorial, I will show you two things: how to disable a payment method on your WooCommerce store for a specific product, and then we will do it for a product category (or a product tag, or a product brand – the whole idea is the same).
We will do it using two approaches:
- at the beginning, I will show you how to do it with the plugin,
- and after that we will dive into the programmatic approach.
Let’s jump into it.
Configure Different Payment Methods for Different Products Using a Plugin
In this chapter, we’ll use the Simple Conditional Shipping and Payments plugin to restrict specific payment methods based on a product in the cart in just a few clicks.
To do so, you need to go to the plugin settings in WooCommerce > Settings > Conditions first and add a new payment condition there.
An example of the condition is below:

It can be done in a similar way for product categories – simply select a “Product category” condition and choose a specific product category from your store:

I also want to tell you about the difference between “AND” and “OR” conditions and how to configure both of them:
- “AND-condition” – is needed in a scenario when we want to enable or disable a specific payment gateway for two or more products in the cart at the same time; in other words, both products “Product 1” and “Product 2” should be in the customer’s cart (or in an order) for a condition to be applied.
- “OR-condition” – when you add multiple products in the condition, and just having one of them in the customer’s cart will be enough to trigger the condition (it is similar to using a “Product category” condition).
With the Simple Conditional Shipping and Payments plugin, both types of conditions can be easily configured.
For the “OR”-type, you can use a “Product category” condition as I mentioned before, or add more conditional rules like this:

For the “AND”-type, you will need to add multiple conditions within a single rule:

That’s pretty much it, guys, for the plugin approach. Needless to say, you can create conditions for product variations.
Disabling Payment Method for a Product Programmatically
Creating a brand new WooCommerce settings page with conditions can be a pretty big deal; that’s why it would be better to add some settings to product pages instead:

You might ask, but maybe we can add these settings straight to the payment gateway options. At this moment, I am not sure we can easily modify the init_form_fields() method of the WC_Payment_Gateway class unless your custom payment gateway has a filter hook inside. If you think that I am missing something, please let me know in the comments.
Let’s uncover the entire process step by step anyway.
1. Add an option to the product settings
Sure thing, this step is optional, and you can feel free to hardcode product IDs directly into the woocommerce_available_payment_gateways filter hook in the next step. However, it would be nice to have a neat setting on the product pages.
To create a setting field, I am going to use this code snippet:
add_action( 'woocommerce_product_options_advanced', function(){
// get all installed payment gateways
$payment_methods = WC()->payment_gateways()->payment_gateways();
if( ! $payment_methods ) {
return;
}
$options = array(
'' => 'Select a payment method',
);
// let's create an options array for our select dropdown
foreach( $payment_methods as $payment_method_slug => $payment_method ) {
$options[ $payment_method_slug ] = $payment_method->method_title;
}
echo '<div class="options_group">';
woocommerce_wp_select( array(
'id' => 'disable_payment_method',
'value' => get_post_meta( get_the_ID(), 'disable_payment_method', true ),
'label' => 'Disable payment method',
'options' => $options,
) );
echo '</div>';
} );
add_action( 'woocommerce_process_product_meta', function( $product_id ){
$payment_method = ! empty( $_POST[ 'disable_payment_method' ] ) ? wc_clean( $_POST[ 'disable_payment_method' ] ) : '';
update_post_meta( $product_id, 'disabled_payment_method', $payment_method );
} );I didn’t want to just hardcode a checkbox like “Disable cash on delivery for this product”, so I decided to get payment gateways dynamically with the payment_gateways() method, which allows a shop manager (or whoever can edit products in your store) to choose a different payment method for every specific product.
And here we go:

2. Disable payment method on the checkout page when a product is in the cart
It is time to tap into the woocommerce_available_payment_gateways hook.
add_filter( 'woocommerce_available_payment_gateways', function( $gateways ){
if( ! is_checkout() ) {
return $gateways;
}
foreach( WC()->cart->get_cart_contents() as $key => $cart_item ) {
// count number of items if needed (optional)
$disabled_payment_method = get_post_meta( $cart_item[ 'data' ]->get_id(), 'disable_payment_method', true );
if( ! $disabled_payment_method ) {
continue;
}
if( ! isset( $gateways[ $disabled_payment_method ] ) ) {
continue;
}
unset( $gateways[ $disabled_payment_method ] );
}
return $gateways;
} );A couple of things I’d like to highlight here:
- In the very beginning, we’re checking whether our code is running either in the WooCommerce cart or checkout page – it is an important thing to do; otherwise, we may notice, for example, that our payment methods disappear from the admin area. Another story is the “Pay for order” page on the “My Account” page. We are going to talk about it in just a little bit.
- It is not necessary to run the
get_post_meta()function for each product in the cart. Perhaps, in terms of performance, it would be better to store all the product IDs for which we’d like to disable a payment gateway inwp_options. - Last but not least, this code snippet works great for both classic and block checkout.
3. Disable payment methods in “My account” as well
Here, I mean the “Pay for order” page, of course. It would be weird if customers couldn’t use a specific payment method on the checkout page, but then they can freely use it when paying for an order directly.
The thing is that the code above will not work for this page because the customer cart is either empty or already has other products in it. This means that we can not rely anymore on the WC()->cart->get_cart_contents() method and need to get the order items from that specific order instead.
add_filter( 'woocommerce_available_payment_gateways', function( $gateways ){
if( ! is_wc_endpoint_url( 'order-pay' ) ) {
return $gateways;
}
$order_id = wc_get_order_id_by_order_key( $_GET[ 'key' ] );
$order = wc_get_order( $order_id );
foreach( $order->get_items() as $item_id => $order_item ) {
$disabled_payment_method = get_post_meta( $order_item->get_product_id(), 'disable_payment_method', true );
if( ! $disabled_payment_method ) {
continue;
}
if( ! isset( $gateways[ $disabled_payment_method ] ) ) {
continue;
}
unset( $gateways[ $disabled_payment_method ] );
}
return $gateways;
} );4. Disable multiple payment methods at once
I can already foresee your questions in comments like: “Misha, how to do it for multiple payment methods?” 😁
So, why not take a look at it right now?
First things first – product settings. How can we organize it there? One of the options is using a multi-select field where you can add multiple payment methods (WooCommerce version of the Select2 script). Another option is creating a custom settings tab where we just display all the added payment methods as checkboxes.
Something like this:

Also, I don’t want to copy most of the code as pieces, so let’s create a complete plugin from it:
/**
* Plugin name: WooCommerce Disable payment method for specific product
* Version: 1.0
* Description: Adds checkboxes with payment gateways you would like to disable into each product settings
* Author: Misha Rudrastyh
* Plugin URI: https://rudrastyh.com/woocommerce/restrict-payments-gateways-for-specific-products.html
*/
class Rudr_Payment_Methods_By_Products{
public function __construct() {
// product settings
add_filter( 'woocommerce_product_data_tabs', array( $this, 'product_tabs' ) );
add_action( 'woocommerce_product_data_panels', array( $this, 'product_settings_html' ) );
add_action( 'woocommerce_process_product_meta', array( $this, 'product_settings_save' ) );
// disable payment gateway
add_filter( 'woocommerce_available_payment_gateways', array( $this, 'disable_payment_method' ) );
}
// add one more tab into the product settings meta box
public function product_tabs( $tabs ) {
$tabs[ 'payment-methods' ] = array(
'label' => 'Payment Methods',
'target' => 'rudr_payment_methods_tab',
);
return $tabs;
}
// add checkboxes with payment methods into that tab
public function product_settings_html() {
// get all installed payment gateways
$payment_methods = WC()->payment_gateways()->payment_gateways();
if( ! $payment_methods ) {
return;
}
$options = array(
'' => 'Select a payment method',
);
echo '<div id="rudr_payment_methods_tab" class="panel woocommerce_options_panel hidden">';
// an array with disabled payment methods slugs
$disabled_payment_methods = get_post_meta( get_the_ID(), 'disable_payment_methods', true );
$disabled_payment_methods = is_array( $disabled_payment_methods ) ? $disabled_payment_methods : array();
// loop through all the installed payment gateways and display a checkbox for each one of them
foreach( $payment_methods as $payment_method_slug => $payment_method ) {
woocommerce_wp_checkbox(
array(
'id' => "disable_payment_method-{$payment_method_slug}",
'name' => 'disable_payment_methods[]',
'cbvalue' => $payment_method_slug,
'value' => in_array( $payment_method_slug, $disabled_payment_methods ) ? $payment_method_slug : '',
'label' => "Disable {$payment_method->method_title}",
)
);
}
echo '</div>';
}
// save product settings
public function product_settings_save( $product_id ) {
$disable_payment_methods = ! empty( $_POST[ 'disable_payment_methods' ] ) ? wc_clean( $_POST[ 'disable_payment_methods' ] ) : '';
update_post_meta( $product_id, 'disable_payment_methods', $disable_payment_methods );
}
// it is time to disable payment methods for those specific products
public function disable_payment_method( $gateways ) {
// mainly for the checkout page
if( is_checkout() ) {
foreach( WC()->cart->get_cart_contents() as $key => $cart_item ) {
$disable_payment_methods = get_post_meta( $cart_item[ 'data' ]->get_id(), 'disable_payment_methods', true );
if( ! $disable_payment_methods ) {
continue;
}
foreach( $disable_payment_methods as $method ) {
if( isset( $gateways[ $method ] ) ) {
unset( $gateways[ $method ] );
}
}
}
// "Pay for order" in my account page
} elseif( is_wc_endpoint_url( 'order-pay' ) ) {
$order_id = wc_get_order_id_by_order_key( $_GET[ 'key' ] );
$order = wc_get_order( $order_id );
foreach( $order->get_items() as $item_id => $order_item ) {
$disable_payment_methods = get_post_meta( $order_item->get_product_id(), 'disable_payment_methods', true );
if( ! $disable_payment_methods ) {
continue;
}
foreach( $disable_payment_methods as $method ) {
if( isset( $gateways[ $method ] ) ) {
unset( $gateways[ $method ] );
}
}
}
}
return $gateways;
}
}
new Rudr_Payment_Methods_By_Products;Disabling Payment Method for a Product Category
Of course, nothing stops us from creating a setting for a product category as well. You can do it from scratch, or you can use my Simple Fields plugin for that if you want.
And here is the snippet you can use:
add_filter( 'simple_register_taxonomy_settings', function( $settings ) {
$payment_methods = WC()->payment_gateways()->payment_gateways();
if( ! $payment_methods ) {
return $settings;
}
$options = array();
foreach( $payment_methods as $payment_method_slug => $payment_method ) {
$options[ $payment_method_slug ] = $payment_method->method_title;
}
$settings[] = array(
'id' => 'rudr_product_cat_settings',
'taxonomy' => array( 'product_cat' ),
'fields' => array(
array(
'id' => 'disable_payment_method',
'label' => 'Disable payment method',
'type' => 'select',
'placeholder' => 'Select a payment method',
'options' => $options,
),
)
);
return $settings;
} );We’re going to have a select dropdown with the payment gateways like this:

Once we finish with category settings, let’s come back to the woocommerce_available_payment_gateways filter hook.
add_filter( 'woocommerce_available_payment_gateways', function( $gateways ) {
// don't forget about My Account page as well, I skipped it here for the sake of simplicity
if ( ! is_checkout() ) {
return $gateways;
}
foreach( WC()->cart->get_cart_contents() as $key => $cart_item ) {
$product_categories = get_the_terms( $cart_item[ 'data' ]->get_id(), 'product_cat' );
foreach( $product_categories as $cat ) {
$disable_payment_method = get_term_meta( $cat->term_id, 'disable_payment_method', true );
if( ! $disable_payment_method ) {
continue;
}
if( isset( $gateways[ $disable_payment_method ] ) ) {
unset( $gateways[ $disable_payment_method ] );
}
}
}
return $gateways;
} );Feel free to ask any questions in the comments section below.
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
Hi Misha,
It seems that
woocommerce_available_payment_gatewaysfilter doesn’t really work with the woo-commerce-checkout-block: it works fine when the page loads, but then when the user updates the form, the unset gateways are displayed again. Do you have any idea how to solve this problem?Thanks for all your great blog posts.
Hi Celestin,
In that case, you could try the plugin approach 🙃 I have just tested it – it works great for your scenario.
Thank you for this example. Unfortunately your plugin threw a fatal error on line 58 for me when the post didn’t have the meta field set. I fixed that by changing line 47 to:
Thank you for noticing, Rickk.
It is fixed.
Sorry about that, the code snippets are super-simplified here, so not every scenario is tested.