Adding A Custom Woocommerce Payment Gateway Connection

WooCommerce Docs

Documentation, Reference Materials, and Tutorials for your WooCommerce products

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 that then redirects them to the payment processor on the gateway’s own website. Example: PayPal standard, Authorize.net DPM
  2. iFrame based– This is when the gateway 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, Authorize.net AIM
  4. Offline– No online payment is made. Example: Cheque, Bank Transfer

Form and iFrame based gateways post data offsite, 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 need to create a class after plugins are loaded. Example:

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

As well as defining your class, you need to also tell WooCommerce (WC) that it exists. Do this by filtering woocommerce_payment_gateways:

Required Methods ↑ Back to top

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

__construct()
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 that are then loaded with init_settings() .

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

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

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

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

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, and this is done with a returned array.

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

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, then you can complete the order here instead. Rather than using update_status when an order is paid, you should use payment_complete:

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

If payment fails, you should throw an error and return null:

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

Updating order status and adding notes ↑ Back to top

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:

The above example updates the status to On-Hold and adds a note informing the owner that it is awaiting a Cheque. You can add notes without updating the order status; this is used for adding a debug message:

Order status best practice ↑ Back to top

  • If the order has completed but the admin needs to manually verify payment, use On-Hold
  • If the order fails and has already been created, set to Failed
  • If payment is complete, let WooCommerce handle the status and use $order->payment_complete() . WooCommerce will use either Completedor Processingstatus and handle stock.

Notes on Direct Gateways ↑ Back to top

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

This tells the checkout to output a ‘payment_box’ containing your direct payment form that you define next.

Create a method called payment_fields() – this contains your form, most likely to have credit card details.

The next but optional method to 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 and display it to the user.

Finally, you need to add payment code inside your process_payment( $order_id ) method. This takes the posted form data and attempts payment directly via the payment provider.

If payment fails, you should output an error and return nothing:

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

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

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

The best way to add a callback and callback handler is to use WC-API hooks. An example would be as PayPal Standard does. It sets the callback/IPN URL as:

Then hooks in its handler to the hook:

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

Hooks in Gateways ↑ Back to top

It’s important to note that adding hooks inside gateway classes may not trigger. Gateways are only loaded when needed, such as 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.

Create a Payment Gateway Plugin for WooCommerce

I gonna guide your through all the steps that are required when you create a custom payment gateway plugin for Woo.

Step 1. We begin with creating a plugin #

When I first heard about plugins for WordPress I thought it is so hard to create one. But actually, to create a plugin you just need to create a file and add a couple lines of code inside it.

So, in the plugins folder I created misha-gateway.php file and added the following code there. In case your plugin will have more than one file, place it in the folder with the same name, example: misha-gateway/misha-gateway.php .

Once you did it, the plugin will appear in your admin area! And you can even activate it.

Step 2. Payment Gateways are PHP classes. Here is the class skeleton. #

Every class method is described below. You can begin with copying and pasting the below code into your main plugin file.

If you inserted the code above “as is” in your plugin file, you get 500 error, because this code just shows the plugin class structure, where each method should be.

Step 3. Payment Gateway Plugin Options #

In the class constructor we:

  • Define class properties, like gateway ID and name, lines 23-33,
  • Initialize the settings, lines 35-39,
  • Append options to class properties, lines 40-45,
  • Save options, line 48,
  • Enqueue custom JavaScript and CSS if needed, line 51.

We can also register payment gateway webhooks in class constructor (example on line 54).

Depending on the payment processor you use, the option fields could be different, but in most cases you will have “Enabled/Disabled”, “Title”, “Description” and “Test mode” options.

If you’ve done everything correctly, your options page should like like this:

Step 4. Direct Checkout Form #

