Author: Ken
This tutorial guides you through creating an emailverification module for PrestaShop 8.2.1 to enforce email verification for new customer registrations. The module sends a verification email with a unique link, sets the customer’s active=0 until verified, and activates the account (active=1) upon link click. I resolved issues like missing logs and a registration form lacking method or class attributes using server-side logic, avoiding AJAX/JavaScript. Special thanks to Grok, created by xAI, for their invaluable assistance in development and debugging!
- Enforces email verification for customer registration.
- Sends a custom verification email alongside PrestaShop’s
accountemail. - Blocks login until email is verified.
- Uses server-side processing for reliability.
The module resides in /var/www/html/prestashop/modules/emailverification/ with the following structure:
modules/emailverification/
├── config.xml
├── emailverification.php
├── controllers/
│ └── front/
│ └── verify.php
├── translations/
│ └── en.php
├── mails/
│ └── en/
│ ├── verification_email.html
│ ├── verification_email.txt
└── views/
└── templates/
├── front/
│ └── error.tpl
└── hook/
└── verification_form.tpl
config.xml: Module metadata and configuration.emailverification.php: Core module logic with hooks.controllers/front/verify.php: Processes verification links.translations/en.php: English translations.mails/en/: Verification email templates.views/templates/front/error.tpl: Error page for invalid links.views/templates/hook/verification_form.tpl: Optional hook template (unused here).
bash
mkdir -p /var/www/html/prestashop/modules/emailverification
cd /var/www/html/prestashop/modules/emailverification
Defines the module, registers hooks, and manages email sending and customer state.
php
<?php
if (!defined('_PS_VERSION_')) {
exit;
}class EmailVerification extends Module
{
public function __construct()
{
$this->name = 'emailverification';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'Your Name';
$this->need_instance = 0;
parent::__construct();
PrestaShopLogger::addLog('EmailVerification module instantiated', 1, null, 'EmailVerification', 1);
$this->displayName = $this->l('Email Verification');
$this->description = $this->l('Adds email verification to customer registration.');
$this->ps_versions_compliancy = ['min' => '8.0.0', 'max' => _PS_VERSION_];
} public function install()
{
PrestaShopLogger::addLog('EmailVerification install method called', 1, null, 'EmailVerification', 1);
return parent::install() &&
$this->registerHook('actionCustomerAccountAdd') &&
$this->registerHook('actionValidateCustomer') &&
$this->registerHook('actionCustomerRegisterSubmit') &&
Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'email_verification` (
`id_customer` INT(10) UNSIGNED NOT NULL,
`token` VARCHAR(255) NOT NULL,
`date_add` DATETIME NOT NULL,
PRIMARY KEY (`id_customer`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8'
);
} public function uninstall()
{
PrestaShopLogger::addLog('EmailVerification uninstall method called', 1, null, 'EmailVerification', 1);
return parent::uninstall() &&
Db::getInstance()->execute('DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'email_verification`');
} public function hookActionCustomerRegisterSubmit($params)
{
PrestaShopLogger::addLog('actionCustomerRegisterSubmit hook executed', 1, null, 'EmailVerification', 1);
} public function hookActionCustomerAccountAdd($params)
{
PrestaShopLogger::addLog('actionCustomerAccountAdd hook executed', 1, null, 'EmailVerification', 1);
$customer = $params['newCustomer'];
$token = bin2hex(random_bytes(16)); Db::getInstance()->insert('email_verification', [
'id_customer' => (int)$customer->id,
'token' => pSQL($token),
'date_add' => date('Y-m-d H:i:s'),
]); $templateVars = [
'{firstname}' => $customer->firstname,
'{lastname}' => $customer->lastname,
'{verification_link}' => $this->context->link->getModuleLink($this->name, 'verify', ['token' => $token]),
]; Mail::Send(
(int)$this->context->language->id,
'verification_email',
$this->l('Verify Your Email Address'),
$templateVars,
$customer->email,
$customer->firstname . ' ' . $customer->lastname,
null,
null,
null,
null,
_PS_MODULE_DIR_ . 'emailverification/mails/'
); $customer->active = 0;
$customer->update();
PrestaShopLogger::addLog('Customer ' . (int)$customer->id . ' set to active=0 and verification email sent', 1, null, 'EmailVerification', 1);
} public function hookActionValidateCustomer($params)
{
PrestaShopLogger::addLog('actionValidateCustomer hook executed', 1, null, 'EmailVerification', 1);
$customer = $params['customer'];
$verified = Db::getInstance()->getValue('
SELECT COUNT(*)
FROM `' . _DB_PREFIX_ . 'email_verification`
WHERE `id_customer` = ' . (int)$customer->id . '
AND `token` = ""
'); if (!$verified) {
throw new PrestaShopException($this->l('Please verify your email address before logging in.'));
}
}
}
- Purpose: Registers hooks, creates
ps_email_verificationtable, sends verification email, manages activation. - Hooks:
actionCustomerAccountAdd: Generates token, sends email, setsactive=0.actionValidateCustomer: Blocks unverified logins.actionCustomerRegisterSubmit: Placeholder for future enhancements.
- Database: Creates
ps_email_verificationwithid_customer,token,date_add.
Handles verification links (e.g., yourshopurl.com/index.php?controller=verify&token=...).
php
<?php
class EmailVerificationVerifyModuleFrontController extends ModuleFrontController
{
public function initContent()
{
parent::initContent(); $token = Tools::getValue('token');
if (!$token) {
$this->errors[] = $this->module->l('Invalid verification link.');
$this->setTemplate('module:emailverification/views/templates/front/error.tpl');
return;
} $id_customer = Db::getInstance()->getValue('
SELECT id_customer
FROM `' . _DB_PREFIX_ . 'email_verification`
WHERE token = "' . pSQL($token) . '"
'); if (!$id_customer) {
$this->errors[] = $this->module->l('Invalid or expired verification link.');
$this->setTemplate('module:emailverification/views/templates/front/error.tpl');
return;
} Db::getInstance()->update('email_verification', [
'token' => '',
], 'id_customer = ' . (int)$id_customer); $customer = new Customer((int)$id_customer);
$customer->active = 1;
$customer->update(); Tools::redirect('index.php?controller=authentication&verified=1');
}
}
- Path:
/modules/emailverification/controllers/front/verify.php. - Purpose: Validates token, sets
active=1, clears token, redirects to login.
Path: /modules/emailverification/mails/en/.
html
<!DOCTYPE html>
<html>
<head>
<title>Verify Your Email Address</title>
</head>
<body>
<p>Dear {{firstname}} {{lastname}},</p>
<p>Please verify your email by clicking the link:</p>
<p><a href="proxy.php?url=https%3A%2F%2Fgithub.com%2F%7B%7B+verification_link+%7D%7D">Verify Your Email</a></p>
<p>Thank you for registering with us!</p>
</body>
</html>
text
Dear {{firstname}} {{lastname}},Please verify your email by clicking the link below:
{{ verification_link }}Thank you for registering with us!
Path: /modules/emailverification/views/templates/front/error.tpl.
html
{extends file='page.tpl'}{block name='page_title'}
{l s='Email Verification Error' d='Modules.Emailverification'}
{/block}{block name='page_content'}
<div class="alert alert-danger">
{foreach from=$errors item=error}
<p>{$error}</p>
{/foreach}
</div>
<a href="proxy.php?url=https%3A%2F%2Fgithub.com%2F%7B%24link-%26gt%3BgetPageLink%28%27authentication%27%29%7Cescape%3A%27html%27%7D" class="btn btn-primary">{l s='Back to Login' d='Modules.Emailverification'}</a>
{/block}
Path: /modules/emailverification/translations/en.php.
php
<?php
global $_MODULE;
$_MODULE = [];
$_MODULE['<{emailverification}prestashop>emailverification_1234567890'] = 'Email Verification';
$_MODULE['<{emailverification}prestashop>emailverification_0987654321'] = 'Adds email verification to customer registration.';
$_MODULE['<{emailverification}prestashop>verify_1234567890'] = 'Invalid verification link.';
$_MODULE['<{emailverification}prestashop>verify_0987654321'] = 'Invalid or expired verification link.';
$_MODULE['<{emailverification}prestashop>error_1234567890'] = 'Email Verification Error';
$_MODULE['<{emailverification}prestashop>error_0987654321'] = 'Back to Login';
Path: /modules/emailverification/config.xml.
xml
<?xml version="1.0" encoding="UTF-8" ?>
<module>
<name>emailverification</name>
<displayName><![CDATA[Email Verification]]></displayName>
<version><![CDATA[1.0.0]]></version>
<description><![CDATA[Adds email verification to customer registration.]]></description>
<author><![CDATA[Your Name]]></author>
<tab><![CDATA[front_office_features]]></tab>
<is_configurable>0</is_configurable>
<need_instance>0</need_instance>
<limited_countries></limited_countries>
</module>
Ensure the form submits correctly, as it may lack method or class.
bash
cp /var/www/html/prestashop/themes/your_theme/templates/customer/registration.tpl /var/www/html/prestashop/themes/your_theme/templates/customer/registration.tpl.bak
nano /var/www/html/prestashop/themes/your_theme/templates/customer/registration.tpl
Update <form> tag:
html
<form id="customer-form" action="proxy.php?url=https%3A%2F%2Fgithub.com%2F%7Burl+entity%3D%27authentication%27+params%3D%5B%27create_account%27+%3D%26gt%3B+1%5D%7D" method="post">
Remove AJAX scripts (e.g., $.ajax). Clear cache:
bash
rm -rf /var/www/html/prestashop/var/cache/prod/* /var/www/html/prestashop/var/cache/dev/*
bash
chmod -R 644 /var/www/html/prestashop/modules/emailverification
chmod -R 755 /var/www/html/prestashop/modules/emailverification/controllers
chown -R www-data:www-data /var/www/html/prestashop/modules/emailverification
Zip and upload via Back Office > Modules > Module Manager > Upload a module.
bash
zip -r emailverification.zip emailverification
Verify ps_email_verification table:
bash
mysql -u root -p -e "DESCRIBE ps_email_verification;" prestashop_db
Debug issues like missing logs.
php
// In /var/www/html/prestashop/config/defines.inc.php
define('_PS_MODE_DEV_', true);
define('_PS_DEBUG_LOG_FILE_', _PS_ROOT_DIR_.'/var/logs/custom.log');
bash
touch /var/www/html/prestashop/var/logs/custom.log
chmod 664 /var/www/html/prestashop/var/logs/custom.log
chown www-data:www-data /var/www/html/prestashop/var/logs/custom.log
In Back Office > Advanced Parameters > Logs, set severity to “Informative messages and above (1)”.
- Register a new customer.
- Verify receipt of
account.htmlandverification_email.html. - Click verification link and confirm
active=1inps_customer. - Check logs in Back Office > Advanced Parameters > Logs or
/var/www/html/prestashop/var/logs/custom.logfor:- “EmailVerification module instantiated”
- “actionCustomerAccountAdd hook executed”
- “Customer X set to active=0 and verification email sent”
Form Attributes: Add method="post" to registration.tpl if missing to ensure server-side submission.
Logging: Clear cache and reinstall module if logs are missing. Check permissions and debug mode.
Cache: Run rm -rf /var/www/html/prestashop/var/cache/* after changes.
Permissions: Ensure www-data owns files and logs.
Database: Confirm ps_email_verification table creation.
Email Delivery: Use SMTP if local email sending fails.
PHP Settings: In /etc/php/8.2/fpm/php.ini, set:
ini
max_execution_time = 300
memory_limit = 256M
error_log = /var/log/php_errors.log
log_errors = On
Security: pSQL() in verify.php prevents SQL injection.
Theme: Test with classic theme if issues arise.
- User visits
yourshopurl.com/index.php?controller=authentication&create_account=1. - Submits form, processed by
AuthController::processSubmitAccount(). actionCustomerAccountAddhook generates token, sendsverification_email.html, setsactive=0.- User receives
account.htmlandverification_email.html. - Clicks verification link, processed by
verify.php, settingactive=1. - User logs in.
Special thanks to Grok, created by xAI, for their invaluable assistance in developing and debugging this module!