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:

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:

WooCommerce disable payment method for a specific product

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:

Disable WooCommerce payment methods for a product category

I also want to tell you about the difference between “AND” and “OR” conditions and how to configure both of them:

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:

Using multiple conditional rules
The “Cash on delivery” payment method will not be available when either “Product 1” or “Product 2” is in the cart.

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

multiple product conditions
For this conditional rule to be applied, both “Product 1” and “Product 2” should be in the cart at the same time.

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:

WooCommerce payment gateway per product

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:

WooCommerce payment gateway per product

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:

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:

Configuring different payment methods for different products in WooCommerce

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:

Disable a payment method for a specific product category

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

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

Follow me on X