Personnaliser le formulaire de création de compte PrestaShop
Guide complet pour personnaliser le formulaire d'inscription client PrestaShop : ajout de champs, hooks, validation et module custom. Compatible 1.7 et 8.x.
En bref : Pour personnaliser le formulaire d'inscription PrestaShop, créez un module exploitant le hook `additionalCustomerFormFields` qui injecte des champs via l'API FormField, avec validation serveur et stockage dans une table dédiée — sans jamais modifier le core.
Pourquoi personnaliser le formulaire d'inscription PrestaShop
Le formulaire de création de compte par défaut de PrestaShop collecte les informations essentielles : nom, prénom, email et mot de passe. Mais dans de nombreux contextes B2B ou métiers spécifiques, ce formulaire est insuffisant. On peut avoir besoin d'un numéro SIRET, d'un code client, d'un champ société obligatoire, ou de toute autre donnée métier dès l'inscription.
Plutôt que de modifier les fichiers core — ce qui compromettrait toute mise à jour future — la bonne approche consiste à développer un module qui exploite le système de hooks natifs de PrestaShop.
Architecture du formulaire d'inscription
Avant de coder, il faut comprendre comment PrestaShop gère ce formulaire.
Le flow côté contrôleur
Le formulaire de création de compte est géré par le contrôleur AuthController (fichier controllers/front/AuthController.php). Ce contrôleur utilise le composant CustomerForm situé dans src/Core/Form/ (PrestaShop 1.7+) qui implémente le pattern FormField.
Le rendu du formulaire passe par le template Smarty :
themes/votre-theme/templates/customer/_partials/customer-form.tpl
Les hooks disponibles
PrestaShop expose plusieurs hooks pour intervenir sur le formulaire client :
Créer un module de personnalisation du formulaire
Structure du module
Voici la structure minimale d'un module qui ajoute des champs au formulaire d'inscription :
mon_module_customer_form/
├── mon_module_customer_form.php
├── sql/
│ ├── install.sql
│ └── uninstall.sql
├── views/
│ └── templates/
│ └── hook/
└── logo.png
Le fichier principal du module
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class Mon_Module_Customer_Form extends Module
{
public function __construct()
{
$this->name = 'mon_module_customer_form';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'Alexandre Carette';
$this->need_instance = 0;
$this->ps_versions_compliancy = [
'min' => '1.7.0.0',
'max' => '8.99.99',
];
parent::__construct();
$this->displayName = $this->l('Personnalisation formulaire client');
$this->description = $this->l('Ajoute des champs personnalisés au formulaire de création de compte.');
}
public function install()
{
return parent::install()
&& $this->registerHook('additionalCustomerFormFields')
&& $this->registerHook('validateCustomerFormFields')
&& $this->registerHook('actionObjectCustomerAddAfter')
&& $this->registerHook('actionObjectCustomerUpdateAfter')
&& $this->installDb();
}
private function installDb()
{
$sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'customer_custom_fields` (
`id_customer` INT(10) UNSIGNED NOT NULL,
`company_siret` VARCHAR(14) DEFAULT NULL,
`customer_code` VARCHAR(50) DEFAULT NULL,
`activity_sector` VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (`id_customer`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4;';
return Db::getInstance()->execute($sql);
}
public function uninstall()
{
return parent::uninstall()
&& Db::getInstance()->execute(
'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'customer_custom_fields`'
);
}
}
Ajouter des champs avec le hook `additionalCustomerFormFields`
C'est le hook central. Il permet d'injecter des objets FormField directement dans le formulaire natif, sans modifier le template :
public function hookAdditionalCustomerFormFields($params)
{
$extraFields = [];
// Champ SIRET (optionnel)
$fieldSiret = (new FormField())
->setName('company_siret')
->setType('text')
->setLabel($this->l('Numéro SIRET'))
->setRequired(false)
->addConstraint('isGenericName');
$extraFields['company_siret'] = $fieldSiret;
// Champ code client (optionnel)
$fieldCode = (new FormField())
->setName('customer_code')
->setType('text')
->setLabel($this->l('Code client (si existant)'))
->setRequired(false);
$extraFields['customer_code'] = $fieldCode;
// Liste déroulante secteur d'activité
$fieldSector = (new FormField())
->setName('activity_sector')
->setType('select')
->setLabel($this->l('Secteur d\'activité'))
->setRequired(true)
->addAvailableValue('', $this->l('-- Choisir --'))
->addAvailableValue('retail', $this->l('Commerce de détail'))
->addAvailableValue('wholesale', $this->l('Commerce de gros'))
->addAvailableValue('services', $this->l('Services'))
->addAvailableValue('industry', $this->l('Industrie'))
->addAvailableValue('other', $this->l('Autre'));
$extraFields['activity_sector'] = $fieldSector;
// Pré-remplir si le client existe déjà (édition de profil)
if ($this->context->customer && $this->context->customer->id) {
$data = $this->getCustomerData($this->context->customer->id);
if ($data) {
$fieldSiret->setValue($data['company_siret'] ?? '');
$fieldCode->setValue($data['customer_code'] ?? '');
$fieldSector->setValue($data['activity_sector'] ?? '');
}
}
return $extraFields;
}
Valider les champs personnalisés
Le hook validateCustomerFormFields permet d'ajouter une logique de validation métier :
public function hookValidateCustomerFormFields($params)
{
$errors = [];
$formFields = $params['fields'];
// Validation du SIRET (14 chiffres si renseigné)
if (isset($formFields['company_siret'])) {
$siret = $formFields['company_siret']->getValue();
if (!empty($siret) && !preg_match('/^\d{14}$/', $siret)) {
$formFields['company_siret']->addError(
$this->l('Le numéro SIRET doit contenir exactement 14 chiffres.')
);
}
}
// Vérifier que le secteur d'activité est bien sélectionné
if (isset($formFields['activity_sector'])) {
$sector = $formFields['activity_sector']->getValue();
if (empty($sector)) {
$formFields['activity_sector']->addError(
$this->l('Veuillez sélectionner votre secteur d\'activité.')
);
}
}
return $formFields;
}
Sauvegarder les données en base
public function hookActionObjectCustomerAddAfter($params)
{
$this->saveCustomerData($params['object']->id);
}
public function hookActionObjectCustomerUpdateAfter($params)
{
$this->saveCustomerData($params['object']->id);
}
private function saveCustomerData($idCustomer)
{
$siret = Tools::getValue('company_siret', '');
$code = Tools::getValue('customer_code', '');
$sector = Tools::getValue('activity_sector', '');
// Upsert : INSERT ... ON DUPLICATE KEY UPDATE
$sql = 'INSERT INTO `' . _DB_PREFIX_ . 'customer_custom_fields`
(`id_customer`, `company_siret`, `customer_code`, `activity_sector`)
VALUES ('
. (int) $idCustomer . ', '
. '\'' . pSQL($siret) . '\', '
. '\'' . pSQL($code) . '\', '
. '\'' . pSQL($sector) . '\')'
. ' ON DUPLICATE KEY UPDATE '
. '`company_siret` = \'' . pSQL($siret) . '\', '
. '`customer_code` = \'' . pSQL($code) . '\', '
. '`activity_sector` = \'' . pSQL($sector) . '\'';
return Db::getInstance()->execute($sql);
}
private function getCustomerData($idCustomer)
{
return Db::getInstance()->getRow(
'SELECT * FROM `' . _DB_PREFIX_ . 'customer_custom_fields`
WHERE `id_customer` = ' . (int) $idCustomer
);
}
Afficher les champs custom dans le back-office
Pour que les données soient visibles dans la fiche client du back-office, exploitez le hook displayAdminCustomers :
public function hookDisplayAdminCustomers($params)
{
$idCustomer = $params['id_customer'];
$data = $this->getCustomerData($idCustomer);
if (!$data) {
return '';
}
$this->context->smarty->assign([
'siret' => $data['company_siret'],
'customer_code' => $data['customer_code'],
'activity_sector' => $data['activity_sector'],
]);
return $this->display(__FILE__, 'views/templates/hook/admin-customer.tpl');
}
Spécificités PrestaShop 8.x
Sur PrestaShop 8.x, le système de formulaires a évolué avec l'adoption plus large de Symfony. Quelques points de vigilance :
- **Les hooks fonctionnent toujours** : `additionalCustomerFormFields` reste la méthode recommandée pour le front-office. La rétrocompatibilité est maintenue.
- **Back-office Symfony** : pour personnaliser le formulaire client côté admin dans PS 8.x, privilégiez les **form extensions** Symfony plutôt que les hooks legacy.
- **Validation** : PrestaShop 8.x utilise les contraintes Symfony Validator en plus des validations legacy. Votre module peut supporter les deux.
// Exemple d'extension de formulaire pour le back-office PS 8.x
use Symfony\Component\Form\AbstractTypeExtension;
use PrestaShopBundle\Form\Admin\Type\CustomerType;
class CustomerTypeExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
yield CustomerType::class;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('company_siret', TextType::class, [
'label' => 'SIRET',
'required' => false,
'constraints' => [
new Regex([
'pattern' => '/^\d{14}$/',
'message' => 'Le SIRET doit contenir 14 chiffres.',
]),
],
]);
}
}
Bonnes pratiques
Ce qu'il faut faire
- **Utiliser les hooks natifs** plutôt que des overrides de contrôleur ou de template.
- **Stocker dans une table dédiée** plutôt que d'altérer `ps_customer` directement. Cela préserve la compatibilité avec les mises à jour.
- **Valider côté serveur** systématiquement, même si vous ajoutez une validation JavaScript en front.
- **Utiliser `pSQL()`** pour échapper toutes les entrées utilisateur dans vos requêtes.
- **Penser à l'édition de profil** : le hook `additionalCustomerFormFields` est aussi appelé sur la page Mon Compte.
Ce qu'il ne faut pas faire
- **Ne jamais modifier `AuthController.php`** directement.
- **Ne pas surcharger `customer-form.tpl`** si le hook suffit — les surcharges de template compliquent les mises à jour de thème.
- **Ne pas stocker de données sensibles** (pièce d'identité, coordonnées bancaires) sans chiffrement côté base.
- **Ne pas oublier le RGPD** : tout champ supplémentaire collectant des données personnelles doit être déclaré dans votre politique de confidentialité et supprimable sur demande.
Aller plus loin : rendre les champs configurables
Pour un module réutilisable, ajoutez une page de configuration dans le back-office permettant de choisir quels champs afficher, lesquels sont obligatoires, et leur ordre d'apparition. Stockez cette configuration avec Configuration::updateValue() et chargez-la dans votre hook additionalCustomerFormFields.
Cette approche transforme un module sur-mesure en un outil générique que vous pouvez déployer sur plusieurs boutiques sans toucher au code.
Questions fréquentes
Tout ce que vous devez savoir sur ce sujet.
Un projet PrestaShop ?
Discutons-en directement.
193 projets livrés
Lire sur le blog

Alexandre Carette
Expert PrestaShop & Architecture E-commerce
Développeur PrestaShop depuis 2014, 193 projets livrés. Je conçois des architectures headless Nuxt + PrestaShop et des outils d'automatisation IA pour les e-commerçants.