1. Documentation /
  2. Pre-Orders Payment Gateway Integration Guide

Pre-Orders Payment Gateway Integration Guide

Adding pre-orders support to your existing payment gateway extension is a great way to attract new customers and provide a valuable feature for your existing customers. Pre-Orders offers a full-featured API for pre-order management — you just need to add payment processing. This guide outlines the required steps for integrating a payment gateway with WooCommerce Pre-Orders. Note that your payment gateway must provide some way to tokenize a customer’s payment method so that it can be charged later. There are 3 steps to add pre-order support:

  1. Register support for Pre-Orders
  2. Handle initial processing of Pre-Orders
  3. Handle processing of pre-order completion payments
Before continuing with this guide, you should have read the general Pre-Orders guide. You should also have an in-depth understanding of the WooCommerce Payment Gateway API.

Register support for Pre-Orders

↑ Back to top
When an order contains a product that can be pre-ordered, the Pre-Orders extension filters the available payment gateways. If the pre-order is charged upfront, all enabled gateways are available. If the pre-order is charged upon release, only supported gateways are available. Your gateway must register its support for pre-orders charged upon release using the WC_Payment_Gateway::supports() This is done by setting the supports property of your gateway to an array containing pre-orders (and products if your gateway also supports product purchases). For example, the __construct() function of your gateway class should include a line like the following:
class WC_Best_Payment_Gateway_Ever extends WC_Payment_Gateway {

	public function __construct() {
		...
		$this->supports = array( 'products', 'pre-orders' );
		...
	}
	...
}
Now whenever an order contains a pre-order charged upon release, your payment gateway will be shown as a payment option.

Processing payments for Pre-Orders

↑ Back to top
A pre-order that is charged upfront does not require any special handling, so these orders can be processed like regular orders. The Pre-Orders API provides a method to check if a pre-order exists in the cart, as well as check how the pre-order is charged. Use WC_Pre_Orders_Order::order_contains_pre_order() to determine if the order contains a valid pre-order. You may pass in an Order ID or an order object. Use WC_Pre_Orders_Order::order_requires_payment_tokenization() to determine if the order requires payment tokenization. Pre-Orders that are charged upon release typically require payment tokenization so that the customer’s payment method can be charged when the pre-order is released. The best practice for handling these cases is :
public function process_payment( $order_id ) {
	...

	if ( WC_Pre_Orders_Order::order_contains_pre_order( $order_id ) ) {

		// the order 
		if ( WC_Pre_Orders_Order::order_requires_payment_tokenization( $order_id ) ) {

			...

			// perform a simple authorization/void (or whatever method your gateway requires)
			// to get the payment token that may be used later to charged the customer's payment method

			// mark order as pre-ordered, this will also save meta that indicates a payment token
			// exists for the pre-order so that it may be charged upon release
			WC_Pre_Orders_Order::mark_order_as_pre_ordered( $order );

			// here you should empty the cart and perform whatever other tasks a successful purchase requires

			...

		} else {

			// handle pre-orders charged upfront, or paying for a newly-released pre-order with the gateway
			// process just like regular product
			return parent::process_payment( $order_id );
		}
	}
	...
}
The Authorize.net CIM and Braintree TR gateways support pre-orders so reviewing their code may help to understand this process better.

Processing Pre-Order Completion Payments

↑ Back to top
Once the release date for a pre-order is reached, an action is fired that your gateway must hook into in order to process the completion payment. This action should be hooked into within your gateway’s constructor. The pre-order order object is passed into this action.
// process batch pre-order payments
add_action( 'wc_pre_orders_process_pre_order_completion_payment_' . $this->id, array( $this, 'process_pre_order_payments' ) );
Inside the process_pre_order_payments() method, you should charge the order total to the payment method that was saved to the order during the initial checkout. Your code should look like:
public function process_pre_order_payments( $order ) {

	// the total amount to charge is the the order's total
	$total = $order->get_total();

	...

	// get the payment token and attempt to charge the transaction

	// success!
	if ( $transaction_successful ) {

		...

		// complete the order
		$order->payment_complete();

	} else {

		// failure
		// mark the order as failed
		...
	}
	...
}
There is no special order handling required for processing a pre-order payment completion. If the payment fails for any reason, you should mark the order as failed. In this case the customer will be emailed and instructed to come back to the store and pay for the order with a different payment method. You must call $order->payment_complete() when the transaction is successful, as this will change the pre-order’s status to completed and let the shop admin know the pre-order can be shipped.