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.
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.
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:
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', ) ); }
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
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.
Q. How do I add a payment gateway in WooCommerce?
- Go to Plugins > Add New and search for your chosen payment gateway such as “Stripe” or “PayPal”.
- Install and activate the plugin.
- Go to WooCommerce > Settings > Payments.
- Enable the gateway and enter the required API keys or credentials from your payment provider.
Q. Does WooCommerce have its own payment gateway?
A. WooCommerce itself doesn’t have its own built-in payment gateway, but it offers WooCommerce Payments, which is a payment solution for WooCommerce stores based in specific countries. It also supports various other payment gateways through extensions.
Q. What is the best payment provider for WooCommerce?
A. There’s no single “best” provider, as it depends on your needs and location. Popular options include:
Stripe: Known for its developer-friendly API and wide range of features.
PayPal: Widely recognized and trusted by many customers.
Square: Ideal for businesses with both online and physical stores, providing unified payment processing.
Owais Khan
Owais works as a Marketing Manager at Cloudways (managed hosting platform) where he focuses on growth, demand generation, and strategic partnerships. With more than a decade of experience in digital marketing and B2B, Owais prefers to build systems that help teams achieve their full potential.