Building Custom Payment Gateway Plugins for WooCommerce: Security, Webhooks, and Error Logging

Custom payment gateways eliminate intermediate platform fees and support local processors. Learn how to engineer a secure WooCommerce payment plugin from scratch.

Building Custom Payment Gateway Plugins for WooCommerce: Security, Webhooks, and Error Logging

For e-commerce merchants operating in global markets or regions with specialized local banks (like Sri Lanka's Commercial Bank, Sampath Bank, or PayHere gateway), using standard payment plugins can limit checkout options. Building a custom payment gateway plugin for WooCommerce allows you to bypass expensive middleman fees, control the user checkout flow, and integrate directly with local IPGs (Internet Payment Gateways).

However, payment processing is a high-risk system. Implementing poor webhook verification or weak hashing signatures exposes your store to checkout exploits, where users can forge transaction success states to download products without actually paying.

This guide provides a secure blueprint for building a custom WooCommerce payment gateway plugin, focusing on webhook authorization, transaction validation, and error logging.


1. Structure of a WooCommerce Gateway Class

Every WooCommerce payment gateway must extend the base WC_Payment_Gateway class. This class registers your gateway settings, handles payment forms, processes the redirect to the bank endpoint, and listens for validation webhooks.

Create your main plugin file (e.g., custom-ipg-gateway.php) and register the custom class during the init phase:

`php

<?php

/*

Plugin Name: WooCommerce Custom IPG Gateway

Description: A secure custom payment integration for WooCommerce.

Version: 1.0.0

Author: Anushka Dahanayake

*/

if ( ! class_exists( 'WC_Payment_Gateway' ) ) return;

add_action( 'plugins_loaded', 'init_custom_ipg_gateway_class' );

function init_custom_ipg_gateway_class() {

class WC_Gateway_Custom_IPG extends WC_Payment_Gateway {

public function __construct() {

$this->id = 'custom_ipg';

$this->icon = apply_filters( 'woocommerce_custom_ipg_icon', '' );

$this->has_fields = false;

$this->method_title = __( 'Custom IPG', 'wc-custom-ipg' );

$this->method_description = __( 'Redirects clients to secure local payment gateway.', 'wc-custom-ipg' );

$this->init_form_fields();

$this->init_settings();

$this->title = $this->get_option( 'title' );

$this->description = $this->get_option( 'description' );

$this->merchant_id = $this->get_option( 'merchant_id' );

$this->secret_key = $this->get_option( 'secret_key' );

add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );

add_action( 'woocommerce_api_wc_gateway_custom_ipg', array( $this, 'check_ipn_response' ) );

}

public function init_form_fields() {

$this->form_fields = array(

'enabled' => array(

'title' => __( 'Enable/Disable', 'wc-custom-ipg' ),

'type' => 'checkbox',

'label' => __( 'Enable Custom IPG', 'wc-custom-ipg' ),

'default' => 'no'

),

'title' => array(

'title' => __( 'Title', 'wc-custom-ipg' ),

'type' => 'text',

'default' => __( 'Secure Card Payment', 'wc-custom-ipg' ),

),

'merchant_id' => array(

'title' => __( 'Merchant ID', 'wc-custom-ipg' ),

'type' => 'text',

),

'secret_key' => array(

'title' => __( 'API Secret Key', 'wc-custom-ipg' ),

'type' => 'password',

)

);

}

}

}

`


2. Handling the Checkout Redirect

When the user clicks "Place Order", the process_payment() method is triggered. Instead of handling credit card fields locally (which requires PCI-DSS compliance audits), your plugin should compile transaction parameters and redirect the user to the bank's secure page.

`php

public function process_payment( $order_id ) {

$order = wc_get_order( $order_id );

// Compile redirect query parameters

$payment_url = 'https://secure.localbank.lk/pay';

$query_args = array(

'merchant' => $this->merchant_id,

'order_id' => $order_id,

'amount' => $order->get_total(),

'currency' => $order->get_currency(),

'return_url' => $this->get_return_url( $order ),

'cancel_url' => $order->get_cancel_order_url(),

// Generate secure checksum to prevent parameter tampering

'hash' => md5( $this->merchant_id . $order_id . $order->get_total() . $this->secret_key )

);

return array(

'result' => 'success',

'redirect' => add_query_arg( $query_args, $payment_url )

);

}

`


3. Securing Webhook Listeners (Instant Payment Notifications - IPN)

When a transaction succeeds, the payment gateway sends a POST request back to your server's webhook endpoint (configured via the woocommerce_api_wc_gateway_custom_ipg hook registered in your constructor).

> [!WARNING]

> Never update order status to "Completed" based on user-facing query redirects. Always require a signed backend-to-backend webhook payload containing validation parameters.

Secure Webhook Verification Endpoint:

`php

public function check_ipn_response() {

$merchant_id = sanitize_text_field( $_POST['merchant_id'] );

$order_id = sanitize_text_field( $_POST['order_id'] );

$status_code = sanitize_text_field( $_POST['status_code'] );

$amount = sanitize_text_field( $_POST['amount'] );

$hash = sanitize_text_field( $_POST['hash'] );

// Step 1: Recreate and verify MD5 signature hash

$local_hash = md5( $merchant_id . $order_id . $amount . $this->secret_key . $status_code );

if ( strtoupper( $hash ) !== strtoupper( $local_hash ) ) {

// Log unauthorized attempt and exit

$this->log_gateway_error( "Hash mismatch. Potential fraud payload from IP: " . $_SERVER['REMOTE_ADDR'] );

status_header( 403 );

exit;

}

$order = wc_get_order( $order_id );

if ( ! $order ) {

$this->log_gateway_error( "Order ID {$order_id} not found." );

status_header( 404 );

exit;

}

// Step 2: Verify transaction amount matches order total exactly

if ( (float) $amount !== (float) $order->get_total() ) {

$this->log_gateway_error( "Amount mismatch for Order {$order_id}. Pay: {$amount}, Order: " . $order->get_total() );

$order->update_status( 'on-hold', __( 'Payment amount validation mismatch.', 'wc-custom-ipg' ) );

status_header( 400 );

exit;

}

// Step 3: Update Order Status

if ( $status_code === '2' ) { // Success code from bank API

$order->payment_complete();

$order->add_order_note( __( 'IPN Validation Success. Card Charged.', 'wc-custom-ipg' ) );

status_header( 200 );

exit;

} else {

$order->update_status( 'failed', __( 'Transaction declined by bank API.', 'wc-custom-ipg' ) );

status_header( 200 );

exit;

}

}

`


4. Professional Error Logging

To troubleshoot payment errors and audit disputed logs, implement a helper logging method using WooCommerce's native WC_Logger class:

`php

private function log_gateway_error( $message ) {

if ( class_exists( 'WC_Logger' ) ) {

$logger = wc_get_logger();

$logger->log( 'info', $message, array( 'source' => 'custom-ipg-gateway' ) );

}

}

`

This saves system logs directly to wp-content/uploads/wc-logs/custom-ipg-gateway-... which you can securely inspect in the WooCommerce Status dashboard.

By isolating your webhook endpoints, verifying hash checksums, validating amounts, and maintaining logs, you establish a secure transaction flow that reduces payment failures and eliminates fraud.

Related posts

Cross-Listing Inventory Management Without Overselling
E-commerce14 min read

Cross-Listing Inventory Management Without Overselling

A practical cross-listing inventory architecture covering canonical SKUs, stock states, reservations, marketplace mappings, order events, synchronization, reconciliation and recovery.

Read article →

Depop Pricing Strategy: Fees, Offers and Profit
E-commerce13 min read

Depop Pricing Strategy: Fees, Offers and Profit

A practical Depop pricing system covering market research, location-based fees, buyer costs, offers, discounts, bundles, shipping, boosting, returns and contribution.

Read article →

eBay Item Specifics and Product Identifiers Guide
E-commerce14 min read

eBay Item Specifics and Product Identifiers Guide

A complete eBay structured-data guide covering categories, required and recommended item specifics, product identifiers, catalog matching, variations, condition and bulk repair.

Read article →

Author

Anushka Dahanayake

Anushka Dahanayake is the founder of ANUSHKA DAHANAYAKE (PVT) LTD, building SEO-driven content, digital services, and revenue platforms for businesses in Sri Lanka and worldwide.