Stuart Lambon

Creating a ‘credit account’ payment method on WooCommerce

Recently, whilst building an e-commerce website for a client an interesting feature arose which I’d yet had to build on any other WooCommerce website: to allow certain users to pay via credit ‘on account’. It’s worth noting that the process of applying for a credit account would be handled manually due to credit checks needing to be fulfilled etc.

This is how I built this feature into a custom theme using a relatively simple process:

Step 1—Add a new user role

It’s important to make sure that this extra payment method is locked out to normal customers because it essentially allows them to process orders with no upfront payments. It is possible to create a new user role using the add_role(); function (documentation here) but because you will need to clone exactly the same capabilities as a default WooCommerce customer I’d recommend using the WordPress Members plugin for a few reasons: 1. It allows you to clone an existing role. 2. It’s a lot quicker and roles remain the the database anyway. 3. It allows you to allocate multiple roles to any user which is ideal for testing. I cloned the default WooCommerce ‘Customer’ role with exactly the same capabilities and renamed to, ‘Customer (with account)’.

Step 2—Enable ‘Cash on Delivery’ payment method

This sounds odd but actually once you enable the ‘Cash on Delivery’ payment method and rename it to ‘Pay on account’ it includes the correct functionality to achieve what we need; allowing users to process orders without spending any money upfront.

Step 3—Create a new function to disallow non-account users from using this method

We can use the woocommerce_available_payment_gateways hook to do this. All this function does is check that the payment method 'cod' (Cash on delivery) is turned on and removes it from the list of methods if the current user does not match the role of 'customer-with-account'. This should be added to the theme’s functions.php file.

function payment_gateway_disable_on_account( $available_gateways ) {
		
	// Get current user
	$user = wp_get_current_user();
	
	// If ‘cash on delivery — cod’ (what we have named ‘On account’) is active AND
	// customer IS NOT ‘customer_with_account’ role
	// then remove cod
	if ( isset( $available_gateways['cod'] ) && !in_array( 'customer_with_account', (array) $user->roles ) {
	    unset(  $available_gateways['cod'] );
	}
		
	return $available_gateways;
}

add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_on_account' );

There is a WooCommerce plugin that handles some of this functionality if you require more flexibility or don’t want to dip into the code.

Step 4 (Optional)—Limit order value (add a credit/order limit)

Our client didn’t want to allow their customers to process orders that were of too high a value—this was essentially adding a credit limit to that account. I added an extra meta field to the users so that this limit could be adjusted on a user-by-user basis but the default was set to £5,000.

Here’s the expanded function with the extra code regarding limits:

function payment_gateway_disable_on_account( $available_gateways ) {
	global $woocommerce;
	
	// Get current user & details
	$user = wp_get_current_user();
	$user_id = $user->ID;
	$credit_limit = get_user_meta( $user_id, 'credit_limit', true );
	
	// Get cart subtotal without formatting	
	$amount = floatval( preg_replace( '#[^\d.]#', '', $woocommerce->cart->get_cart_subtotal() ) );
	
	// Set credit limit to default of 5000 if nothing is set
	if ( empty( $credit_limit ) ) {
		$credit_limit = 5000;
	}
	
	// Work out remaining 
	$credit_remaining = $credit_limit - $amount;
		
	// If ‘cash on delivery — cod’ (what we have named ‘On account’) is active AND
	// customer IS NOT ‘customer_with_account’ role OR 
	// customer IS spending more than 5000 (or custom limit)	
	// then remove cod
	if ( isset( $available_gateways['cod'] ) && !in_array( 'customer_with_account', (array) $user->roles ) || $credit_remaining < 0 ) {
	    unset(  $available_gateways['cod'] );
	}
		
	return $available_gateways;
}

add_filter( 'woocommerce_available_payment_gateways', 'payment_gateway_disable_on_account' );