Gateway Template
The Gateway Template gives you a starting point for building your own POS-only payment gateway. It produces a working WordPress plugin with a single PHP file that you can install and customise to fit your needs.
Features
Minimal Code
A single PHP file with just the essentials — easy to read and modify
POS Only
Disabled on web checkout by default, enabled through WCPOS settings
Automated Setup
A shell script handles all the placeholder replacement for you
GitHub Releases
Push a version bump and GitHub Actions builds a downloadable ZIP
Getting Started
Clone the Template Repository
git clone https://github.com/wcpos/woocommerce-gateway-template.git
cd woocommerce-gateway-template
Or click the Use this template button on the GitHub repository to create your own copy.
Run the Setup Script
./create-gateway.sh
The script asks for a few details — your gateway name, a short description, and your GitHub username — then generates a ready-to-use plugin in a directory of your choice.
Install the Plugin
You have two options:
Option A — Copy the folder directly (if you have server access):
Copy the generated gateway folder into your site's wp-content/plugins/ directory.
Option B — Zip and upload (easiest for most people):
- Compress the generated folder into a
.zipfile - In WordPress, go to Plugins > Add New > Upload Plugin
- Choose the zip file and click Install Now
Enable in WCPOS
- Go to WP Admin > WCPOS > Settings > Checkout
- Find your new gateway in the list and enable it
The gateway is disabled on the regular web checkout by default. WCPOS controls which gateways appear in the POS through its own settings.
Manual Setup
If you prefer not to use the script, you can replace the placeholders yourself. Open each file in a text editor and find-and-replace the following:
| Placeholder | What to enter | Example |
|---|---|---|
{{GATEWAY_NAME}} | Your gateway's display name | Cash Payment |
{{GATEWAY_SLUG}} | A URL-safe identifier (lowercase, hyphens) | cash-payment |
{{GATEWAY_DESCRIPTION}} | Short description of the gateway | Accept cash payments in WCPOS |
{{GATEWAY_DEFAULT_DESCRIPTION}} | Text shown to the cashier at checkout | Pay with cash at the point of sale |
{{GITHUB_USERNAME}} | Your GitHub username | kilbot |
{{REPO_NAME}} | Your repository name | cash-payment-gateway |
{{AUTHOR_NAME}} | Your name | kilbot |
{{GATEWAY_ID}} | Slug with underscores instead of hyphens | cash_payment |
{{GATEWAY_CLASS_NAME}} | Each word capitalised, joined by underscores | Cash_Payment |
{{GATEWAY_FUNCTION_PREFIX}} | Same as Gateway ID | cash_payment |
Then rename wcpos-{{GATEWAY_SLUG}}.php to match your slug (e.g., wcpos-cash-payment.php).
The setup script derives GATEWAY_ID, GATEWAY_CLASS_NAME, and GATEWAY_FUNCTION_PREFIX automatically from the name and slug, so you only need to think about these when doing manual setup.
How It Works
The generated plugin registers a WooCommerce payment gateway class. Here are the key things to know:
$this->enabled = 'no'— The gateway is hidden from web checkout. WCPOS enables it in the POS based on your POS settings.process_payment()— Calls$order->payment_complete(), which marks the order as paid and handles stock reduction automatically.init_form_fields()— Defines the Title and Description fields that appear in WooCommerce settings.
Customising Your Gateway
Adding Payment Fields
If your gateway needs input from the cashier (for example, a reference number), override the payment_fields() method:
public function payment_fields() {
if ( $this->description ) {
echo wpautop( wptexturize( $this->description ) );
}
woocommerce_form_field( 'my_gateway_reference', array(
'type' => 'text',
'label' => __( 'Reference Number', 'your-text-domain' ),
'required' => true,
) );
}
You can then read the submitted value in process_payment() via $_POST['my_gateway_reference']. Remember to sanitise any input with sanitize_text_field().
Changing Payment Behaviour
The default template marks orders as paid immediately. If your workflow requires payment later (like an invoice), replace payment_complete() with a status update:
public function process_payment( $order_id ) {
$order = wc_get_order( $order_id );
// Set to pending — the customer will pay later.
$order->update_status( 'pending', __( 'Awaiting payment', 'your-text-domain' ) );
// Stock must be reduced manually when not using payment_complete().
wc_reduce_stock_levels( $order_id );
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order ),
);
}
Making Changes and Updating
After installing your gateway, you can keep editing the plugin file to adjust the payment logic. To install an updated version:
- Edit
wcpos-your-slug.phpin the generated folder - Update the
Version:number in the plugin header (e.g.,0.1.0to0.2.0) - Zip the folder and upload it again through Plugins > Add New > Upload Plugin, or replace the folder directly in
wp-content/plugins/
WordPress will ask if you want to replace the existing plugin when you upload a zip with the same plugin name — click Replace current with uploaded to update.
Automated Releases with GitHub
If you push your gateway to a GitHub repository, the template includes a GitHub Actions workflow that creates releases automatically:
- Update the
Version:number in the plugin header - Commit and push to the
mainbranch - GitHub Actions detects the version change and creates a new release with a downloadable ZIP
Other users can then download the ZIP from your repository's Releases page and install it like any WordPress plugin.
Troubleshooting
Gateway doesn't appear in the POS
- Check that the plugin is activated in WP Admin > Plugins
- Go to WP Admin > WCPOS > Settings > Checkout and make sure the gateway is enabled
- Verify that WooCommerce is installed and active
Gateway shows up on the web checkout
- Make sure
$this->enabled = 'no';is set in the gateway constructor - WCPOS overrides this setting for POS requests, so the gateway should only appear in the POS
Orders stay in 'Processing' instead of 'Completed'
- WooCommerce sets the order status based on product types. Orders containing physical products stay in "Processing" — this is normal WooCommerce behaviour. Only orders with exclusively virtual or downloadable products are marked "Completed" automatically.
Resources
- GitHub: woocommerce-gateway-template
- WooCommerce Payment Gateway API: WC_Payment_Gateway docs
Example Gateways
These existing gateways were built with the same approach and are good references:
- Email Invoice — Sends an invoice email so the customer can pay later
- Web Checkout — Redirects to the web store for payment