Ajouter un champ personnalisé produit dans PrestaShop (back office et front)
Guide complet pour créer un custom field produit dans PrestaShop 1.7 et 8.x : base de données, classe Product, formulaire admin et affichage front.
En bref : Pour ajouter un champ personnalisé produit dans PrestaShop, il faut intervenir à 4 niveaux : colonne SQL dans ps_product_lang, déclaration dans la classe Product ($definition), ajout dans les requêtes SQL du catalogue (Category::getProducts), et affichage dans les templates. Sur PS 8.x, privilégiez un module avec les hooks Symfony plutôt qu'un override.
Introduction
Ajouter un champ personnalisé à la fiche produit PrestaShop est l'un des besoins les plus fréquents en développement e-commerce. Que ce soit pour stocker une référence fournisseur spécifique, un argumentaire technique ou une donnée métier propre à votre catalogue, la mécanique reste la même : intervenir sur la base de données, la classe Product, le formulaire back office et l'affichage front office.
Ce guide couvre la méthode complète, testée de PrestaShop 1.7 à 8.x, avec les bonnes pratiques pour chaque version.
Étape 1 : Ajouter la colonne en base de données
Le champ personnalisé doit être multilingue dans la majorité des cas (descriptions, argumentaires, labels). On l'ajoute donc dans la table ps_product_lang :
ALTER TABLE `ps_product_lang`
ADD COLUMN `custom_field` TEXT DEFAULT NULL
AFTER `available_later`;
Bonne pratique : Si votre champ n'a pas besoin de traduction (un code EAN fournisseur, par exemple), ajoutez-le plutôt dans
ps_productdirectement. Réservezps_product_langaux données qui varient selon la langue.
Pourquoi TEXT et pas VARCHAR ?
Utilisez TEXT si le contenu peut dépasser 255 caractères (descriptions techniques, HTML). Pour un simple label court, un VARCHAR(255) sera plus performant en indexation.
Étape 2 : Déclarer le champ dans la classe Product
PrestaShop utilise un ORM maison basé sur ObjectModel. Pour que votre champ soit reconnu, deux modifications sont nécessaires dans la classe Product.
Déclarer la propriété
// classes/Product.php (ou override)
public $custom_field;
Ajouter la définition dans `$definition`
Dans le tableau $definition['fields'], section des champs multilingues :
'custom_field' => [
'type' => self::TYPE_HTML,
'lang' => true,
'validate' => 'isCleanHtml',
'size' => 65535,
],
Note importante sur les types de validation :
-
self::TYPE_STRING+isGenericName: texte court sans HTML
-
self::TYPE_HTML+isCleanHtml: contenu riche avec HTML autorisé
-
self::TYPE_STRING+isReference: codes alphanumériques stricts
>
Choisissez le type de validation adapté à votre usage. Un champ qui accepte du HTML mal validé est un vecteur XSS.
Étape 3 : Override vs modification directe
PrestaShop 1.7 : le système d'override classique
Sur PrestaShop 1.7, le mécanisme d'override de classes fonctionne en plaçant un fichier dans override/classes/Product.php :
<?php
class Product extends ProductCore
{
public $custom_field;
public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, Context $context = null)
{
// Injecter la définition avant le constructeur parent
self::$definition['fields']['custom_field'] = [
'type' => self::TYPE_HTML,
'lang' => true,
'validate' => 'isCleanHtml',
];
parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
}
}
Après création de l'override, supprimez le fichier cache :
rm var/cache/prod/class_index.php
rm var/cache/dev/class_index.php
PrestaShop 8.x : privilégiez un module
Depuis PrestaShop 8, la recommandation officielle est de ne plus utiliser les overrides pour les classes core. Préférez un module qui utilise les hooks Symfony :
// modules/mymodule/mymodule.php
public function install()
{
return parent::install()
&& $this->registerHook('actionProductFormBuilderModifier')
&& $this->registerHook('actionAfterUpdateProductFormHandler')
&& $this->registerHook('actionAfterCreateProductFormHandler')
&& $this->installSql();
}
private function installSql()
{
$sql = 'ALTER TABLE `' . _DB_PREFIX_ . 'product_lang`
ADD COLUMN IF NOT EXISTS `custom_field` TEXT DEFAULT NULL';
return Db::getInstance()->execute($sql);
}
Pour le formulaire back office sous Symfony (PS 8.x), utilisez le hook actionProductFormBuilderModifier :
public function hookActionProductFormBuilderModifier(array $params)
{
$formBuilder = $params['form_builder'];
$productId = $params['id'];
$formBuilder->add('custom_field', TextareaType::class, [
'label' => $this->l('Mon champ personnalisé'),
'required' => false,
'attr' => ['rows' => 5],
]);
// Pré-remplir avec la valeur existante
$params['data']['custom_field'] = $this->getCustomFieldValue($productId);
$formBuilder->setData($params['data']);
}
Étape 4 : Afficher le champ dans les requêtes SQL du catalogue
Un piège classique : vous ajoutez le champ en base et dans la classe, mais il n'apparaît pas en front. C'est parce que les requêtes SQL de PrestaShop sélectionnent explicitement les colonnes.
Dans la classe Category, la méthode getProducts() contient une requête SQL qui liste les champs de ps_product_lang. Il faut y ajouter votre champ :
-- Extrait de la requête Category::getProducts()
SELECT p.*, product_shop.*, ...
pl.`description`, pl.`description_short`,
pl.`available_now`, pl.`available_later`,
pl.`link_rewrite`, pl.`meta_description`,
pl.`meta_keywords`, pl.`meta_title`,
pl.`name`, pl.`custom_field`, -- Ajout ici
image_shop.`id_image` id_image, ...
Cette même logique s'applique à d'autres méthodes qui construisent des requêtes manuelles : Product::getProductsProperties(), Search::find(), etc.
Attention : En PrestaShop 8.x avec Doctrine, certaines de ces requêtes sont gérées différemment. Vérifiez si un
RepositoryDoctrine n'a pas remplacé la requête SQL brute.
Étape 5 : Afficher le champ en front office
Dans votre template Smarty (PS 1.7) ou Twig (PS 8.x module), le champ est accessible via l'objet produit.
Template Smarty (thème classique)
{* templates/catalog/product.tpl *}
{if $product.custom_field}
<div class="product-custom-field">
<h3>Information complémentaire</h3>
<div>{$product.custom_field nofilter}</div>
</div>
{/if}
Assignation Smarty dans un controller
Si le champ n'est pas automatiquement disponible dans le template, vous pouvez l'assigner via un override du ProductController :
public function initContent()
{
parent::initContent();
$product = $this->context->controller->getTemplateVarProduct();
// Le champ est normalement déjà dans $product si la classe est bien configurée
}
Il n'est généralement pas nécessaire d'assigner manuellement une variable à Smarty si le champ est correctement déclaré dans $definition avec lang => true. L'ORM de PrestaShop le charge automatiquement.
Étape 6 : Formulaire back office (PrestaShop 1.7 legacy)
Sur PrestaShop 1.7 avec le formulaire legacy (AdminProductsController), le formulaire produit est rendu par renderForm(). L'approche la plus propre est d'utiliser un hook dans un module :
public function hookDisplayAdminProductsMainStepLeftColumnMiddle($params)
{
$productId = (int) $params['id_product'];
$languages = Language::getLanguages(true);
$product = new Product($productId);
$this->context->smarty->assign([
'custom_field' => $product->custom_field,
'languages' => $languages,
'default_language' => Configuration::get('PS_LANG_DEFAULT'),
]);
return $this->display(__FILE__, 'views/templates/hook/custom_field.tpl');
}
Récapitulatif des fichiers modifiés
Erreurs fréquentes à éviter
- **Oublier de vider le cache** après un override → le champ semble ne pas exister
- **Ne pas déclarer `lang => true`** alors que la colonne est dans `_lang` → erreur SQL silencieuse
- **Modifier le core directement** au lieu d'un override → perdu à la prochaine mise à jour
- **Oublier les requêtes SQL manuelles** dans `Category.php`, `Search.php`, etc. → le champ est vide en listing
- **Ne pas utiliser `nofilter` dans Smarty** pour un champ HTML → le contenu est échappé et le HTML s'affiche en texte brut
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.