SOLLER logo

Creating a PrestaShop Payment Module with Country Restrictions

LV | EN | RU

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.

Article contents:

What this module should do

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:

Example: a store wants to show bank transfer only to buyers from Latvia, Lithuania, Estonia, Finland and Sweden. For all other countries this payment method is hidden, and the buyer chooses another available payment option.

Why it is better to create a separate module instead of editing the standard Bank Wire module

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.

Important: it is not recommended to edit the PrestaShop core or standard modules directly. New functionality should be implemented as a separate module. This makes maintenance, updates and troubleshooting easier.

What a PrestaShop module consists of

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:

What needs to be installed on the server

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.

1. A working PrestaShop store

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

2. PHP extensions

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.

3. Composer

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.

4. Logs and SSH access

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.

Preparing the GeoIP database

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.

Not recommended: do not place the GeoIP database directly inside 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.

Main module logic

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.

Check 1: whether the module is active

If the module is disabled in the PrestaShop admin panel, it should not appear in checkout.

Check 2: whether the GeoIP database exists

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;
}

Check 3: determine the buyer’s IP address

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.

Important: headers such as 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.

Check 4: determine the country

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

Check 5: compare with the allowed country list

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.

How the module creates an order

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.

What should be included in the module settings

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
Be careful with logs: the buyer’s IP address is personal data. Do not store unnecessary IP logs without a reason, and do not display such data on public pages.

Where the payment method should appear

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.

How to install the finished module

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:

  1. open the module settings;
  2. enter the bank details;
  3. enter the allowed countries;
  4. save the settings;
  5. clear the PrestaShop cache;
  6. check checkout;
  7. create a test order.

What to check 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/*
A good test result: a buyer from an allowed country sees the bank transfer payment method, confirms the order, the order appears in Back Office, and the buyer receives the correct bank details.

Common errors

1. The module does not appear in the payment method list

Possible reasons:

2. Composer autoload error

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

3. The GeoIP database is not readable

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.

4. The wrong country is detected

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.

5. The order is not created after selecting the payment method

In this case, check:

Security and privacy

The module works with the buyer’s IP address, so several rules should be followed:

Practical conclusion: GeoIP is a useful technical filter, but it is not an absolute guarantee of the buyer’s location. It is better used for controlling payment method visibility, not as the only basis for a legally significant decision.

Recommended development workflow

A safe workflow for a store administrator looks like this:

  1. Create a copy of the store on a test domain.
  2. Create the module directory inside /modules/.
  3. Install Composer dependencies.
  4. Connect the GeoLite2 Country database.
  5. Implement the basic payment module.
  6. Add bank details settings.
  7. Add the allowed country list.
  8. Check display in checkout.
  9. Check order creation.
  10. Check emails.
  11. Pack the module into a ZIP archive.
  12. Install it on the live store.
  13. Clear cache.
  14. Create a test order.

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)

What the store administrator should understand

You do not need to be a professional developer to work with such a module, but you should understand the basics:

If the store runs on a VPS, the administrator should ideally have access to:

Conclusion

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:

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.

🧩 Need a payment module for PrestaShop?

SOLLER.LV helps create and customize PrestaShop modules: payment methods, delivery integrations, product import, GeoIP restrictions, checkout logic and e-commerce automation solutions.

📧 info@soller.lv | ☎️ 27463463