Payment Gateway API

Payment Gateways in WooCommerce are class based and can be added through traditional plugins. This guide provides an intro to gateway development.

Types of payment gateway ↑ Back to Top

Payment gateways come in several varieties:

  1. Form based – This is where the user must click a button on a form which then redirects them to the payment processor on the gateway’s own website. Example: PayPal standard, DPM
  2. iframe based – This is when the gateways payment system is loaded inside an iframe on your store. Example: SagePay Form, PayPal Advanced
  3. Direct – This is when the payment fields are shown directly on the checkout page and the payment is made when ‘place order’ is pressed. Example: PayPal Pro, AIM
  4. Offline – No online payment is made. Example: Cheque, Bank Transfer

Form and iFrame based gateways post data off-site meaning there are less security issues for you to think about. Direct gateways however require server security to be implemented (SSL certificates etc) and may also require a level of PCI compliance.

Creating a basic payment gateway ↑ Back to Top

Payment gateways should be created as additional plugins that hook into WooCommerce. Inside the plugin you should create your class after the plugins are loaded. Example:

add_action( 'plugins_loaded', 'init_your_gateway_class' );

It is also important that your gateway class extends WC’s base gateway class so that you have access to important methods and the settings API:

function init_your_gateway_class() {
	class WC_Gateway_Your_Gateway extends WC_Payment_Gateway {}

You can view the WC_Payment_Gateway class in the API Docs.

As well as defining your class, you need to also tell WC that it exists. You can do so by filtering woocommerce_payment_gateways:

function add_your_gateway_class( $methods ) {
	$methods[] = 'WC_Gateway_Your_Gateway'; 
	return $methods;

add_filter( 'woocommerce_payment_gateways', 'add_your_gateway_class' );

Required Methods

Most methods are inherited from the WC_Payment_Gateway class, however, some are required in your custom gateway.

Within your constructor you should define the following variables:

  • $this->id – Unique ID for your gateway. e.g. ‘your_gateway’
  • $this->icon – If you want to show an image next to the gateway’s name on the frontend, enter a URL to an image.
  • $this->has_fields – Bool. Can be set to true if you want payment fields to show on the checkout (if doing a direct integration).
  • $this->method_title – Title of the payment method shown on the admin page.
  • $this->method_description – Description for the payment method shown on the admin page.

Your constructor should also define and load settings fields:


We’ll cover init_form_fields() later, but this basically defines your settings which are then loaded with init_settings().

After init_settings() is called, you can get the settings and load them into variables, e.g:

$this->title = $this->get_option( 'title' );

Finally, you need to add a save hook for your settings:

add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );

Use this method to set $this->form_fields – these are the options you’ll show in admin on your gateway’s settings page and make use of the WC Settings API.

A basic set of settings for your gateway would consist of enabled, title and description:

$this->form_fields = array(
	'enabled' => array(
		'title' => __( 'Enable/Disable', 'woocommerce' ),
		'type' => 'checkbox',
		'label' => __( 'Enable Cheque Payment', 'woocommerce' ),
		'default' => 'yes'
	'title' => array(
		'title' => __( 'Title', 'woocommerce' ),
		'type' => 'text',
		'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
		'default' => __( 'Cheque Payment', 'woocommerce' ),
		'desc_tip'      => true,
	'description' => array(
		'title' => __( 'Customer Message', 'woocommerce' ),
		'type' => 'textarea',
		'default' => ''

process_payment( $order_id )
Now for the most important part of the gateway; handling payment and processing the order. Process_payment also tells WC where to redirect the user – this is done with a returned array.

Here is an example of a process_payment function from the Cheque gateway:

function process_payment( $order_id ) {
	global $woocommerce;
	$order = new WC_Order( $order_id );

	// Mark as on-hold (we're awaiting the cheque)
	$order->update_status('on-hold', __( 'Awaiting cheque payment', 'woocommerce' ));

	// Reduce stock levels

	// Remove cart

	// Return thankyou redirect
	return array(
		'result' => 'success',
		'redirect' => $this->get_return_url( $order )

As you can see, its job is to:

  • Get and update the order being processed
  • Reduce stock and empty the cart
  • Return success and redirect URL (in this case the thanks page)

Cheque gives the order on-hold status since the payment cannot be verified automatically. If however you are building a direct gateway you can actually complete the order here instead. When an order is paid for, rather than using update_status you should us payment_complete:


This will ensure stock reductions are made, and the status is changed to the correct value.

If your payment fails, rather than return the success array you should throw an error and return null:

wc_add_notice( __('Payment error:', 'woothemes') . $error_message, 'error' );

WooCommerce will catch this error and show it on the checkout page.

Updating order status and adding notes

Updating the order status can be done using functions in the order class. You should only do this if the order status is not processing (in which case you should use payment_complete()). An example of updating to a custom status would be:

$order = new WC_Order( $order_id );
$order->update_status('on-hold', __('Awaiting cheque payment', 'woothemes'));

The above example update the status to on-hold and adds a note informing the owner that its awaiting a cheque. You can add notes without updating an order’s status – this is using for adding debug message:

$order->add_order_note( __('IPN payment completed', 'woothemes') );

Order status best practice

  • If the order has gone through, but the admin needs to manually verify payment use on-hold
  • If the order fails and has already been created, set to failed
  • If the payment is complete let WooCommerce handle the status and use $order->payment_complete(). WC will use either completed or processing status and handle stock.

Notes on Direct Gateways ↑ Back to Top

If you are creating an advanced, direct gateway (i.e. one which takes payment on the actual checkout page) there are some additional steps involved. First off, you need to set has_fields to true in the gateway constructor:

$this->has_fields = true;

This tells the checkout to output a ‘payment_box’ containing your direct payment form which you’ll define next. Create a method called payment_fields() – this contains your form, most likely to contain credit card details.

The next method you can optionally add is validate_fields(). Return true if the form passes validation, or false if it fails. You can use the wc_add_notice() function if you want to add an error as well and display it to the user.

Finally, you’ll need to add payment code inside your process_payment( $order_id ) method. This needs to take the posted form data and try to take payment directly via the payment provider. If the payment fails you should output an error and return nothing:

wc_add_notice( __('Payment error:', 'woothemes') . $error_message, 'error' );

If on the other hand payment is successful you should set the order as paid, and return the success array:

// Payment complete
// Return thank you page redirect
return array(
	'result' => 'success',
	'redirect' => $this->get_return_url( $order )

Working with Payment Gateway Callbacks (such as PayPal IPN) ↑ Back to Top

If you are building a gateway which makes a callback to your store to tell you about the status of an order you will need to add code to handle this inside your gateway.

The best way to add a callback and callback handler would be to use the WC-API hooks. A quick example would be like PayPal standard does. It sets the callback/IPN url as:

str_replace( 'https:', 'http:', add_query_arg( 'wc-api', 'WC_Gateway_Paypal', home_url( '/' ) ) );

Then hooks in it’s handler to the following hook:

add_action( 'woocommerce_api_wc_gateway_paypal', array( $this, 'check_ipn_response' ) );

WooCommerce will call your gateway and run the action when the URL is called.

For more information on the WooCommerce API see here.

Hooks in gateways ↑ Back to Top

It’s important to note that adding hooks inside gateway classes may not trigger – gateways only get loaded when needed (during checkout and on the settings page in admin). You should keep hooks outside of the class or use WC-API if you need to hook into WordPress events from your class.

More Examples ↑ Back to Top

Fore more examples of payment gateways checkout the core gateways or any of our premium gateways on

Back to the top