[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":22,"megamenu":103,"footer-db":160,"$flqY1bSmyHIAyJCeJhMV69SoJGAwnxFBkmpxr5dhJ72Y":178,"header-db":220,"$fAiTrw0IK8bjxhNtWxO_kmok34qXePHHvEGiyvP9GQDI":231},{"theme":4},{"colors":5,"typography":13,"ui":17,"defaultColorMode":21},{"primary":6,"secondary":7,"background":8,"foreground":9,"muted":10,"headerBg":11,"footerBg":12,"topBarBg":9,"topBarText":11},"#4F46E5","#0D9488","#F9FAFB","#111827","#6B7280","#ffffff","#020617",{"fontFamily":14,"fontUrl":15,"baseFontSize":16},"Inter, system-ui, sans-serif","https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;0,800;0,900;1,400;1,700&display=swap","16px",{"borderRadius":18,"contentWidth":19,"shadow":20},"lg","7xl",true,"light",{"columns":23},[24,40,70,91],{"title":25,"links":26},"Plateforme",[27,31,34,37],{"label":28,"href":29,"external":30},"Offre Starter (2 500 €)","\u002Foffre-starter",false,{"label":32,"href":33,"external":30},"Devenir Ambassadeur","\u002Fambassadeur",{"label":35,"href":36,"external":30},"Modules PrestaShop","\u002Fmodules",{"label":38,"href":39,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":41,"links":42},"Le Synedre",[43,46,49,52,55,58,61,64,67],{"label":44,"href":45,"external":30},"L'histoire","\u002Fsynedre",{"label":47,"href":48,"external":30},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":50,"href":51,"external":30},"L'équipe","\u002Fequipe",{"label":53,"href":54,"external":30},"Le réacteur en direct","\u002Freacteur",{"label":56,"href":57,"external":30},"Le Drill (entraînement)","\u002Fdrill",{"label":59,"href":60,"external":30},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":62,"href":63,"external":30},"Les agents IA","\u002Fagents-ia",{"label":65,"href":66,"external":30},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":68,"href":69,"external":30},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":71,"links":72},"Ressources",[73,76,79,82,85,88],{"label":74,"href":75,"external":30},"Blog","\u002Fblog",{"label":77,"href":78,"external":30},"Academy","\u002Facademy",{"label":80,"href":81,"external":30},"Dictionnaire","\u002Fdictionnaire",{"label":83,"href":84,"external":30},"Expertise PrestaShop","\u002Fexpertise",{"label":86,"href":87,"external":30},"Flywheel","\u002Fflywheel",{"label":89,"href":90,"external":30},"Manifeste","\u002Fmanifeste",{"title":92,"links":93},"À propos",[94,97,100],{"label":95,"href":96,"external":30},"Alexandre Carette","\u002Fa-propos",{"label":98,"href":99,"external":30},"Dossier de presse","\u002Fpresse",{"label":101,"href":102,"external":30},"Contact","\u002Fcontact",{"items":104},[105,114,120,126,134,142,148,154],{"id":106,"type":107,"label":108,"href":84,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":110,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":111,"children":112,"psChildren":113},41,"link",{"fr":109},"Expertise",null,0,[],[],{"id":115,"type":107,"label":116,"href":75,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":110,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":117,"children":118,"psChildren":119},42,{"fr":74},1,[],[],{"id":121,"type":107,"label":122,"href":36,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":110,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":123,"children":124,"psChildren":125},43,{"fr":35},2,[],[],{"id":127,"type":107,"label":128,"href":130,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":110,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":131,"children":132,"psChildren":133},44,{"fr":129},"Outils IA","\u002Foutils-ia",3,[],[],{"id":135,"type":107,"label":136,"href":29,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":138,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":139,"children":140,"psChildren":141},45,{"fr":137},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":143,"type":107,"label":144,"href":78,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":110,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":145,"children":146,"psChildren":147},46,{"fr":77},5,[],[],{"id":149,"type":107,"label":150,"href":96,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":110,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":151,"children":152,"psChildren":153},47,{"fr":92},6,[],[],{"id":155,"type":107,"label":156,"href":102,"icon":110,"description":110,"badge":110,"groupTitle":110,"style":110,"gridColumns":110,"cssClass":110,"psCategoryId":110,"showPsChildren":30,"position":157,"children":158,"psChildren":159},48,{"fr":101},7,[],[],{"footer":161},{"theme":162,"description":110,"hours":110,"logo":163,"contact":166,"social":167,"bottomBar":177},"dark",{"src":164,"href":165,"alt":95},"\u002Flogo-ac.svg","\u002F",{"email":110,"phone":110,"address":110,"cta":110},[168,171,174],{"platform":169,"href":170,"label":169},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":172,"href":173,"label":172},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":175,"href":176,"label":175},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":110},{"title":179,"slug":180,"metaDescription":181,"category":182,"tags":183,"difficulty":189,"psVersions":190,"content":193,"faq":194,"tldr":216,"readingTime":157,"generatedAt":217,"publishDate":217,"relatedArticles":218,"sourceCategory":219},"Ajouter des champs personnalisés au formulaire d'inscription PrestaShop via un module","ajouter-champs-personnalises-formulaire-inscription-prestashop-module","Apprenez à ajouter des champs personnalisés au formulaire d'inscription client PrestaShop sans override, grâce à un module utilisant les hooks natifs.","developpement",[184,185,186,187,188],"module prestashop","formulaire inscription","hooks prestashop","champs personnalisés","customer form","intermediaire",[191,192],"1.7","8.x","\u003Ch2>Pourquoi ajouter des champs au formulaire d'inscription ?\u003C\u002Fh2>\n\u003Cp>Le formulaire d'inscription par défaut de PrestaShop collecte le strict minimum : nom, prénom, email, mot de passe. Or, de nombreux marchands ont besoin d'informations complémentaires dès la création du compte : numéro SIRET pour le B2B, secteur d'activité, source de découverte du site, ou encore un identifiant professionnel.\u003C\u002Fp>\n\u003Cp>La tentation est forte de modifier directement la classe \u003Ccode>Customer\u003C\u002Fcode> via un override. C'est une erreur classique qui expose votre boutique à des conflits lors des mises à jour et rend la maintenance cauchemardesque dès qu'un second module touche au même fichier.\u003C\u002Fp>\n\u003Cp>La bonne approche repose sur les \u003Cstrong>hooks natifs\u003C\u002Fstrong> de PrestaShop, disponibles depuis la version 1.7, qui permettent d'étendre le formulaire client sans jamais toucher au cœur du CMS.\u003C\u002Fp>\n\u003Ch2>Architecture du module\u003C\u002Fh2>\n\u003Cp>Le module s'articule autour de trois hooks complémentaires :\u003C\u002Fp>\n\u003Ctr>\u003Cth>Hook\u003C\u002Fth>\u003Cth>Rôle\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`additionalCustomerFormFields`\u003C\u002Fth>\u003Cth>Injecte les champs supplémentaires dans le formulaire front-office\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`actionObjectCustomerAddAfter`\u003C\u002Fth>\u003Cth>Sauvegarde les données après création d'un compte\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`actionObjectCustomerUpdateAfter`\u003C\u002Fth>\u003Cth>Met à jour les données quand le client modifie son profil\u003C\u002Fth>\u003C\u002Ftr>\n\u003Cp>Cette approche respecte le cycle de vie complet du compte client : création, modification et affichage.\u003C\u002Fp>\n\u003Ch2>Structure des fichiers\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-\">\nac_customerfields\u002F\n├── ac_customerfields.php          # Fichier principal du module\n├── classes\u002F\n│   └── CustomerFieldsModel.php    # ObjectModel pour stocker les données\n├── sql\u002F\n│   ├── install.sql                # Création de la table\n│   └── uninstall.sql              # Suppression propre\n└── views\u002F\n    └── templates\u002F\n        └── admin\u002F\n            └── customer_fields.tpl # Affichage back-office (optionnel)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Étape 1 : Créer la table de stockage\u003C\u002Fh2>\n\u003Cp>Les champs personnalisés sont stockés dans une table dédiée, liée au client par son \u003Ccode>id_customer\u003C\u002Fcode>. Ne modifiez jamais la table \u003Ccode>ps_customer\u003C\u002Fcode> directement.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\nCREATE TABLE IF NOT EXISTS `PREFIX_customer_custom_fields` (\n    `id_customer_custom_fields` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,\n    `id_customer` INT(10) UNSIGNED NOT NULL,\n    `siret` VARCHAR(14) DEFAULT NULL,\n    `company_type` VARCHAR(100) DEFAULT NULL,\n    `referral_source` VARCHAR(255) DEFAULT NULL,\n    `date_add` DATETIME NOT NULL,\n    `date_upd` DATETIME NOT NULL,\n    PRIMARY KEY (`id_customer_custom_fields`),\n    UNIQUE KEY `idx_customer` (`id_customer`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\u003Cp>\u003Cstrong>Point technique :\u003C\u002Fstrong> Utilisez toujours \u003Ccode>utf8mb4\u003C\u002Fcode> et non \u003Ccode>utf8\u003C\u002Fcode> pour supporter l'intégralité des caractères Unicode. Le préfixe \u003Ccode>PREFIX_\u003C\u002Fcode> sera remplacé automatiquement par le préfixe de vos tables lors de l'installation.\u003C\u002Fp>\u003C\u002Fblockquote>\n\u003Ch2>Étape 2 : L'ObjectModel\u003C\u002Fh2>\n\u003Cp>Créez un ObjectModel propre pour manipuler vos données. C'est la couche d'abstraction standard de PrestaShop et elle vous offre validation, sanitisation et compatibilité avec le système de hooks.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\nif (!defined('_PS_VERSION_')) {\n    exit;\n}\n\nclass CustomerFieldsModel extends ObjectModel\n{\n    public $id_customer;\n    public $siret;\n    public $company_type;\n    public $referral_source;\n    public $date_add;\n    public $date_upd;\n\n    public static $definition = [\n        'table' =&gt; 'customer_custom_fields',\n        'primary' =&gt; 'id_customer_custom_fields',\n        'fields' =&gt; [\n            'id_customer' =&gt; [\n                'type' =&gt; self::TYPE_INT,\n                'validate' =&gt; 'isUnsignedId',\n                'required' =&gt; true,\n            ],\n            'siret' =&gt; [\n                'type' =&gt; self::TYPE_STRING,\n                'validate' =&gt; 'isGenericName',\n                'size' =&gt; 14,\n            ],\n            'company_type' =&gt; [\n                'type' =&gt; self::TYPE_STRING,\n                'validate' =&gt; 'isGenericName',\n                'size' =&gt; 100,\n            ],\n            'referral_source' =&gt; [\n                'type' =&gt; self::TYPE_STRING,\n                'validate' =&gt; 'isCleanHtml',\n                'size' =&gt; 255,\n            ],\n            'date_add' =&gt; [\n                'type' =&gt; self::TYPE_DATE,\n                'validate' =&gt; 'isDate',\n            ],\n            'date_upd' =&gt; [\n                'type' =&gt; self::TYPE_DATE,\n                'validate' =&gt; 'isDate',\n            ],\n        ],\n    ];\n\n    \u002F**\n     * Récupère les champs personnalisés d'un client\n     *\u002F\n    public static function getByCustomerId(int $idCustomer): ?self\n    {\n        $id = (int) Db::getInstance()-&gt;getValue(\n            'SELECT id_customer_custom_fields\n             FROM `' . _DB_PREFIX_ . 'customer_custom_fields`\n             WHERE id_customer = ' . (int) $idCustomer\n        );\n\n        if ($id) {\n            return new self($id);\n        }\n\n        return null;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Étape 3 : Le fichier principal du module\u003C\u002Fh2>\n\u003Cp>Voici le cœur du module avec l'enregistrement des hooks et la logique métier :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\nif (!defined('_PS_VERSION_')) {\n    exit;\n}\n\nrequire_once __DIR__ . '\u002Fclasses\u002FCustomerFieldsModel.php';\n\nclass ac_customerfields extends Module\n{\n    public function __construct()\n    {\n        $this-&gt;name = 'ac_customerfields';\n        $this-&gt;tab = 'administration';\n        $this-&gt;version = '1.0.0';\n        $this-&gt;author = 'Alexandre Carette';\n        $this-&gt;need_instance = 0;\n        $this-&gt;bootstrap = true;\n\n        parent::__construct();\n\n        $this-&gt;displayName = $this-&gt;l('Champs client personnalisés');\n        $this-&gt;description = $this-&gt;l('Ajoute des champs supplémentaires au formulaire d\\'inscription client.');\n        $this-&gt;ps_versions_compliancy = ['min' =&gt; '1.7.0.0', 'max' =&gt; '8.99.99'];\n    }\n\n    public function install(): bool\n    {\n        $sql = file_get_contents(__DIR__ . '\u002Fsql\u002Finstall.sql');\n        $sql = str_replace('PREFIX_', _DB_PREFIX_, $sql);\n\n        return parent::install()\n            && Db::getInstance()-&gt;execute($sql)\n            && $this-&gt;registerHook([\n                'additionalCustomerFormFields',\n                'actionObjectCustomerAddAfter',\n                'actionObjectCustomerUpdateAfter',\n                'displayAdminCustomers',\n            ]);\n    }\n\n    public function uninstall(): bool\n    {\n        $sql = file_get_contents(__DIR__ . '\u002Fsql\u002Funinstall.sql');\n        $sql = str_replace('PREFIX_', _DB_PREFIX_, $sql);\n\n        return parent::uninstall()\n            && Db::getInstance()-&gt;execute($sql);\n    }\n\n    \u002F**\n     * Hook : injecte les champs dans le formulaire d'inscription\n     *\u002F\n    public function hookAdditionalCustomerFormFields(array $params): array\n    {\n        $fields = [];\n\n        \u002F\u002F Champ SIRET\n        $fieldSiret = (new FormField())\n            -&gt;setName('siret')\n            -&gt;setType('text')\n            -&gt;setLabel($this-&gt;l('Numéro SIRET'))\n            -&gt;setRequired(false)\n            -&gt;addConstraint('isGenericName');\n\n        \u002F\u002F Si le client est connecté, pré-remplir\n        if ($this-&gt;context-&gt;customer-&gt;isLogged()) {\n            $existing = CustomerFieldsModel::getByCustomerId(\n                (int) $this-&gt;context-&gt;customer-&gt;id\n            );\n            if ($existing) {\n                $fieldSiret-&gt;setValue($existing-&gt;siret);\n            }\n        }\n\n        $fields['siret'] = $fieldSiret;\n\n        \u002F\u002F Champ source de découverte\n        $fieldSource = (new FormField())\n            -&gt;setName('referral_source')\n            -&gt;setType('select')\n            -&gt;setLabel($this-&gt;l('Comment nous avez-vous connu ?'))\n            -&gt;setRequired(false)\n            -&gt;addAvailableValue('', $this-&gt;l('-- Choisir --'))\n            -&gt;addAvailableValue('google', $this-&gt;l('Recherche Google'))\n            -&gt;addAvailableValue('social', $this-&gt;l('Réseaux sociaux'))\n            -&gt;addAvailableValue('recommendation', $this-&gt;l('Recommandation'))\n            -&gt;addAvailableValue('other', $this-&gt;l('Autre'));\n\n        $fields['referral_source'] = $fieldSource;\n\n        return $fields;\n    }\n\n    \u002F**\n     * Hook : sauvegarde après création du compte\n     *\u002F\n    public function hookActionObjectCustomerAddAfter(array $params): void\n    {\n        $this-&gt;saveCustomerFields($params['object']);\n    }\n\n    \u002F**\n     * Hook : sauvegarde après modification du profil\n     *\u002F\n    public function hookActionObjectCustomerUpdateAfter(array $params): void\n    {\n        $this-&gt;saveCustomerFields($params['object']);\n    }\n\n    \u002F**\n     * Logique commune de sauvegarde\n     *\u002F\n    private function saveCustomerFields(Customer $customer): void\n    {\n        $idCustomer = (int) $customer-&gt;id;\n        if (!$idCustomer) {\n            return;\n        }\n\n        $model = CustomerFieldsModel::getByCustomerId($idCustomer);\n        if (!$model) {\n            $model = new CustomerFieldsModel();\n            $model-&gt;id_customer = $idCustomer;\n        }\n\n        $model-&gt;siret = pSQL(Tools::getValue('siret', ''));\n        $model-&gt;referral_source = pSQL(Tools::getValue('referral_source', ''));\n        $model-&gt;save();\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Étape 4 : Afficher les données dans le back-office\u003C\u002Fh2>\n\u003Cp>Pour que les données personnalisées soient visibles depuis la fiche client du back-office, utilisez le hook \u003Ccode>displayAdminCustomers\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\npublic function hookDisplayAdminCustomers(array $params): string\n{\n    $idCustomer = (int) $params['id_customer'];\n    $model = CustomerFieldsModel::getByCustomerId($idCustomer);\n\n    if (!$model) {\n        return '';\n    }\n\n    $this-&gt;context-&gt;smarty-&gt;assign([\n        'siret' =&gt; $model-&gt;siret,\n        'company_type' =&gt; $model-&gt;company_type,\n        'referral_source' =&gt; $model-&gt;referral_source,\n    ]);\n\n    return $this-&gt;display(__FILE__, 'views\u002Ftemplates\u002Fadmin\u002Fcustomer_fields.tpl');\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Bonnes pratiques et pièges à éviter\u003C\u002Fh2>\n\u003Ch3>Pourquoi ne pas utiliser un override ?\u003C\u002Fh3>\n\u003Cp>L'override de la classe \u003Ccode>Customer\u003C\u002Fcode> est la méthode historique, mais elle présente des inconvénients majeurs :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**Conflits entre modules** : un seul override possible par classe. Si deux modules veulent modifier `Customer`, l'un des deux sera ignoré.\u003C\u002Fli>\n\u003Cli>**Mises à jour risquées** : lors d'une montée de version, l'override peut devenir incompatible silencieusement.\u003C\u002Fli>\n\u003Cli>**Maintenance complexe** : le code est dispersé entre le module et le dossier `\u002Foverride\u002F`.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Avec les hooks, chaque module est autonome et désinstallable proprement.\u003C\u002Fp>\n\u003Ch3>Validation côté serveur\u003C\u002Fh3>\n\u003Cp>Ne faites jamais confiance aux données du formulaire. Le hook \u003Ccode>additionalCustomerFormFields\u003C\u002Fcode> permet de définir des contraintes via \u003Ccode>addConstraint()\u003C\u002Fcode>, mais ajoutez également une validation dans votre méthode de sauvegarde :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Validation du SIRET (14 chiffres)\n$siret = Tools::getValue('siret', '');\nif (!empty($siret) && !preg_match('\u002F^[0-9]{14}$\u002F', $siret)) {\n    \u002F\u002F Gérer l'erreur\n    return;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Compatibilité PrestaShop 8.x\u003C\u002Fh3>\n\u003Cp>Sur PrestaShop 8.x, le système de hooks reste identique, mais quelques points d'attention :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>La classe `FormField` est toujours disponible nativement, pas besoin de `use` supplémentaire dans le contexte d'un module classique.\u003C\u002Fli>\n\u003Cli>PrestaShop 8 utilise Symfony plus largement côté back-office. Pour une intégration back-office avancée, envisagez un `AdminController` basé sur Symfony plutôt que Smarty.\u003C\u002Fli>\n\u003Cli>Le hook `displayAdminCustomers` fonctionne toujours, mais PrestaShop 8.1+ encourage l'utilisation des hooks Symfony (`CustomerFormDataProvider`) pour les formulaires admin.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Migration depuis un override existant\u003C\u002Fh3>\n\u003Cp>Si vous avez déjà un override en place :\u003C\u002Fp>\n\u003Col>\n\u003Cli>Installez d'abord le module sur un environnement de test\u003C\u002Fli>\n\u003Cli>Migrez les données de la colonne ajoutée dans `ps_customer` vers votre nouvelle table\u003C\u002Fli>\n\u003Cli>Supprimez l'override (`\u002Foverride\u002Fclasses\u002FCustomer.php`)\u003C\u002Fli>\n\u003Cli>Videz le cache de classes (`\u002Fvar\u002Fcache\u002F` ou via back-office)\u003C\u002Fli>\n\u003Cli>Vérifiez que le fichier `\u002Fapp\u002Fcache\u002Fclass_index.php` a été régénéré\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>Script de migration des données\u003C\u002Fh2>\n\u003Cp>Si vous passez d'un override qui stockait les données directement dans \u003Ccode>ps_customer\u003C\u002Fcode> vers cette approche modulaire :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\nINSERT INTO `ps_customer_custom_fields` (id_customer, siret, date_add, date_upd)\nSELECT id_customer, siret, NOW(), NOW()\nFROM `ps_customer`\nWHERE siret IS NOT NULL AND siret != '';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Résultat attendu\u003C\u002Fh2>\n\u003Cp>Après installation du module, le formulaire d'inscription affiche automatiquement les champs supplémentaires. Les données sont sauvegardées dans une table dédiée, consultables depuis la fiche client en back-office, et le tout est désinstallable proprement sans laisser de traces dans le cœur de PrestaShop.\u003C\u002Fp>",[195,198,201,204,207,210,213],{"q":196,"a":197},"Comment ajouter un champ obligatoire au formulaire d'inscription PrestaShop ?","Utilisez la méthode setRequired(true) sur l'objet FormField dans le hook additionalCustomerFormFields. PrestaShop gère automatiquement la validation côté front-office et affiche un message d'erreur si le champ est vide. Côté serveur, ajoutez également une vérification dans votre méthode de sauvegarde pour ne jamais faire confiance uniquement à la validation JavaScript.",{"q":199,"a":200},"Est-il possible d'ajouter des champs personnalisés sans module, directement dans le thème ?","Techniquement oui, en modifiant le template du formulaire d'inscription et en interceptant les données via un override. Mais cette approche est fortement déconseillée : elle ne survivra pas aux mises à jour du thème, rend la maintenance complexe et ne permet pas de réutiliser la logique sur d'autres boutiques. Un module dédié avec les hooks natifs est toujours la bonne approche.",{"q":202,"a":203},"Le hook additionalCustomerFormFields fonctionne-t-il sur PrestaShop 8 ?","Oui, ce hook est disponible depuis PrestaShop 1.7 et reste pleinement fonctionnel sur PrestaShop 8.x. Il est intégré au CustomerFormatter qui construit dynamiquement le formulaire d'inscription. Aucune modification n'est nécessaire pour assurer la compatibilité entre les versions 1.7 et 8.x.",{"q":205,"a":206},"Comment afficher les champs personnalisés dans l'export CSV des clients ?","Utilisez le hook actionAdminCustomersListingFieldsModifier pour ajouter vos colonnes à la liste des clients en back-office. Vous pouvez joindre votre table personnalisée via une requête SQL dans ce hook, ce qui rendra les données disponibles dans la liste et dans l'export CSV natif de PrestaShop.",{"q":208,"a":209},"Peut-on ajouter un champ de type fichier (upload) au formulaire d'inscription ?","Le hook additionalCustomerFormFields supporte les types text, select, checkbox et radio. Pour un champ fichier, il faut combiner le hook avec un traitement personnalisé : ajoutez un champ HTML via le type text avec un template personnalisé, puis récupérez le fichier uploadé dans le hook actionObjectCustomerAddAfter via la superglobale $_FILES. Stockez le fichier dans un répertoire dédié de votre module et enregistrez le chemin en base.",{"q":211,"a":212},"Comment rendre un champ personnalisé visible uniquement pour les clients professionnels (B2B) ?","Dans le hook additionalCustomerFormFields, vérifiez le groupe du client connecté avant d'ajouter le champ. Pour les nouveaux inscrits, vous pouvez conditionner l'affichage via JavaScript en écoutant le changement d'un champ type de compte (particulier\u002Fprofessionnel) si votre formulaire propose cette distinction. Côté serveur, filtrez toujours dans le hook pour ne sauvegarder les données B2B que si le contexte le justifie.",{"q":214,"a":215},"Pourquoi mes champs personnalisés disparaissent après une mise à jour de PrestaShop ?","Si vos champs disparaissent après une mise à jour, c'est probablement que vous utilisez un override plutôt qu'un module avec hooks. Les overrides peuvent être écrasés lors des mises à jour. Avec un module basé sur le hook additionalCustomerFormFields, les champs sont injectés dynamiquement et survivent à toute mise à jour du cœur ou du thème, tant que le module reste actif.","Pour ajouter des champs au formulaire d'inscription PrestaShop, créez un module utilisant le hook additionalCustomerFormFields plutôt qu'un override de la classe Customer. Cette approche est compatible 1.7 à 8.x, sans conflit entre modules et désinstallable proprement.","2026-03-21T16:01:59.000Z",[],"PrestaShop pour les développeurs",{"header":221},{"logo":222,"topBar":225,"contactEmail":228,"features":229,"navBar":110},{"src":164,"alt":223,"text":95,"href":165,"class":224},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":110,"showLanguages":30,"align":226,"languages":227},"left",[],"contact@alexandrecarette.fr",{"showSearch":30,"showWishlist":30,"showLogin":20,"showContact":30,"showCart":30,"stickyHeader":20,"headerLayout":230},"inline",{"academy":232,"blog":233,"expertise":244},[],[234,238,241],{"title":235,"url":236,"score":117,"type":237},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":239,"url":240,"score":117,"type":237},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":242,"url":243,"score":117,"type":237},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[]]