Before implementing the code below, please read these key points:

  • If you’re creating a payment gateway like PayPal, where all the user actions happen on the payment gateway website, you can skip this step, just do not add payment_fields() and validate_fields() methods and continue to Step 5.
  • In this tutorial I assume that you use a payment processor that sends card data with its own AJAX-request and gives you a token that you can use in PHP, so do not (!) add name attributes to the card form fields. This is how it works by step:
    1. Customer fills his card data and clicks “Place Order” button.
    2. We delay the form submission using checkout_place_order event in WooCommerce and send AJAX request with card data directly to our payment processor,
    3. If customer details are OK, the processor returns a token and we add it to our form below,
    4. Now we can submit the form (in JS of course),
    5. We use the token in PHP to capture a payment via payment processor’s API.

    4.1 Enqueue scripts

    In step 2 we’ve already added wp_enqueue_scripts action hook and connect payment_scripts method to it.

    4.2 Obtain a token in JavaScript

    Before all I want to say that for every payment processor this code could be different, but the main idea is the same. Here is the content for your misha.js file:

    4.3 Form with card data

    With payment_fields() class method you can create a payment form with card fields like this:

    Below is the code:

    Step 5. Process payments #

    5.1 Validate fields

    I know that checkout fields like First name are validated before, but this is just an example:

    5.2 Capture payments with API and set the order status

    Prepare for a lot of text 🙃

    • Once you get the order object with wc_get_order() function, you can use its methods like get_billing_first_name() , get_billing_country() , get_billing_address_1() etc to get the customer billing and shipping details (by the way you can find all the methods in includes/class-wc-order.php which is in WooCommerce plugin folder). You can also get the billing details from $_POST array, at the moment of writing this tutorial I’m not sure what is better.
    • You can add notes to the order with $order->add_order_note() method, it can be notes to customer (will be displayed in member’s area) and private notes (only on edit order pages).
      Order notes on Edit Order pages
    • In this tutorial we consider using direct payments without going to gateway websites. But if for your purposes customers must go to a payment gateway website to complete their payment, you have to skip Step 4 and in this step instead capturing the payments with wp_remote_post() , use add_query_arg() to build a correct redirect URL to your payment gateway checkout page.
    • Use $order->get_total() to receive the order amount.
    • get_woocommerce_currency() should help you to get current shop currency.
    • If your payment gateway asks to list all the products in a order, use $order->get_items() , some examples you can find here.

    5.3 In case you need a Payment Gateway Callback (Instant Payment Notifications, Webhooks etc)

    Let’s say that our custom payment gateway doesn’t have its own form for the card data, and once the customer completed his billing details (like name, address etc) he will be redirected to a payment gateway website.

    How can we check if payment is completed and display it in our store?

    Manually? Huh, serious? 😐

    Many payment gateways have payment notifications and this is how it works — once a customer completed an order on a payment gateway website, the gateway sends a request with $_GET parameters to a specific URL of our website that we set on the gateway’s settings page. And WooCommerce allows to process these requests.

    The webshook URLs (callback URLs) in Woo look like this: http://rudrastyh.com/wc-api// , the hook name could be near anything, example paypal-payment-complete or just misha . It absolutely doesn’t mean what you will use here, the main requirement is thatin the URL andin the filter (Step 3, line 54) must match.

    And webhook() is the function (class method) that can do anything with $_GET parameters received.

    You do not have to add exit; at the end because it exits WordPress anyway once the code inside it is fired.

    Passionate about WordPress and snowboarding, creating websites for over 10 years! Let’s work together — just contact me.

    If you are a developer too, subscribe to my facebook page.

    Add custom payment gateway

    This tutorial is mostly targeted at developers as a bit programming knowledge is required to add a new gateway. It works with all gateways that use a form (mostly appears as button) submit to get the information and process the payment with the guest from there on.
    It only works with easyReservations 3.3 and above.

    Basic setup

    To start we create a new wordpress plugin by going in the folder /wp-content/plugins/ and creating a new folder with any name.
    Then create a new file named like the folder with the extension .php. In this tutorial it will be example and example.php.
    Open it with your editor and copy the standard plugin header from the wordpress codex.
    You can change the values, but they only matter to find and activate it in the plugins list later on.

    Register the gateway

    To start we register our new gateway. Only a few informations are required for it.

    The keyof the array, in the example my_gateway, is only a identifier and wont be used later on. The nameis only used if you activate multiple gateways to choose from. In form_nameand amount_nameenter the html names of the payment form and the name of the amount (price) field in it. You’ll see them later in the tutorial.

    If you want to add options to the settings you have to enter the options name to the array with the key “options”.

    Generate payment form

    Next is to generate the payment form. You’ll need some informations like the name and format of the fields and the URL to post the form to from the documentation of the gateway and an image for the payment button.

    After replacing the URLs and correctly naming and adding the required fields your done with the basic implementation.
    On this point it is fully usable. Your guest can pay and you get the money, but the reservation wont get updated in easyreservations.
    No matter if you want to proceed or that’s enough, this is a good point to test everything and get the last errors out.

    IPN (Instant Payment Notification)

    To get the reservations updating their price and payment status, as well as use the automatically approval function, you’ll need to write an IPN script. It verifies that the payment has been made before calling the payment callback function. As the way of verification is very different an example is senseless, but in the folder /lib/modules/paypal/ you can find all IPN scripts of the existing gateways. In them you can find four different ways so it should cover the most. The documentation of the gateway should also have an example of it.
    Create a new file in the same folder, insert the payment verification and let it call the following function if it’s correct:

    Where invoice is the same as sent to the gateway and amount is the amount paid.
    Don’t forget to enter the URL to your IPN script to the payment forms generation.

    If you want to add a options panel to the settings there’a an action to insert it on the right spot:

    The option to activate it should be saved as “modus”. Use the wordpress options to save them and don’t forget to add it’s name to the gateway registration array with the key “options”.

    Leave a Reply

    Your email address will not be published. Required fields are marked *