Creating a Payment Gateway

Developers can extend the GetPaid_Payment_Gateway PHP class to create their own custom payment gateways. This class will take care of registering the payment gateway and provide a way of adding the admin settings fields and frontend payment fields.

GetPaid supports 4 different types of payment gateways:-

  1. Redirect - When a customer clicks on the pay now button, this payment gateway redirects them to the payment processor's website. For example, PayPal.
  2. iFrame based - The payment fields (e.g credit card forms) are loaded within the payment form in an iframe. For example, Square and Stripe.
  3. Embedded - The payment fields (e.g credit card forms) are added directly to the payment form. For example, Authorize.net AIM. These types of gateways may require the website to be PCI compliant.
  4. Offline - Money is collected offline and the invoice is manually marked as paid. For example, Bank Transfer.

Creating a simple payment gateway

Start by creating a PHP class that extends the GetPaid_Payment_Gateway class as shown...

<?php
/**
 * Custom payment gateway
 *
 */

defined( 'ABSPATH' ) || exit;

/**
 * Custom Payment Gateway class.
 *
 */
class My_Custom_Gateway extends GetPaid_Payment_Gateway {

}

Next, use the getpaid_default_gateways filter hook to register the payment gateway as shown below.

/**
 * Registers the gateway.
 */
function register_my_custom_gateway( $gateways ){
    $gateways['custom'] = 'My_Custom_Gateway';
    return $gateways;
}
add_filter( 'getpaid_default_gateways', 'register_my_custom_gateway' );<br>

That's all.

However, before the gateway can be used to process payments and subscriptions, you need to implement a few required methods.

Required Methods

Most methods will be inherited from the GetPaid_Payment_Gateway class, but some are required in your custom gateway.

__construct()

This is where you set a unique id for the gateway and give it a name and description. In addition, you can also set the features that your gateway supports and add some hooks that are unique to the gateway.

Some of the properties that you can set here include:-

  • checkout_button_text - The label to show on a payment form's submit-button when this gateway is selected. If not set, the label set when editing a payment form will be used instead.
  • id - A unique id for your payment gateway.
  • order - The default priority of your payment gateway. Gateways with a lower priority appear first on payment forms. This can be changed by site admins.
  • title - The (frontend) name of the payment gateway. This is what customers will see. This can be changed by site admins.
  • description - The description of the payment gateway, shown on the frontend. This can be changed by site admins.
  • method_title - The actual name of the payment gateway, shown on the settings page.
  • countries - An array of countries that this payment gateway is allowed for. Do not set if the gateway is usable worldwide.
  • currencies - An array of currencies that this payment gateway is allowed for. Do not set if the gateway should be usable with any currency.
  • exclude_currencies -  An array of currencies that this payment gateway is NOT allowed for. Do not set if the gateway should be usable with any currency.
  • max_amount - The maximum amount that this gateway can process in a single invoice.
  • view_transaction_url - The remote URL to view a transaction. '%s' will be replaced by the transaction ID of an invoice.
  • view_subscription_url - The remote URL to view a subscription. '%s' will be replaced by the remote subscription ID of a subscription.
  • supports - An array of features that this payment gateway supports. This includes sandbox, subscription, tokens and addons.
Before registering hooks for a gateway, it might be a good idea to first check if the gateway is enabled by calling the $this->enabled property.
Example:-
/**
 * Class constructor.
 */
public function __construct() {
  $this->id           = 'custom';
  $this->title        = __( 'Custom', 'my-domain' ); // Frontend name
  $this->method_title = __( 'Custom Gateway', 'my-domain' ); // Admin name
  $this->description  = __( 'Pay using my custom payment gateway', 'my-domain' );
  $this->supports     = array( 'subscription', 'sandbox', 'tokens', 'addons' );

  // Add code that should always run whether or not the gateway is enabled (active).

  // Call the parent constructor.
  parent::__construct();

  // Add code that should only run when the gateway is enabled (active).
  if ( $this->enabled ) {

  }

}

admin_settings( $admin_settings )

When you register a payment gateway, GetPaid will automatically add settings that allow admins to enable/disable the payment gateway, change the name and description shown on payment forms, and if the gateway supports sandbox mode, enable/disable sandbox.

You can add an admin_settings() method to your gateway's class if you need to add more settings.

The example code below allows you to add an "API Key" settings field to your gateway's settings page.

public function admin_settings( $admin_settings ) {

   $admin_settings['custom_api_key'] = array(
       'id'   => 'custom_api_key',
       'name' => __( 'API Key', 'my-domain' ),
       'desc' => __( 'Enter the API Key used to process payments.', 'my-domain' ),
       'type' => 'text',
   );

   return $admin_settings;
}
<br>

payment_fields( $invoice_id, $form )

If you're creating an embedded or iframe-based payment gateway, you can extend the payment_fields() method to display the iframe or credit card form.

This method is passed an invoice id (or 0 if there is no invoice yet) and a payment form object.

You can then display your own payment fields or call the get_cc_form() method to display a pre-built credit card form. The example below shows how to display a quick credit card input form.

