Chat with us, powered by LiveChat

This website uses cookies

Our website, platform and/or any sub domains use cookies to understand how you use our services, and to improve both your experience and our marketing relevance.

How to Build a WooCommerce Payment Gateway Plugin

May 9, 2017

9 Min Read
gateway banner
Reading Time: 9 minutes

The good thing about creating a WooCommerce payment extension is that the process is very simple. The most important challenge is the interaction with a merchant’s API for submission of payment requests.

For the purpose of this article, I will use Authorize.net. If you do not have one, signup for a sandbox account to test the plugin.

Sandbox Account

The sandbox is a functional payment gateway with two important differences – No actual credit cards are processed and specific errors and responses could be triggered on demand to test various situations.

API Credentials

Structure of the WooCommerce Payment Plugin

To make things easy to handle during the development and testing process, I will split the plugin into two files. These two files will be located in the cloudways-authorize-woocommerce-gateway directory (in the Plugin directory).  The first file registers the payment gateway and custom action link (cloudways-authorize-woocommerce-gateway.php). The second file will have the class that will create administration fields (cloudways-authorize-woocommerce.php).

Development of Plugin

Open up the file cloudways-authorize-woocommerce-gateway.php and add the following code to it:

/*
Plugin Name: Authorize.net AIM - Cloudways WooCommerce Payment Gateway
Plugin URI: http://www.cloudways.com/
Description: WooCommerce custom payment gateway integration on cloudways.
Version: 1.0
*/

add_action( 'plugins_loaded', 'cwoa_authorizenet_aim_init', 0 );
function cwoa_authorizenet_aim_init() {
    //if condition use to do nothin while WooCommerce is not installed
	if ( ! class_exists( 'WC_Payment_Gateway' ) ) return;
	include_once( 'cloudways-authorize-woocommerce.php' );
	// class add it too WooCommerce
	add_filter( 'woocommerce_payment_gateways', 'cwoa_add_authorizenet_aim_gateway' );
	function cwoa_add_authorizenet_aim_gateway( $methods ) {
		$methods[] = 'cwoa_AuthorizeNet_AIM';
		return $methods;
	}
}
// Add custom action links
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'cwoa_authorizenet_aim_action_links' );
function cwoa_authorizenet_aim_action_links( $links ) {
	$plugin_links = array(
		'<a href="' . admin_url( 'admin.php?page=wc-settings&tab=checkout' ) . '">' . __( 'Settings', 'cwoa-authorizenet-aim' ) . '</a>',
	);
	return array_merge( $plugin_links, $links );
}

Class Constructor

  • id — This is the global ID for the Payment method.
  • method_title — This is the title that appears on the top of the payment gateways Page.
  • method_description — This is the description of the payment gateway.
  • title — This is the title to be used for the vertical tabs.
  • icon — This is the optional image that appears with the gateway’s name on the front-end.
  • has_fields — This is a boolean option that could be set to ‘true’ if you want payment fields to show on the checkout.
  • supports — This indicates that the method supports the default credit card form.
<?php

class cwoa_AuthorizeNet_AIM extends WC_Payment_Gateway {

	function __construct() {

		// global ID
		$this->id = "cwoa_authorizenet_aim";

		// Show Title
		$this->method_title = __( "Authorize.net AIM", 'cwoa-authorizenet-aim' );

		// Show Description
		$this->method_description = __( "Authorize.net AIM Payment Gateway Plug-in for WooCommerce", 'cwoa-authorizenet-aim' );

		// vertical tab title
		$this->title = __( "Authorize.net AIM", 'cwoa-authorizenet-aim' );


		$this->icon = null;

		$this->has_fields = true;

		// support default form with credit card
		$this->supports = array( 'default_credit_card_form' );

		// setting defines
		$this->init_form_fields();

		// load time variable setting
		$this->init_settings();
		
		// Turn these settings into variables we can use
		foreach ( $this->settings as $setting_key => $value ) {
			$this->$setting_key = $value;
		}
		
		// further check of SSL if you want
		add_action( 'admin_notices', array( $this,	'do_ssl_check' ) );
		
		// Save settings
		if ( is_admin() ) {
			add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
		}		
	} // Here is the  End __construct()

