💻 DéveloppementIntermédiaire PS 1.7 PS 8.x

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.

Publié le 21 mars 2026 6 min de lecture Alexandre Carette

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_product directement. Réservez ps_product_lang aux 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 Repository Doctrine 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

FichierModificationMéthode Base de données`ALTER TABLE ps_product_lang`SQL direct ou module `install()` `classes/Product.php`Propriété + `$definition`Override (1.7) ou module (8.x) `classes/Category.php`Requête SQL `getProducts()`Override si nécessaire Template frontAffichage conditionnel`product.tpl` ou hook module Formulaire adminChamp dans le formulaireHook module

Erreurs fréquentes à éviter

  1. **Oublier de vider le cache** après un override → le champ semble ne pas exister
  2. **Ne pas déclarer `lang => true`** alors que la colonne est dans `_lang` → erreur SQL silencieuse
  3. **Modifier le core directement** au lieu d'un override → perdu à la prochaine mise à jour
  4. **Oublier les requêtes SQL manuelles** dans `Category.php`, `Search.php`, etc. → le champ est vide en listing
  5. **Ne pas utiliser `nofilter` dans Smarty** pour un champ HTML → le contenu est échappé et le HTML s'affiche en texte brut
#custom field #override #Product.php #back office #champ personnalisé

Questions fréquentes

Tout ce que vous devez savoir sur ce sujet.

Un projet PrestaShop ?

Discutons-en directement.

★★★★★

193 projets livrés

Gratuit & sans engagement — réponse sous 24h

Alexandre Carette

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.