public function payment_fields( $invoice_id, $form ) {
   echo $this->get_cc_form()
}

Some payment gateways allow you to tokenize a credit card so that you can use the token for future payments. If yours supports it, ensure to register support for tokens then replace the above code with this one instead.

public function payment_fields( $invoice_id, $form ) {

    // Let the user select a pre-saved payment token...
    echo $this->saved_payment_methods();

    // ... or provide new credit card details.
    echo $this->new_payment_method_entry( $this->get_cc_form( true ) );
}

process_payment( $invoice, $submission_data, $submission )

This is the most important method as it allows you to process the payment, and maybe mark the invoice as paid. The method is passed an invoice object, an array of submitted data, and the submission object.
Here, you can retrieve saved gateway settings such as an API key:-
$api_key = wpinv_get_option( 'custom_api_key' );
You can also fetch the submitted credit card fields:-
$cc_number = $submission_data['custom']['cc_number'];
If there is an error (for example when an API has not been set), use wpinv_set_error() to set the error then redirect the user back to the checkout.
if ( empty( $cc_number ) {
    wpinv_set_error( 'missing_cc', __( 'Please provide a valid credit card number', 'my-domain' ) );
    wpinv_send_back_to_checkout( $invoice );
}
The invoice object allows you to retrieve several details about the transaction including:-
The currency code.
$currency = $invoice->get_currency()
The invoice number.
$invoice_number = $invoice->get_number()
The invoice totals.
$invoice_total  = $invoice->get_total();
$total_discount = $invoice->get_total_discount();
$total_tax      = $invoice->$invoice->get_total_tax();
$subtotal       = $invoice->get_subtotal();
And the customer details.
$first_name  = $invoice->get_first_name();
$last_name   = $invoice->get_last_name();
$address     = $invoice->get_address();
$city        = $invoice->get_city();
$state       = $invoice->get_state();
$zip         = $invoice->get_zip();
$country     = $invoice->get_country();
$customer_id = $invoice->get_customer_id();
Depending on the payment gateway you're building, you might either:-
Process the payment immediately, mark the invoice as paid, then redirect to the success page, ...
// Process the payment here.

// If successfuly, mark the invoice as paid...
$invoice->mark_paid();

// ... then send to the success page.
wpinv_send_to_success_page( array( 'invoice_key' => $invoice->get_key() ) );
... put the invoice on hold then redirect to the receipt page where you'll then display offline payment instructions...
// Mark the invoice as held...
$invoice->set_status( 'wpi-onhold' );

// Add note.
$invoice->add_note( __( 'Mark the invoice as paid when you receive offline payment', 'my-domain' ), false, false, true );

// ... then save it...
$invoice->save();

// ... and redirect to the receipt page.
wpinv_send_to_success_page( array( 'invoice_key' => $invoice->get_key() ) );
or redirect it to your payment processor.
wp_redirect( 'https://my-payment-processor.com/process' );

verify_ipn()

This method is called when we receive an IPN request for your gateway. You can use it to process the request and process the invoice/subscription as needed.

Here are a few snippets that might be useful when it comes to IPNs:-

Getting an invoice object:-

$invoice = new WPInv_Invoice( $_POST['invoice_id'] );

if ( $invoice->exists() ) {
    // Process IPN.
}

Getting your gateway's IPN URL:-

$ipn_url = wpinv_get_ipn_url( $this->id );

Working with subscriptions

If your payment gateway supports subscriptions, add it to the list of supported features. You can then use the following code snippets to work with subscriptions.

Checking if an invoice has an associated subscription:-

if ( $invoice->is_recurring() && $subscription = wpinv_get_subscription( $invoice ) ) {
  
    $period                 = $subscription->get_period();
    $interval               = (int) $subscription->get_frequency();
    $max_bill_times         = (int) $subscription->get_bill_times();
    $initial_amount         = (float) wpinv_sanitize_amount( $invoice->get_initial_total(), 2 );
    $recurring_amount       = (float) wpinv_sanitize_amount( $invoice->get_recurring_total(), 2 );
    $subscription_item      = $invoice->get_recurring( true );

    // Process the subscription here.
}

Activating an invoice's subscription:-

$duration = strtotime( $subscription->get_expiration() ) - strtotime( $subscription->get_date_created() );
$expiry   = date( 'Y-m-d H:i:s', ( current_time( 'timestamp' ) + $duration ) );

$subscription->set_next_renewal_date( $expiry );
$subscription->set_date_created( current_time( 'mysql' ) );
$subscription->set_profile_id( /*THE REMOTE ID OF THE SUBSCRIPTION*/ );
$subscription->activate();

Renewing an invoice's subscription:-

// If this is the last renewal, complete the subscription.
if ( $subscription->is_last_renewal() ) {
    return $subscription->complete();
}

// Renew the subscription.
$subscription->add_payment(
   array(
      'transaction_id' => /*THE REMOTE ID OF THE RENEWAL PAYMENT*/,
       'gateway'       => $this->id
   )
);

$subscription->renew();

Still need help? Contact Us Contact Us