	// administration fields for specific Gateway
	public function init_form_fields() {
		$this->form_fields = array(
			'enabled' => array(
				'title'		=> __( 'Enable / Disable', 'cwoa-authorizenet-aim' ),
				'label'		=> __( 'Enable this payment gateway', 'cwoa-authorizenet-aim' ),
				'type'		=> 'checkbox',
				'default'	=> 'no',
			),
			'title' => array(
				'title'		=> __( 'Title', 'cwoa-authorizenet-aim' ),
				'type'		=> 'text',
				'desc_tip'	=> __( 'Payment title of checkout process.', 'cwoa-authorizenet-aim' ),
				'default'	=> __( 'Credit card', 'cwoa-authorizenet-aim' ),
			),
			'description' => array(
				'title'		=> __( 'Description', 'cwoa-authorizenet-aim' ),
				'type'		=> 'textarea',
				'desc_tip'	=> __( 'Payment title of checkout process.', 'cwoa-authorizenet-aim' ),
				'default'	=> __( 'Successfully payment through credit card.', 'cwoa-authorizenet-aim' ),
				'css'		=> 'max-width:450px;'
			),
			'api_login' => array(
				'title'		=> __( 'Authorize.net API Login', 'cwoa-authorizenet-aim' ),
				'type'		=> 'text',
				'desc_tip'	=> __( 'This is the API Login provided by Authorize.net when you signed up for an account.', 'cwoa-authorizenet-aim' ),
			),
			'trans_key' => array(
				'title'		=> __( 'Authorize.net Transaction Key', 'cwoa-authorizenet-aim' ),
				'type'		=> 'password',
				'desc_tip'	=> __( 'This is the Transaction Key provided by Authorize.net when you signed up for an account.', 'cwoa-authorizenet-aim' ),
			),
			'environment' => array(
				'title'		=> __( 'Authorize.net Test Mode', 'cwoa-authorizenet-aim' ),
				'label'		=> __( 'Enable Test Mode', 'cwoa-authorizenet-aim' ),
				'type'		=> 'checkbox',
				'description' => __( 'This is the test mode of gateway.', 'cwoa-authorizenet-aim' ),
				'default'	=> 'no',
			)
		);		
	}
	
