Sometimes an online store needs to show a specific payment method not to every customer, but only to buyers from selected countries. For example, bank transfer may be convenient for one group of countries, but unsuitable for another. In this case, you can create a separate PrestaShop payment module that works similarly to the standard bank wire module, but additionally checks the buyer’s country by IP address.
This article is intended for a store administrator with basic PrestaShop knowledge: installing modules, working with site files, FTP/SFTP, SSH, clearing cache, and understanding the general structure of the store. We will not go deep into PrestaShop core architecture, but we will explain what such a module consists of, what needs to be prepared on the server, and what should be tested before launching it on a live store.
The task of the module is quite simple: add a new payment method to the PrestaShop checkout that works like bank transfer, but is displayed only to buyers from allowed countries.
In practice, the module should perform the following actions:
At first glance, it may seem easier to modify the standard bank wire module. For a live store, however, this is not the safest approach.
The standard module may be overwritten during a PrestaShop update or during an update of the module itself. In addition, if the store already uses the regular bank wire payment method, editing the standard module may break the current payment setup, old orders, emails and settings.
A much safer option is to create a separate module, for example:
sollerwiregeo
Such a module can be enabled, disabled, removed, moved to another store and improved independently from the standard bank wire module.
PrestaShop modules are normally located in the following directory:
/modules/
For example, our module could be placed here:
/modules/sollerwiregeo/
The main module file usually has the same name as the module directory:
/modules/sollerwiregeo/sollerwiregeo.php
A minimal payment module structure may look like this:
sollerwiregeo/
├── sollerwiregeo.php
├── config.xml
├── index.php
├── logo.png
├── composer.json
├── vendor/
├── controllers/
│ └── front/
│ ├── payment.php
│ └── validation.php
├── views/
│ └── templates/
│ └── hook/
│ └── payment_options.tpl
└── mails/
├── en/
├── lv/
└── ru/
Not all files are mandatory at the first stage, but a proper payment module usually needs:
composer.json file if external PHP libraries are used;vendor/ directory with installed dependencies.For this type of module, the server must be able to run PrestaShop normally and also read a GeoIP database. Below is a practical checklist of what should be verified before development or installation.
First, you need an installed and working PrestaShop store. It is better not to develop or test the module directly on the live store. A safer approach is:
production shop → test / staging copy
On a test copy, you can safely check installation, removal, checkout errors, order creation and email sending.
For PrestaShop 1.7.8, a typical environment is:
PHP 7.4
MariaDB / MySQL
Apache or Nginx + Apache
SSH access
access to site files
debug mode enabled on the test site
Usually, the main PHP extensions required for PrestaShop are already installed:
php-cli
php-curl
php-zip
php-intl
php-mbstring
php-xml
php-gd
php-mysql
For GeoIP functionality, it is not necessary to install a separate system GeoIP extension. It is more convenient to use the MaxMind GeoIP2 PHP library via Composer. In this case, PHP reads the .mmdb database file through the library.
Composer is needed to install external PHP libraries. In this case, it is used to install the GeoIP2 library.
You can check Composer with:
composer --version
If Composer is not installed on Debian or Ubuntu, it can be installed as follows:
apt update
apt install composer -y
Inside the module directory, create a file:
composer.json
Example content:
{
"require": {
"geoip2/geoip2": "^2.13"
}
}
Then install dependencies inside the module directory:
cd /path/to/prestashop/modules/sollerwiregeo
composer install --no-dev
After that, the following directory will appear:
vendor/
This directory must remain inside the module because it contains the classes used to read the GeoIP database.
For normal debugging, it is useful to have SSH access to the server and the ability to read logs:
/var/log/apache2/
/var/log/nginx/
/var/log/php*/
/path/to/prestashop/var/logs/
If the site is hosted on shared hosting without SSH access, the module can still be used, but the vendor/ directory should be prepared in advance on a local computer or test server, and then uploaded as part of the finished module archive.
To determine the buyer’s country by IP address, the GeoLite2 Country database is sufficient. It allows the module to obtain a country ISO code, for example:
LV
LT
EE
SE
FI
DE
The database file is usually named:
GeoLite2-Country.mmdb
It is better to store it outside the public site directory, one level above public_html, for example:
/home/shop/private/geoip/GeoLite2-Country.mmdb
Example structure:
/home/shop/
├── private/
│ └── geoip/
│ └── GeoLite2-Country.mmdb
└── public_html/
└── modules/
└── sollerwiregeo/
This approach is safer because the database file will not be directly accessible from the browser.
public_html or another public directory. Even if the file does not contain passwords, service files should be stored outside the public part of the website.
Example directory preparation:
mkdir -p /home/shop/private/geoip
chown -R shop:shop /home/shop/private/geoip
chmod 750 /home/shop/private/geoip
chmod 640 /home/shop/private/geoip/GeoLite2-Country.mmdb
In the module code, the database path can be defined like this:
const GEOIP_DB_PATH = _PS_ROOT_DIR_ . '/../private/geoip/GeoLite2-Country.mmdb';
Here _PS_ROOT_DIR_ is the PrestaShop root directory, usually public_html. Therefore, ../private/geoip/ means a directory above the public site directory.
The module should not simply display a payment button. It should carefully run several checks. If something is wrong, it is better to hide the payment method than to break the entire checkout process.
If the module is disabled in the PrestaShop admin panel, it should not appear in checkout.
If the database file does not exist or is not readable, the module should not cause a fatal error.
if (!is_file(self::GEOIP_DB_PATH) || !is_readable(self::GEOIP_DB_PATH)) {
return false;
}
In a simple setup, the IP address can be taken from the standard server variable:
$_SERVER['REMOTE_ADDR']
However, if the site works behind Cloudflare, a reverse proxy or another CDN, trusted headers must be handled separately. Otherwise, the module may see the proxy server IP address instead of the buyer’s real IP address.
X-Forwarded-For must not be trusted blindly. They should only be used when the server is actually behind a trusted proxy and the web server configuration is set up correctly.
After connecting Composer autoload, the GeoIP2 library can be used:
require_once __DIR__ . '/vendor/autoload.php';
$reader = new \GeoIp2\Database\Reader(self::GEOIP_DB_PATH);
$record = $reader->country($ip);
$countryIso = $record->country->isoCode;
As a result, the module receives a country ISO code, for example:
LV
The module settings can store a country list:
LV,LT,EE,SE,FI
If the buyer’s country is in this list, the payment method is shown. If not, it is hidden.
A PrestaShop payment module does not only show a button in checkout. It must correctly create an order in the system.
Usually, such a module extends the class:
PaymentModule
After payment confirmation, the order creation method is called:
$this->module->validateOrder(...);
For bank transfer, the order usually receives a status indicating that payment is being awaited, for example:
Awaiting bank wire payment
Or the module can create its own status, for example:
Awaiting geo bank transfer payment
It is important for the store administrator to understand that such a module does not automatically charge the buyer’s card or account. It only creates an order and shows the buyer the bank details. The actual receipt of funds must be checked manually in the bank account.
So that the administrator can manage the module without editing PHP code, it is useful to create a settings page in the Back Office.
The minimum set of settings:
Example value for the allowed country field:
LV,LT,EE,SE,FI
It is also useful to add a debug mode:
Debug mode: Yes / No
In debug mode, the module may log technical information:
IP: 85.xxx.xxx.xxx
Detected country: LV
Payment visible: yes
In PrestaShop 1.7, the payment method appears during checkout at the payment selection step.
The buyer should see something like this:
Pay by bank transfer
Your order will be processed after payment is received.
After selecting the payment method and confirming the order, the buyer lands on the order confirmation page and sees the bank details:
Order confirmed
Please transfer the total amount to the following bank account:
IBAN: ...
SWIFT: ...
Bank: ...
The store administrator sees the order in the Back Office, and the buyer receives an email with payment instructions.
When the module is ready, it should be packed into a ZIP archive.
Correct archive structure:
sollerwiregeo.zip
└── sollerwiregeo/
├── sollerwiregeo.php
├── config.xml
├── vendor/
├── controllers/
├── views/
└── mails/
Important: the archive must contain the module directory, not just files without a folder.
Installation through the PrestaShop admin panel:
Back Office → Modules → Module Manager → Upload a module
After installation:
Minimum checklist:
Syntax check of the main file:
php -l /path/to/prestashop/modules/sollerwiregeo/sollerwiregeo.php
Clearing PrestaShop 1.7 cache:
rm -rf /path/to/prestashop/var/cache/prod/*
rm -rf /path/to/prestashop/var/cache/dev/*
Possible reasons:
If an error appears related to GeoIp2 or MaxMind classes, dependencies are probably not installed.
Check for the autoload file:
ls -la /path/to/prestashop/modules/sollerwiregeo/vendor/autoload.php
If the file does not exist:
cd /path/to/prestashop/modules/sollerwiregeo
composer install --no-dev
Check the file:
ls -lh /home/shop/private/geoip/GeoLite2-Country.mmdb
Check permissions along the full path:
namei -l /home/shop/private/geoip/GeoLite2-Country.mmdb
The PHP user must have permission to read the database file.
This may happen if the site works behind a proxy, CDN or Cloudflare. In that case, REMOTE_ADDR may contain the intermediate server IP address instead of the buyer’s IP address.
Possible headers:
HTTP_CF_CONNECTING_IP
X-Forwarded-For
They should only be used with a correctly configured trusted proxy. Otherwise, a malicious user may insert any IP address into the header.
In this case, check:
validation.php;validateOrder() call;The module works with the buyer’s IP address, so several rules should be followed:
A safe workflow for a store administrator looks like this:
/modules/.Before making any changes on a live site, it is recommended to create a backup:
cp -a /path/to/prestashop/modules/sollerwiregeo \
/path/to/prestashop/modules/sollerwiregeo.bak.$(date +%F-%H%M%S)
You do not need to be a professional developer to work with such a module, but you should understand the basics:
modules directory is;If the store runs on a VPS, the administrator should ideally have access to:
A payment module with buyer country restrictions is a practical solution for stores that need flexible control over available payment methods. It can be built using the logic of the standard bank wire module, but it is better to implement it as a separate independent module.
The main elements of such a solution are:
PaymentModule;validateOrder();public_html;This approach allows you to avoid breaking the standard bank wire module, avoid modifying the PrestaShop core, and keep the store easier to update in the future.
SOLLER.LV helps create and customize PrestaShop modules: payment methods, delivery integrations, product import, GeoIP restrictions, checkout logic and e-commerce automation solutions.