Woocommerce is one of the leading e-commerce platforms. Woocommerce supports multiple Payment Gateways by default but you can also create a plugin for payment gateway on your own. In this article, we will be discussing how to create a payment gateway plugin for Woocommerce. Following are the steps to create a payment gateway plugin:
Create a Plugin
There can be two ways of creating a plugin in WordPress. Fill in the information like Plugin Name, Plugin URL, Description, Version, Author, Author URL. etc. Either you can create just one file for starters or you can use WordPress Plugin Boilerplate Generator.
Upload it to directory /wp-content/plugins/ and you will see the plugin appearing in your admin area. You can activate it from here.
Extend WC_Payment _Gateway
Woocommerce provide us multiple core classes like WC_Payment_Gateway which are extendable to add custom functionality. Payment gateways are php classes. For custom payment functionality, we will have to extend the default WooCommerce class WC_Payment_Gateway with our custom class WC_MyApp_Gateway to gain the functionality associated with WC_Payment_Gateway. Our class will have the following functions:
- constructor()
- init_form_fields()
- payment_fields()
- validate_fields()
- process_payment()
All the business logic will be done in this WC_MyApp_Gateway. Following code shows us the plugin custom class structure.
class WC_MyApp_Gateway extends WC_Payment_Gateway { public function __construct() { } public function init_form_fields(){ } public function payment_fields() { } public function payment_scripts() { } public function validate_fields() { } public function process_payment( $order_id ) { } public function webhook() { } } }
Create Plugin Options
Let’s assume that we are creating a payment gateway plugin, which redirects the user to the Payments gateway’s website and redirects to the success or failure page after the payment is done. And for the backend creates a webhook to receive the status of the payment via a callback. We are going to make a plugin which supports particular countries and currencies. For this purpose, we will have to declare the countries we want to support and endpoint URLs in order to determine the success or failure of payments:
private $allowedCurrencies = array( 'SEK' ,'EUR' ,'NOK' ,'USD' ,'CLP' ); private $SUCCESS_CALLBACK_URL = "myApp_payment_success"; private $FAILURE_CALLBACK_URL = "smyApp_payment_failure"; private $SUCCESS_REDIRECT_URL = "/checkout/order-received/"; private $FAILURE_REDIRECT_URL = "/checkout/order-received/"; private $API_HOST = " "; private $API_SESSION_CREATE_ENDPOINT = "/checkout/v1/session/create";
In the constructor of the class WC_MyApp_Gateway, we will do the following:
- Define Class Properties
- Initialize Plugin Settings
- Append Options to Properties
- Save Options
- Register Callbacks
1. Define Class Properties
In class Constructor, we will define class properties. These properties include ‘id’, an ‘icon’ to show at the checkout page, ‘Method title’ and ‘Method Description’. These properties will show at options page and checkout page.
$this->id = ‘MyApp’; // payment gateway plugin ID $this->icon =” "; // URL of icon that will be displayed on the checkout page $this->has_fields = true; $this->method_title = ‘MyApp Payment Gateway Plugin'; $this->method_description = 'MyApp Payment Gateway Plugin.'; //displayed on option page $this->supports = array( 'products' );
2. Initialize Plugin Settings
When Class properties are defined, the second step is to initialize form fields. For this purpose, we will use init_form_fields() function.
// Method with all the options fields $this->init_form_fields();
Depending on the payment process, the plugin may have different form fields. We will use
- Enable / Disable
- Title
- Description
- Test Mode
- Test MerchantID
- Test Auth Token
- Live MerchantID
- Live Auth Token
- Country
public function init_form_fields() { $this->form_fields = array( 'enabled' => array( 'title' => 'Enable/Disable', 'label' => 'Enable myApp Gateway', 'type' => 'checkbox', 'description' => '', 'default' => 'no' ), 'title' => array( 'title' => 'Title', 'type' => 'text', 'description' => 'This controls the title which the user sees during checkout.', 'default' => 'MyApp', 'desc_tip' => true, ), 'description' => array( 'title' => 'Description', 'type' => 'text', 'description' => 'This controls the description which the user sees during checkout.', 'desc_tip' => true, ), 'testmode' => array( 'title' => 'Test mode', 'label' => 'Enable Test Mode', 'type' => 'checkbox', 'description' => 'Place the payment gateway in test mode using test API keys.', 'default' => 'yes', 'desc_tip' => true, ), 'test_merchant_id' => array( 'title' => 'Test MerchantID', 'type' => 'text', 'placeholder' => 'Enter Test MerchantID' ), 'test_auth_token' => array( 'title' => 'Test Auth Token', 'type' => 'text', 'placeholder' => 'Enter Test Auth Token' ), 'merchant_id' => array( 'title' => 'Live MerchantID', 'type' => 'text', 'placeholder' => 'Enter Live MerchantID' ), 'auth_token' => array( 'title' => 'Live Auth Token', 'type' => 'text', 'placeholder' => 'Enter Live Auth Token' ), 'country_code' => array( 'type' => 'select', 'title' => 'Country', 'label' => 'Country', 'options' => array( '' => 'Select Country', 'SE' => 'Sweden', 'FI' => 'Finland', 'NO' => 'Norway', 'DE' => 'Germany', 'CL' => 'Chile', ), ) ) }
Our form field or options page will look like this:
3. Append Options to Properties
Once the form fields are initialized, we will append the field options to the properties we defined earlier in the constructor.
$this->title = $this->get_option( 'title' ); $this->description = $this->get_option( 'description' ); // Checking if valid to use if($this->is_valid_for_use()) { $this->enabled = $this->get_option( 'enabled' ); } else { $this->enabled = 'no'; } // Site URL $this->siteUrl = get_site_url(); $this->testmode = 'yes' === $this->get_option( 'testmode' ); $this->merchant_id = $this->testmode ? $this->get_option( 'test_merchant_id' ) : $this->get_option( 'merchant_id' ); $this->auth_token = $this->testmode ? $this->get_option( 'test_auth_token' ) : $this->get_option( 'auth_token' ); $this->country_code = $this->get_option( 'country_code' );
4. Save Options
After appending the options availed from form fields to the properties, now we will save the options using action hook:
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
5. Register Callbacks
Now we will register the callback hooks which we will use to receive the payment response from the gateway.
add_action( 'woocommerce_api_'. $this->SUCCESS_CALLBACK_URL, array( $this, 'payment_success')); add_action( 'woocommerce_api_' . $this->FAILURE_CALLBACK_URL, array( $this, 'payment_failure'));
After we have done this, the endpoints created for the above-created callbacks will look like this:
$this->siteUrl . "//wc-api/" . {SUCCESS_CALLBACK_URL} $this->siteUrl . "//wc-api/" . {FAILURE_CALLBACK_URL}
Our complete constructor will look like this:
$this->id = ‘MyApp’; // payment gateway plugin ID $this->icon =” "; // URL of icon that will be displayed on the checkout page $this->has_fields = true; $this->method_title = ‘MyApp Payment Gateway Plugin'; $this->method_description = 'MyApp Payment Gateway Plugin.'; //displayed on option page $this->supports = array( 'products' ); // Method with all the options fields $this->init_form_fields(); // Load the settings. $this->init_settings(); $this->title = $this->get_option( 'title' ); $this->description = $this->get_option( 'description' ); // Checking if valid to use if($this->is_valid_for_use()) { $this->enabled = $this->get_option( 'enabled' ); } else { $this->enabled = 'no'; } $this->testmode = 'yes' === $this->get_option( 'testmode' ); $this->merchant_id = $this->testmode ? $this->get_option( 'test_merchant_id' ) : $this->get_option( 'merchant_id' ); $this->auth_token = $this->testmode ? $this->get_option( 'test_auth_token' ) : $this->get_option( 'auth_token' ); $this->country_code = $this->get_option( 'country_code' ); // Site URL $this->siteUrl = get_site_url(); // This action hook saves the settings add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); // Callback Actions add_action( 'woocommerce_api_'. $this->SUCCESS_CALLBACK_URL, array( $this, 'payment_success')); add_action( 'woocommerce_api_' . $this->FAILURE_CALLBACK_URL, array( $this, 'payment_failure'));
Field Validations
In our case, we will be allowing only five countries and their respective currencies for payments. So, we will have to validate Country and Currency Fields to move further or show an error on the admin page. We can do this while using WooCommerce hooks like get_woocommerce_currency(), validate_country_code_field().
Validate Currency
“admin_options” method is called before the settings page is loaded. In this method, we will check if the selected currency is supported by our plugin or not. We can get store currency by using get_woocommerce_currency() and compare it with the currencies we allowed and stored in $allowedCurrencies.
function is_valid_for_use () { return in_array(get_woocommerce_currency(), $this->allowedCurrencies); } function admin_options() { if ( $this->is_valid_for_use() ) { parent::admin_options(); } else { ?> <div class="notice error is-dismissible" > <p><?php _e( 'MyApp Does not support the selected currency ' . get_woocommerce_currency() . '!', 'my-text-domain' ); ?></p> </div> <?php } }
Validate Form Field
Validating the form fields before storing is a very common use case that every plugin developer has to implement. To achieve this woocommerce has provided a specific way to validate the individual fields. We have to create a method with “validate_” prefix and “_field” postfix to the field name you want to validate. validate_{field_name}_field();
We will allow our payment gateway plugin in limited countries. To achieve this, we will have to perform a couple of checks in order to confirm that the store country is supported by our plugin.
public function validate_country_code_field( $key, $value){ if( $this->validate_currency_with_country($value) ){ return $value; } else{ ?> <div class="notice error is-dismissible" > <p><?php _e( 'MyApp does not support ' . get_woocommerce_currency() . ' for the selected country! ' . $this->validate_currency_with_country($value), 'my-text-domain' ); ?></p> </div> <?php } }
We will use validate_currency_with_country(); to validate if the store currency is supported by the country.
private function validate_currency_with_country ($value) { $status = false; switch($value){ case "CL": $status = get_woocommerce_currency() == 'CLP'; break; case "DE": $status = get_woocommerce_currency() == 'EUR'; break; case "SE": $status = get_woocommerce_currency() == 'SEK'; break; case "NO": $status = get_woocommerce_currency() == 'NOK'; break; case "FI": $status = get_woocommerce_currency() == 'EUR'; break; } return $status;
Payment Process
Once we have validated all the fields and plugin compatibility with Woocommerce, we will have to create a session for payment platform and redirect the user to that platform. In this session, we will send complete information of the order, including order_id, amount, currency, user_id. process_payment($order_id); is called when a user clicks on Places an order on Checkout Page. We wil override this in our plugin and get the result of success and redirect in an array.
public function process_payment( $order_id ) { global $woocommerce; //To receive order id $order = wc_get_order( $order_id ); //To receive order amount $amount = $order->get_total(); //To receive woocommerce Currency $currency = get_woocommerce_currency(); //To receive user id and order details $merchantCustomerId = $order->get_user_id(); $merchantOrderId = $order->get_order_number(); $orderIdString = '?orderId=' . $order_id; $transaction = array( "amount" => $amount, "currency" => $currency, ); $transactions = array( $transaction ); //Create a session and send it to Payment platform while handling errors $requestBody = array( 'country' => $this->country_code, 'merchantId' => $this->merchant_id, 'transactions' => $transactions, "redirectOnSuccessUrl" => $this->siteUrl . $this->SUCCESS_REDIRECT_URL . $orderIdString, "redirectOnFailureUrl" => $this->siteUrl . $this->FAILURE_REDIRECT_URL . $orderIdString, "callbackOnSuccessUrl" => $this->siteUrl . "//wc-api/" . $this->SUCCESS_CALLBACK_URL . $orderIdString, "callbackOnFailureUrl" => $this->siteUrl . "//wc-api/" . $this->FAILURE_CALLBACK_URL . $orderIdString, "redirectTarget" => "TOP", "merchantCustomerId" => $merchantCustomerId, "merchantOrderId" => $merchantOrderId, ); $header = array( 'Authorization' => $this->auth_token, 'Content-Type' => 'application/json' ); $args = array( 'method' => 'POST', 'headers' => $header, 'body' => json_encode($requestBody), ); $apiUrl = $this->api_host . $this->API_SESSION_CREATE_ENDPOINT; $response = wp_remote_post( $apiUrl, $args ); if( !is_wp_error( $response ) ) { $body = json_decode( $response['body'], true ); if ( $body['status'] == 'OK' ) { $sessionId = $body['payload']['sessionId']; $url = $body['payload']['url']; $order->update_meta_data( 'myApp_session_id', $sessionId ); $session_note = "MyApp SessionID: " . $sessionId; $order->add_order_note( $session_note ); update_post_meta( $order_id, '_session_id', $sessionId ); $order->update_status( 'processing'); return array( 'result' => 'success', 'redirect' => $url ); } else { wc_add_notice( 'Please try again', 'error' ); return; } } else { wc_add_notice( 'Connection error.', 'error' ); return; } }
In order to get the response from the payment platform, we will define call back functions which return the results either the transaction was successful or not. The call back functions defined in the constructor will trigger the webhooks to return the result.
Success Response Callback
payment_success() function is called to get the success response from Payment Gateway Platform. Data is fetched in a file. To make this data usable, we will store the data in a variable by using file_get_content(); This response is in encoded form, we will decode response using json_decode(); and store it in a variable. Now we have complete order information, which can be used to update the metadata.
public function payment_success() { // Getting POST data $postData = file_get_contents( 'php://input' ); $response = json_decode( $postData ); $orderId = $_GET['orderId']; $order = wc_get_order( $orderId ); if ($order && $response) { $order->update_meta_data( 'myApp_callback_payload', $postData ); if ( $response->event === 'CHECKOUT_SUCCEEDED' ) { $order->update_meta_data( 'myApp_event', $response->event ); if ($response->payload->reservations && $response->payload->reservations[0] && $response->payload->reservations[0]->reservationId) { $order->update_meta_data( 'myApp_reservation_id', $response->payload->reservations[0]->reservationId ); $reservation_note = "MyApp ReservationID: " . $response->payload->reservations[0]->reservationId; $order->add_order_note( $reservation_note ); update_post_meta( $orderId, '_myApp_reservation_id', $response->payload->reservations[0]->reservationId ); } $order->update_status( 'completed'); $order->payment_complete(); $order->reduce_order_stock(); } else { $order->update_meta_data( 'myApp_event', $response->event ); if ($response->payload->reservations && $response->payload->reservations[0] && $response->payload->reservations[0]->reservationId) { $order->update_meta_data( 'myApp_reservation_id', $response->payload->reservations[0]->reservationId ); } $order->update_status( 'failed'); } } }}
Failure Response Callback
payment_failure() function is called to get the success response from Payment Gateway Platform. Data is fetched in a file. To make this data usable, we will store the data in a variable by using file_get_content(); This response is in encoded form, we will decode response using json_decode(); and store it in a variable. Now we have complete order information, which can be used to update the metadata.
public function payment_failure() { // Getting POST data $postData = file_get_contents( 'php://input' ); $response = json_decode( $postData ); $orderId = $_GET['orderId']; $order = wc_get_order( $orderId ); if ($order && $response) { $order->update_meta_data( 'myApp_callback_payload', $postData ); $order->update_meta_data( 'myApp_event', $response->event ); if ($response->payload->reservations && $response->payload->reservations[0] && $response->payload->reservations[0]->reservationId) { $order->update_meta_data( 'myApp_reservation_id', $response->payload->reservations[0]->reservationId ); } $order->update_status( 'failed'); } }
Last Say!
Woocommerce is an extensively used eCommerce platform. You can find many extensions developed by the WordPress community members at different WordPress forums but time can come in a developers life, where he will have to develop some custom functionality in order to meet the needs of a project.
WP inCare always strives to provide you all the necessary updates to move ahead from your competition and grab the opportunity.Click To TweetPlugin development can be a difficult task to do especially if you are new to the development. Hopefully, this woocommerce payment gateway plugin tutorial will help you to achieve your goal. If you want to develop a WordPress Plugin and you are not experienced enough there is no need of worry WE ARE HERE!. We are experienced in WordPress Developer if you want to develop any WordPress plugin Contact us now!
WordPress Updates
Security Checks
Daily Cloud Backups
Speed Optimization
Premium Plugins
Developer Consultation
6 thoughts on “How to Create Payment Gateway for Woocommerce?”
I have a payment API and I want to create a woocommerce payment gateway. I need help.
My problem is how can I redirect customer on my gateway payment interface
Hi,
For this, you will need to create a hook on checkout process. Which will create a session on your API and then you can redirect user to the returned session URL and perform an HTTP request using POST method. You can use wp_remote_post for this.
In case you need any kind of help in development, drop us an email at: support@wpincare.com
Hi, does the callback function trigger the thank you page on success? If so, can you you tell me which line of code does that please.
Hi,
The callback function determines whether the process is successful or failed. It updates the meta data like order status, payment status, and stock according to the response from the API.
If you have any query or need any assistance from our side you can drop an email at support@wpincare.com
Hi,
How can I create a plugin without using a token?
My bank just provides me a URL to connect to the payment gateway page and they currently don’t support token.[token == false]
and also how can I make it encrypt using the encryption provided by the bank.
Hi,
Seems like you will have to redirect to gateway’s URL and perform necessities there. We have already covered this part. If you have any query or need any assistance from our side you can drop an email at support@wpincare.com