	// Response handled for payment gateway
	public function process_payment( $order_id ) {
		global $woocommerce;

		$customer_order = new WC_Order( $order_id );
		
		// checking for transiction
		$environment = ( $this->environment == "yes" ) ? 'TRUE' : 'FALSE';

		// Decide which URL to post to
		$environment_url = ( "FALSE" == $environment ) 
                               ? 'https://secure.authorize.net/gateway/transact.dll'
						   : 'https://test.authorize.net/gateway/transact.dll';

		// This is where the fun stuff begins
		$payload = array(
			// Authorize.net Credentials and API Info
			"x_tran_key"           	=> $this->trans_key,
			"x_login"              	=> $this->api_login,
			"x_version"            	=> "3.1",
			
			// Order total
			"x_amount"             	=> $customer_order->order_total,
			
			// Credit Card Information
			"x_card_num"           	=> str_replace( array(' ', '-' ), '', $_POST['cwoa_authorizenet_aim-card-number'] ),
			"x_card_code"          	=> ( isset( $_POST['cwoa_authorizenet_aim-card-cvc'] ) ) ? $_POST['cwoa_authorizenet_aim-card-cvc'] : '',
			"x_exp_date"           	=> str_replace( array( '/', ' '), '', $_POST['cwoa_authorizenet_aim-card-expiry'] ),
			
			"x_type"               	=> 'AUTH_CAPTURE',
			"x_invoice_num"        	=> str_replace( "#", "", $customer_order->get_order_number() ),
			"x_test_request"       	=> $environment,
			"x_delim_char"         	=> '|',
			"x_encap_char"         	=> '',
			"x_delim_data"         	=> "TRUE",
			"x_relay_response"     	=> "FALSE",
			"x_method"             	=> "CC",
			
			// Billing Information
			"x_first_name"         	=> $customer_order->billing_first_name,
			"x_last_name"          	=> $customer_order->billing_last_name,
			"x_address"            	=> $customer_order->billing_address_1,
			"x_city"              	=> $customer_order->billing_city,
			"x_state"              	=> $customer_order->billing_state,
			"x_zip"                	=> $customer_order->billing_postcode,
			"x_country"            	=> $customer_order->billing_country,
			"x_phone"              	=> $customer_order->billing_phone,
			"x_email"              	=> $customer_order->billing_email,
			
			// Shipping Information
			"x_ship_to_first_name" 	=> $customer_order->shipping_first_name,
			"x_ship_to_last_name"  	=> $customer_order->shipping_last_name,
			"x_ship_to_company"    	=> $customer_order->shipping_company,
			"x_ship_to_address"    	=> $customer_order->shipping_address_1,
			"x_ship_to_city"       	=> $customer_order->shipping_city,
			"x_ship_to_country"    	=> $customer_order->shipping_country,
			"x_ship_to_state"      	=> $customer_order->shipping_state,
			"x_ship_to_zip"        	=> $customer_order->shipping_postcode,
			
			// information customer
			"x_cust_id"            	=> $customer_order->user_id,
			"x_customer_ip"        	=> $_SERVER['REMOTE_ADDR'],
			
		);
	
		// Send this payload to Authorize.net for processing
		$response = wp_remote_post( $environment_url, array(
			'method'    => 'POST',
			'body'      => http_build_query( $payload ),
			'timeout'   => 90,
			'sslverify' => false,
		) );

		if ( is_wp_error( $response ) ) 
			throw new Exception( __( 'There is issue for connectin payment gateway. Sorry for the inconvenience.', 'cwoa-authorizenet-aim' ) );

		if ( empty( $response['body'] ) )
			throw new Exception( __( 'Authorize.net\'s Response was not get any data.', 'cwoa-authorizenet-aim' ) );
			
		// get body response while get not error
		$response_body = wp_remote_retrieve_body( $response );

		foreach ( preg_split( "/\r?\n/", $response_body ) as $line ) {
			$resp = explode( "|", $line );
		}

		// values get
		$r['response_code']             = $resp[0];
		$r['response_sub_code']         = $resp[1];
		$r['response_reason_code']      = $resp[2];
		$r['response_reason_text']      = $resp[3];

		// 1 or 4 means the transaction was a success
		if ( ( $r['response_code'] == 1 ) || ( $r['response_code'] == 4 ) ) {
			// Payment successful
			$customer_order->add_order_note( __( 'Authorize.net complete payment.', 'cwoa-authorizenet-aim' ) );
												 
			// paid order marked
			$customer_order->payment_complete();

			// this is important part for empty cart
			$woocommerce->cart->empty_cart();

			// Redirect to thank you page
			return array(
				'result'   => 'success',
				'redirect' => $this->get_return_url( $customer_order ),
			);
		} else {
			//transiction fail
			wc_add_notice( $r['response_reason_text'], 'error' );
			$customer_order->add_order_note( 'Error: '. $r['response_reason_text'] );
		}

	}
	
	// Validate fields
	public function validate_fields() {
		return true;
	}

	public function do_ssl_check() {
		if( $this->enabled == "yes" ) {
			if( get_option( 'woocommerce_force_ssl_checkout' ) == "no" ) {
				echo "<div class=\"error\"><p>". sprintf( __( "<strong>%s</strong> is enabled and WooCommerce is not forcing the SSL certificate on your checkout page. Please ensure that you have a valid SSL certificate and that you are <a href=\"%s\">forcing the checkout pages to be secured.</a>" ), $this->method_title, admin_url( 'admin.php?page=wc-settings&tab=checkout' ) ) ."</p></div>";	
			}
		}		
	}

}

Insert the above code in cloudways-authorize-woocommerce.php

Looking for better performance and security?

Migrate your WooCommerce website to Cloudways at zero cost.

Activate the Plugin

Now that the plugin has been created, activate the plugin.

Make sure that there are no errors. Go to WooCommerce >> Settings. This will take you to the Checkout Administration options:

WooCommerce setting

At this point, it is a good practice to include an option to set the test mode of the gateway.

  • enabled — Enable/Disable this payment gateway.
  • title — Payment title that the customer will see during the checkout process.
  • description — Payment description that the customer will see during the checkout process.
  • api_login — API Login provided by Authorize.net when you signed up for an account.
  • trans_key — Transaction Key provided by Authorize.net when you signed up for an account.
  • environment — Place the payment gateway in test mode or production.
public function init_form_fields() {
		$this->form_fields = array(
			'enabled' => array(
				'title'		=> __( 'Enable / Disable', 'cwoa-authorizenet-aim' ),
				'label'		=> __( 'Enable this payment gateway', 'cwoa-authorizenet-aim' ),
				'type'		=> 'checkbox',
				'default'	=> 'no',
			),
			'title' => array(
				'title'		=> __( 'Title', 'cwoa-authorizenet-aim' ),
				'type'		=> 'text',
				'desc_tip'	=> __( 'Payment title of checkout process.', 'cwoa-authorizenet-aim' ),
				'default'	=> __( 'Credit card', 'cwoa-authorizenet-aim' ),
			),
			'description' => array(
				'title'		=> __( 'Description', 'cwoa-authorizenet-aim' ),
				'type'		=> 'textarea',
				'desc_tip'	=> __( 'Payment title of checkout process.', 'cwoa-authorizenet-aim' ),
				'default'	=> __( 'Successfully payment through credit card.', 'cwoa-authorizenet-aim' ),
				'css'		=> 'max-width:450px;'
			),
			'api_login' => array(
				'title'		=> __( 'Authorize.net API Login', 'cwoa-authorizenet-aim' ),
				'type'		=> 'text',
				'desc_tip'	=> __( 'This is the API Login provided by Authorize.net when you signed up for an account.', 'cwoa-authorizenet-aim' ),
			),
			'trans_key' => array(
				'title'		=> __( 'Authorize.net Transaction Key', 'cwoa-authorizenet-aim' ),
				'type'		=> 'password',
				'desc_tip'	=> __( 'This is the Transaction Key provided by Authorize.net when you signed up for an account.', 'cwoa-authorizenet-aim' ),
			),
			'environment' => array(
				'title'		=> __( 'Authorize.net Test Mode', 'cwoa-authorizenet-aim' ),
				'label'		=> __( 'Enable Test Mode', 'cwoa-authorizenet-aim' ),
				'type'		=> 'checkbox',
				'description' => __( 'This is the test mode of gateway.', 'cwoa-authorizenet-aim' ),
				'default'	=> 'no',
			)
		);		
	}

Save changes

Payment Processing Method

The payment processing is handled by the method process_payment($order_id ). The form will create the following default form fields ( obtained from $_POST):

  • GATEWAYID-card-number
  • GATEWAYID-card-cvc
  • GATEWAYID-card-expiry

Payment Processing Method

Next, I will build the function process_payment(). This function handles all the transactions:

public function process_payment( $order_id ) {
		global $woocommerce;

		$customer_order = new WC_Order( $order_id );
		
		// checking for transiction
		$environment = ( $this->environment == "yes" ) ? 'TRUE' : 'FALSE';

		// Decide which URL to post to
		$environment_url = ( "FALSE" == $environment ) 
                               ? 'https://secure.authorize.net/gateway/transact.dll'
						   : 'https://test.authorize.net/gateway/transact.dll';

		// This is where the fun stuff begins
		$payload = array(
			// Authorize.net Credentials and API Info
			"x_tran_key"           	=> $this->trans_key,
			"x_login"              	=> $this->api_login,
			"x_version"            	=> "3.1",
			
			// Order total
			"x_amount"             	=> $customer_order->order_total,
			
			// Credit Card Information
			"x_card_num"           	=> str_replace( array(' ', '-' ), '', $_POST['cwoa_authorizenet_aim-card-number'] ),
			"x_card_code"          	=> ( isset( $_POST['cwoa_authorizenet_aim-card-cvc'] ) ) ? $_POST['cwoa_authorizenet_aim-card-cvc'] : '',
			"x_exp_date"           	=> str_replace( array( '/', ' '), '', $_POST['cwoa_authorizenet_aim-card-expiry'] ),
			
			"x_type"               	=> 'AUTH_CAPTURE',
			"x_invoice_num"        	=> str_replace( "#", "", $customer_order->get_order_number() ),
			"x_test_request"       	=> $environment,
			"x_delim_char"         	=> '|',
			"x_encap_char"         	=> '',
			"x_delim_data"         	=> "TRUE",
			"x_relay_response"     	=> "FALSE",
			"x_method"             	=> "CC",
			
			// Billing Information
			"x_first_name"         	=> $customer_order->billing_first_name,
			"x_last_name"          	=> $customer_order->billing_last_name,
			"x_address"            	=> $customer_order->billing_address_1,
			"x_city"              	=> $customer_order->billing_city,
			"x_state"              	=> $customer_order->billing_state,
			"x_zip"                	=> $customer_order->billing_postcode,
			"x_country"            	=> $customer_order->billing_country,
			"x_phone"              	=> $customer_order->billing_phone,
			"x_email"              	=> $customer_order->billing_email,
			
			// Shipping Information
			"x_ship_to_first_name" 	=> $customer_order->shipping_first_name,
			"x_ship_to_last_name"  	=> $customer_order->shipping_last_name,
			"x_ship_to_company"    	=> $customer_order->shipping_company,
			"x_ship_to_address"    	=> $customer_order->shipping_address_1,
			"x_ship_to_city"       	=> $customer_order->shipping_city,
			"x_ship_to_country"    	=> $customer_order->shipping_country,
			"x_ship_to_state"      	=> $customer_order->shipping_state,
			"x_ship_to_zip"        	=> $customer_order->shipping_postcode,
			
			// information customer
			"x_cust_id"            	=> $customer_order->user_id,
			"x_customer_ip"        	=> $_SERVER['REMOTE_ADDR'],
			
		);
	
		// Send this payload to Authorize.net for processing
		$response = wp_remote_post( $environment_url, array(
			'method'    => 'POST',
			'body'      => http_build_query( $payload ),
			'timeout'   => 90,
			'sslverify' => false,
		) );

		if ( is_wp_error( $response ) ) 
			throw new Exception( __( 'There is issue for connectin payment gateway. Sorry for the inconvenience.', 'cwoa-authorizenet-aim' ) );

		if ( empty( $response['body'] ) )
			throw new Exception( __( 'Authorize.net\'s Response was not get any data.', 'cwoa-authorizenet-aim' ) );
			
		// get body response while get not error
		$response_body = wp_remote_retrieve_body( $response );

		foreach ( preg_split( "/\r?\n/", $response_body ) as $line ) {
			$resp = explode( "|", $line );
		}

		// values get
		$r['response_code']             = $resp[0];
		$r['response_sub_code']         = $resp[1];
		$r['response_reason_code']      = $resp[2];
		$r['response_reason_text']      = $resp[3];

		// 1 or 4 means the transaction was a success
		if ( ( $r['response_code'] == 1 ) || ( $r['response_code'] == 4 ) ) {
			// Payment successful
			$customer_order->add_order_note( __( 'Authorize.net complete payment.', 'cwoa-authorizenet-aim' ) );
												 
			// paid order marked
			$customer_order->payment_complete();

			// this is important part for empty cart
			$woocommerce->cart->empty_cart();

			// Redirect to thank you page
			return array(
				'result'   => 'success',
				'redirect' => $this->get_return_url( $customer_order ),
			);
		} else {
			//transaction fail
			wc_add_notice( $r['response_reason_text'], 'error' );
			$customer_order->add_order_note( 'Error: '. $r['response_reason_text'] );
		}

	}

Now test the value of response_code. If the transaction goes through, you will receive a message that signifies success. Here is how the order notes change throughout the process:

Wrapping up!

Creating the WooCommerce payment extension is not a huge project or a difficult project to tackle. It usually takes just a few hours to create the extension. However, testing is the key to success. this is where you should thoroughly test the code so that the WooCommerce store remains operational.

If you need more help, do leave a comment and I will get back to you.

Share your opinion in the comment section. COMMENT NOW

Share This Article

Your WooCommerce Store Needs A Reliable Host

With no compromise on Performance, Security & Support.

Owais Alam

is the WordPress Community Manager at Cloudways - A Managed WooCommerce Hosting Platform and a seasoned PHP developer. He loves to develop all sorts of websites on WordPress and is in love with WooCommerce in particular. You can email him at owais.alam@cloudways.com

Get Our Newsletter
Be the first to get the latest updates and tutorials.

Do you like what you read?

Get the Latest Updates

Share Your Feedback

Please insert Content

Thank you for your feedback!