[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":22,"$fwMZ68UG9ffadUhQHBY-dy2XxzyUhz1Nzf7MzcjXGW2Y":103,"footer-db":149,"megamenu":168,"header-db":224,"$f_OPlDbzqjHGrlBRa6Eidokx32DaLCCuokB2M9j-K_is":235},{"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",{"title":104,"slug":105,"metaDescription":106,"category":107,"tags":108,"difficulty":116,"psVersions":117,"content":121,"faq":122,"tldr":144,"readingTime":145,"generatedAt":146,"publishDate":146,"relatedArticles":147,"sourceCategory":148},"Implémenter un système de prix libre sur PrestaShop (Name Your Price)","prix-libre-client-choisit-prix-prestashop","Guide technique pour créer un système de prix libre sur PrestaShop : override Product, validation sécurisée, formulaire front-end et bonnes pratiques 8.x.","developpement",[109,110,111,112,113,114,115],"override","prix","Product","ProductController","formulaire","validation","name-your-price","intermediaire",[118,119,120],"1.6","1.7","8.x","\u003Ch2>Pourquoi proposer un prix libre sur PrestaShop ?\u003C\u002Fh2>\n\u003Cp>Le concept de \u003Cstrong>prix libre\u003C\u002Fstrong> (ou *Name Your Price*) permet au client de définir lui-même le montant qu'il souhaite payer pour un produit. Ce mécanisme trouve sa place dans plusieurs contextes e-commerce :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**Dons et associations** : laisser le visiteur choisir le montant de sa contribution\u003C\u002Fli>\n\u003Cli>**Produits numériques** : ebooks, templates, musique — le client paie ce qu'il estime juste\u003C\u002Fli>\n\u003Cli>**Ventes solidaires** : prix plancher garanti, mais liberté au-delà\u003C\u002Fli>\n\u003Cli>**Tests de pricing** : mesurer la valeur perçue d'un produit par le marché\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>PrestaShop ne propose pas cette fonctionnalité nativement. La solution technique repose sur un \u003Cstrong>override du contrôleur produit\u003C\u002Fstrong>, une \u003Cstrong>méthode de mise à jour du prix\u003C\u002Fstrong> dans la classe \u003Ccode>Product\u003C\u002Fcode>, et un \u003Cstrong>formulaire front-end\u003C\u002Fstrong> avec validation stricte.\u003C\u002Fp>\n\u003Ch2>Architecture de la solution\u003C\u002Fh2>\n\u003Cp>La mise en œuvre s'articule en trois couches :\u003C\u002Fp>\n\u003Col>\n\u003Cli>**Classe `Product`** — nouvelle méthode statique pour mettre à jour le prix en base\u003C\u002Fli>\n\u003Cli>**Contrôleur `ProductController`** — interception du formulaire et validation des données\u003C\u002Fli>\n\u003Cli>**Template front-end** — formulaire de saisie du prix avec feedback utilisateur\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cblockquote>\u003Cp>\u003Cstrong>Remarque importante :\u003C\u002Fstrong> cette approche modifie le prix du produit en base de données. Elle convient pour un usage où chaque client « fixe » son prix avant ajout au panier. Pour un usage multi-visiteurs simultanés, il faudra adapter la logique (voir la section sur les alternatives en fin d'article).\u003C\u002Fp>\u003C\u002Fblockquote>\n\u003Ch2>Étape 1 : Override de la classe Product\u003C\u002Fh2>\n\u003Cp>Créez le fichier d'override pour ajouter une méthode de mise à jour du prix.\u003C\u002Fp>\n\u003Ch3>PrestaShop 1.6\u003C\u002Fh3>\n\u003Cp>Fichier : \u003Ccode>override\u002Fclasses\u002FProduct.php\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F**\n * @author Alexandre Carette &lt;contact@alexandrecarette.fr&gt;\n * @copyright 2026 Alexandre Carette\n * @license Propriétaire et Confidentiel\n *\u002F\n\nclass Product extends ProductCore\n{\n    \u002F**\n     * Met à jour le prix d'un produit dans toutes les tables concernées\n     *\n     * @param int $idProduct ID du produit\n     * @param float $price Nouveau prix HT\n     * @return bool\n     *\u002F\n    public static function updateCustomPrice($idProduct, $price)\n    {\n        $idProduct = (int) $idProduct;\n        $price = (float) $price;\n\n        \u002F\u002F Mise à jour dans ps_product\n        $sql1 = 'UPDATE `' . _DB_PREFIX_ . 'product`\n                  SET `price` = ' . $price . '\n                  WHERE `id_product` = ' . $idProduct;\n\n        \u002F\u002F Mise à jour dans ps_product_shop (multiboutique)\n        $sql2 = 'UPDATE `' . _DB_PREFIX_ . 'product_shop`\n                  SET `price` = ' . $price . '\n                  WHERE `id_product` = ' . $idProduct;\n\n        $db = Db::getInstance();\n\n        if (!$db-&gt;execute($sql1) || !$db-&gt;execute($sql2)) {\n            return false;\n        }\n\n        \u002F\u002F Vider le cache produit pour refléter le nouveau prix\n        Cache::clean('Product::getPriceStatic_' . $idProduct . '_*');\n\n        return true;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Points critiques de cette implémentation\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>Utilisation du préfixe de table\u003C\u002Fstrong> : ne jamais écrire \u003Ccode>ps_product\u003C\u002Fcode> en dur. La constante \u003Ccode>_DB_PREFIX_\u003C\u002Fcode> garantit la compatibilité avec toute installation PrestaShop, quel que soit le préfixe configuré.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Cast des paramètres\u003C\u002Fstrong> : le \u003Ccode>(int)\u003C\u002Fcode> et \u003Ccode>(float)\u003C\u002Fcode> sont la première ligne de défense contre les injections SQL. Même si la validation se fait en amont dans le contrôleur, la méthode doit être autonome en termes de sécurité.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Table \u003Ccode>product_shop\u003C\u002Fcode>\u003C\u002Fstrong> : en contexte multiboutique, le prix est stocké à la fois dans \u003Ccode>ps_product\u003C\u002Fcode> et \u003Ccode>ps_product_shop\u003C\u002Fcode>. Oublier l'une des deux tables provoque des incohérences difficiles à diagnostiquer.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Invalidation du cache\u003C\u002Fstrong> : PrestaShop met en cache les prix calculés. Sans invalidation, l'ancien prix reste affiché jusqu'à l'expiration du cache.\u003C\u002Fp>\n\u003Ch3>PrestaShop 8.x — Approche modernisée\u003C\u002Fh3>\n\u003Cp>Sur PrestaShop 8.x, les overrides restent supportés mais la bonne pratique est de passer par un \u003Cstrong>module\u003C\u002Fstrong>. Voici l'équivalent propre :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F\u002F modules\u002Fmonmodule\u002Fsrc\u002FService\u002FCustomPriceUpdater.php\n\nnamespace MonModule\\Service;\n\nuse Db;\nuse Cache;\n\nclass CustomPriceUpdater\n{\n    public function updatePrice(int $idProduct, float $price, int $idShop = null): bool\n    {\n        if ($idProduct &lt;= 0 || $price &lt; 0) {\n            return false;\n        }\n\n        $db = Db::getInstance();\n\n        $result = $db-&gt;update('product', [\n            'price' =&gt; $price,\n        ], 'id_product = ' . $idProduct);\n\n        $shopCondition = $idShop\n            ? 'id_product = ' . $idProduct . ' AND id_shop = ' . (int) $idShop\n            : 'id_product = ' . $idProduct;\n\n        $result &= $db-&gt;update('product_shop', [\n            'price' =&gt; $price,\n        ], $shopCondition);\n\n        \u002F\u002F Invalider le cache Symfony + cache PS natif\n        Cache::clean('Product::getPriceStatic_' . $idProduct . '_*');\n\n        return (bool) $result;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>L'utilisation de \u003Ccode>Db::update()\u003C\u002Fcode> avec un tableau associatif est plus lisible et bénéficie de l'échappement automatique de PrestaShop.\u003C\u002Fp>\n\u003Ch2>Étape 2 : Override du ProductController\u003C\u002Fh2>\n\u003Cp>Le contrôleur intercepte la soumission du formulaire, valide les données et appelle la méthode de mise à jour.\u003C\u002Fp>\n\u003Cp>Fichier : \u003Ccode>override\u002Fcontrollers\u002Ffront\u002FProductController.php\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F**\n * @author Alexandre Carette &lt;contact@alexandrecarette.fr&gt;\n * @copyright 2026 Alexandre Carette\n * @license Propriétaire et Confidentiel\n *\u002F\n\nclass ProductController extends ProductControllerCore\n{\n    public function postProcess()\n    {\n        \u002F\u002F Appel du traitement parent (ajout panier, etc.)\n        parent::postProcess();\n\n        if (Tools::isSubmit('isChangePrice')) {\n            $this-&gt;processCustomPrice();\n        }\n    }\n\n    protected function processCustomPrice()\n    {\n        $idProduct = (int) Tools::getValue('id_product');\n        $prix = Tools::getValue('prix');\n\n        \u002F\u002F --- Validation stricte ---\n\n        \u002F\u002F Le champ prix est-il rempli ?\n        if (empty($prix)) {\n            $this-&gt;errors[] = $this-&gt;trans(\n                'Veuillez saisir un prix.',\n                [],\n                'Shop.Notifications.Error'\n            );\n            return;\n        }\n\n        \u002F\u002F Le format est-il un prix valide ?\n        if (!Validate::isPrice($prix)) {\n            $this-&gt;errors[] = $this-&gt;trans(\n                'Le format du prix n\\'est pas valide.',\n                [],\n                'Shop.Notifications.Error'\n            );\n            return;\n        }\n\n        $prix = (float) $prix;\n\n        \u002F\u002F Bornes de prix (à adapter selon votre besoin)\n        $prixMin = 10.0;\n        $prixMax = 30.0;\n\n        if ($prix &lt;= $prixMin) {\n            $this-&gt;errors[] = $this-&gt;trans(\n                'Le prix doit être supérieur à %min% €.',\n                ['%min%' =&gt; $prixMin],\n                'Shop.Notifications.Error'\n            );\n            return;\n        }\n\n        if ($prix &gt;= $prixMax) {\n            $this-&gt;errors[] = $this-&gt;trans(\n                'Le prix doit être inférieur à %max% €.',\n                ['%max%' =&gt; $prixMax],\n                'Shop.Notifications.Error'\n            );\n            return;\n        }\n\n        \u002F\u002F Le produit existe-t-il ?\n        if (!Validate::isLoadedObject(new Product($idProduct))) {\n            $this-&gt;errors[] = $this-&gt;trans(\n                'Produit introuvable.',\n                [],\n                'Shop.Notifications.Error'\n            );\n            return;\n        }\n\n        \u002F\u002F --- Mise à jour ---\n        if (Product::updateCustomPrice($idProduct, $prix)) {\n            $this-&gt;context-&gt;smarty-&gt;assign('confirm', true);\n            \u002F\u002F Redirection propre pour éviter le double-submit\n            Tools::redirect(\n                $this-&gt;context-&gt;link-&gt;getProductLink($idProduct)\n                . '?price_updated=1'\n            );\n        } else {\n            $this-&gt;errors[] = $this-&gt;trans(\n                'Erreur lors de la mise à jour du prix.',\n                [],\n                'Shop.Notifications.Error'\n            );\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Détail des validations\u003C\u002Fh3>\n\u003Ctr>\u003Cth>Validation\u003C\u002Fth>\u003Cth>Méthode\u003C\u002Fth>\u003Cth>Rôle\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Champ vide\u003C\u002Fth>\u003Cth>`empty()`\u003C\u002Fth>\u003Cth>Empêche la soumission sans valeur\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Format prix\u003C\u002Fth>\u003Cth>`Validate::isPrice()`\u003C\u002Fth>\u003Cth>Vérifie que la chaîne est un nombre décimal valide\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Borne basse\u003C\u002Fth>\u003Cth>Comparaison `\u003C=`\u003C\u002Fth>\u003Cth>Garantit un prix minimum (protection marchande)\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Borne haute\u003C\u002Fth>\u003Cth>Comparaison `>=`\u003C\u002Fth>\u003Cth>Évite les abus (prix déraisonnablement élevé)\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Produit valide\u003C\u002Fth>\u003Cth>`Validate::isLoadedObject()`\u003C\u002Fth>\u003Cth>Protection contre la manipulation du champ caché `id_product`\u003C\u002Fth>\u003C\u002Ftr>\n\u003Cp>\u003Cstrong>Sécurité renforcée\u003C\u002Fstrong> : la validation native \u003Ccode>Validate::isPrice()\u003C\u002Fcode> de PrestaShop vérifie le format (\u003Ccode>\u002F^[0-9]{1,10}(\\.[0-9]{1,9})?$\u002F\u003C\u002Fcode>). Combinée au cast \u003Ccode>(int)\u003C\u002Fcode> sur l'ID produit et \u003Ccode>(float)\u003C\u002Fcode> sur le prix, cette chaîne de validation protège contre les injections SQL.\u003C\u002Fp>\n\u003Ch2>Étape 3 : Template front-end\u003C\u002Fh2>\n\u003Ch3>PrestaShop 1.6 (Smarty)\u003C\u002Fh3>\n\u003Cp>Ajoutez ce bloc dans \u003Ccode>themes\u002Fvotre-theme\u002Fproduct.tpl\u003C\u002Fcode>, à l'emplacement souhaité (typiquement sous le prix affiché) :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-smarty\">\n{* Formulaire de prix libre *}\n&lt;div class=\"custom-price-form\"&gt;\n    &lt;h3&gt;{l s='Choisissez votre prix'}&lt;\u002Fh3&gt;\n    &lt;p class=\"price-hint\"&gt;\n        {l s='Vous pouvez définir un prix entre'}\n        &lt;strong&gt;11 €&lt;\u002Fstrong&gt; {l s='et'} &lt;strong&gt;29 €&lt;\u002Fstrong&gt;\n    &lt;\u002Fp&gt;\n\n    {if isset($confirm) && $confirm}\n        &lt;div class=\"alert alert-success\"&gt;\n            {l s='Prix mis à jour avec succès !'}\n        &lt;\u002Fdiv&gt;\n    {\u002Fif}\n\n    {if isset($errors) && $errors|@count &gt; 0}\n        &lt;div class=\"alert alert-danger\"&gt;\n            &lt;ul&gt;\n                {foreach from=$errors item=error}\n                    &lt;li&gt;{$error}&lt;\u002Fli&gt;\n                {\u002Fforeach}\n            &lt;\u002Ful&gt;\n        &lt;\u002Fdiv&gt;\n    {\u002Fif}\n\n    &lt;form action=\"{$link-&gt;getProductLink($product)}\" method=\"post\" class=\"form-inline\"&gt;\n        &lt;input type=\"hidden\" value=\"{$product-&gt;id}\" name=\"id_product\"&gt;\n        &lt;div class=\"form-group\"&gt;\n            &lt;label for=\"custom-price\"&gt;{l s='Votre prix (€ HT)'}&lt;\u002Flabel&gt;\n            &lt;input\n                type=\"number\"\n                id=\"custom-price\"\n                name=\"prix\"\n                min=\"11\"\n                max=\"29\"\n                step=\"0.01\"\n                class=\"form-control\"\n                placeholder=\"15.00\"\n                required\n            &gt;\n        &lt;\u002Fdiv&gt;\n        &lt;button type=\"submit\" name=\"isChangePrice\" class=\"btn btn-primary\"&gt;\n            {l s='Valider mon prix'}\n        &lt;\u002Fbutton&gt;\n    &lt;\u002Fform&gt;\n&lt;\u002Fdiv&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>PrestaShop 1.7 \u002F 8.x (Twig via module)\u003C\u002Fh3>\n\u003Cp>Pour les versions modernes, le formulaire s'intègre via un hook dans un module :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-twig\">\n{# views\u002Ftemplates\u002Fhook\u002Fcustom-price-form.tpl #}\n{# Ou en Twig si module Symfony : templates\u002Ffront\u002Fcustom-price.html.twig #}\n\n&lt;div class=\"custom-price-form card mt-3 p-3\"&gt;\n    &lt;h3 class=\"h5\"&gt;{{ 'Choisissez votre prix'|trans({}, 'Modules.Monmodule.Shop') }}&lt;\u002Fh3&gt;\n\n    {% if app.request.query.get('price_updated') %}\n        &lt;div class=\"alert alert-success\"&gt;\n            {{ 'Prix mis à jour avec succès !'|trans({}, 'Modules.Monmodule.Shop') }}\n        &lt;\u002Fdiv&gt;\n    {% endif %}\n\n    &lt;form method=\"post\" action=\"{{ product_url }}\"&gt;\n        &lt;input type=\"hidden\" name=\"id_product\" value=\"{{ product.id }}\"&gt;\n        &lt;div class=\"form-group\"&gt;\n            &lt;label for=\"custom-price\"&gt;{{ 'Votre prix (€ HT)'|trans({}, 'Modules.Monmodule.Shop') }}&lt;\u002Flabel&gt;\n            &lt;input\n                type=\"number\"\n                id=\"custom-price\"\n                name=\"prix\"\n                min=\"{{ price_min }}\"\n                max=\"{{ price_max }}\"\n                step=\"0.01\"\n                class=\"form-control\"\n                required\n            &gt;\n        &lt;\u002Fdiv&gt;\n        &lt;button type=\"submit\" name=\"isChangePrice\" class=\"btn btn-primary mt-2\"&gt;\n            {{ 'Valider mon prix'|trans({}, 'Modules.Monmodule.Shop') }}\n        &lt;\u002Fbutton&gt;\n    &lt;\u002Fform&gt;\n&lt;\u002Fdiv&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Limiter le prix libre à une catégorie spécifique\u003C\u002Fh2>\n\u003Cp>Dans de nombreux cas, seule une catégorie de produits doit proposer le prix libre (par exemple, une catégorie « Dons » ou « Prix libre »). La condition porte sur la \u003Cstrong>catégorie par défaut\u003C\u002Fstrong> du produit :\u003C\u002Fp>\n\u003Ch3>En Smarty (1.6)\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-smarty\">\n{if $product-&gt;id_category_default == 42}\n    {* Afficher le formulaire de prix libre *}\n    {include file=\".\u002Fcustom-price-form.tpl\"}\n{\u002Fif}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>En PHP (contrôleur ou module)\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Vérifier si le produit appartient à la catégorie \"prix libre\"\n$idCategoryPrixLibre = (int) Configuration::get('MON_MODULE_CATEGORY_FREE_PRICE');\n\nif ((int) $product-&gt;id_category_default === $idCategoryPrixLibre) {\n    \u002F\u002F Afficher le formulaire\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Stocke l'ID de catégorie dans la configuration du module (\u003Ccode>Configuration::updateValue()\u003C\u002Fcode>) plutôt que de le coder en dur. Cela permet de le modifier depuis le back-office sans toucher au code.\u003C\u002Fp>\n\u003Ch2>Bonnes pratiques et points de vigilance\u003C\u002Fh2>\n\u003Ch3>Sécurité\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>**Token CSRF** : ajoutez un token anti-CSRF dans le formulaire. PrestaShop 1.7+ le gère nativement via `$this->context->controller->getToken()`.\u003C\u002Fli>\n\u003Cli>**Validation côté serveur ET client** : l'attribut HTML `min`\u002F`max` sur l'input est un confort UX, mais ne remplace jamais la validation PHP.\u003C\u002Fli>\n\u003Cli>**Ne jamais utiliser `die()`** : dans un contexte web, `die('Erreur')` affiche un message brut sans mise en page. Utilisez `$this->errors[]` pour une gestion propre des erreurs.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Performance\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>**Invalidation de cache** : après la mise à jour du prix, il faut invalider le cache produit. Sans cela, les pages catégorie et les blocs de prix afficheront l'ancien montant.\u003C\u002Fli>\n\u003Cli>**Attention au multiboutique** : en contexte multi-shop, filtrez la mise à jour par `id_shop` pour ne pas impacter toutes les boutiques.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Limites de l'approche par mise à jour directe\u003C\u002Fh3>\n\u003Cp>Cette technique modifie le prix du produit \u003Cstrong>en base de données\u003C\u002Fstrong>. Cela signifie que :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Si deux clients visitent le produit simultanément, le dernier prix soumis écrase le précédent\u003C\u002Fli>\n\u003Cli>L'historique des prix n'est pas conservé\u003C\u002Fli>\n\u003Cli>Les règles de prix spécifiques (promotions, groupes clients) peuvent entrer en conflit\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Alternative recommandée pour la production\u003C\u002Fh3>\n\u003Cp>Pour un usage en production avec du trafic concurrent, privilégiez une approche par \u003Cstrong>prix spécifique lié au panier\u003C\u002Fstrong> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Créer un prix spécifique temporaire pour ce client\n$specificPrice = new SpecificPrice();\n$specificPrice-&gt;id_product = $idProduct;\n$specificPrice-&gt;id_customer = (int) $this-&gt;context-&gt;customer-&gt;id;\n$specificPrice-&gt;id_shop = (int) $this-&gt;context-&gt;shop-&gt;id;\n$specificPrice-&gt;id_currency = 0;\n$specificPrice-&gt;id_country = 0;\n$specificPrice-&gt;id_group = 0;\n$specificPrice-&gt;price = $prix;\n$specificPrice-&gt;from_quantity = 1;\n$specificPrice-&gt;reduction = 0;\n$specificPrice-&gt;reduction_type = 'amount';\n$specificPrice-&gt;from = date('Y-m-d H:i:s');\n$specificPrice-&gt;to = date('Y-m-d H:i:s', strtotime('+1 hour'));\n$specificPrice-&gt;add();\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette méthode est \u003Cstrong>thread-safe\u003C\u002Fstrong> : chaque client a son propre prix spécifique, sans collision possible.\u003C\u002Fp>\n\u003Ch2>Régénérer le cache des classes après un override\u003C\u002Fh2>\n\u003Cp>Après avoir créé ou modifié un override, supprimez le fichier de cache des classes :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">\n# PrestaShop 1.6\nrm -f cache\u002Fclass_index.php\n\n# PrestaShop 1.7 \u002F 8.x\nrm -f var\u002Fcache\u002Fprod\u002Fclass_index.php\nrm -f var\u002Fcache\u002Fdev\u002Fclass_index.php\n\n# Ou depuis le back-office : Paramètres avancés &gt; Performances &gt; Vider le cache\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Sans cette étape, PrestaShop continuera d'utiliser les classes originales et votre override sera ignoré silencieusement.\u003C\u002Fp>",[123,126,129,132,135,138,141],{"q":124,"a":125},"Comment implémenter un système de prix libre (Name Your Price) sur PrestaShop ?","La solution repose sur trois éléments : un override de la classe Product avec une méthode de mise à jour du prix, un override du ProductController pour intercepter et valider le formulaire, et un template front-end avec un champ de saisie numérique. Le contrôleur valide le format (Validate::isPrice), vérifie les bornes min\u002Fmax, puis met à jour les tables ps_product et ps_product_shop.",{"q":127,"a":128},"Le prix libre est-il compatible avec le multiboutique PrestaShop ?","Oui, à condition de mettre à jour à la fois la table ps_product et ps_product_shop. En contexte multiboutique, pensez à filtrer par id_shop pour ne modifier le prix que sur la boutique concernée. Utilisez Db::update() avec une condition WHERE incluant l'id_shop du contexte courant.",{"q":130,"a":131},"Comment limiter le prix libre à une seule catégorie de produits ?","Utilisez la propriété id_category_default du produit pour conditionner l'affichage du formulaire. En Smarty : {if $product->id_category_default == ID_CATEGORIE}. Stockez l'ID de catégorie dans Configuration plutôt que de le coder en dur, ce qui permettra de le modifier depuis le back-office.",{"q":133,"a":134},"Le système de prix libre pose-t-il des problèmes de concurrence entre visiteurs ?","Oui, la méthode par mise à jour directe du prix en base modifie le prix pour tous les visiteurs simultanément. Pour un site en production avec du trafic, utilisez plutôt les SpecificPrice de PrestaShop : créez un prix spécifique temporaire lié au client (id_customer) avec une durée de validité courte. Chaque visiteur aura ainsi son propre prix sans collision.",{"q":136,"a":137},"Faut-il vider le cache après avoir ajouté un override sur PrestaShop ?","Oui, impérativement. Supprimez le fichier cache\u002Fclass_index.php (PS 1.6) ou var\u002Fcache\u002Fprod\u002Fclass_index.php (PS 1.7\u002F8.x). Sans cette étape, PrestaShop ignore silencieusement l'override et continue d'utiliser la classe originale. Vous pouvez aussi vider le cache depuis le back-office via Paramètres avancés > Performances.",{"q":139,"a":140},"Comment sécuriser le formulaire de prix libre contre les injections SQL ?","Appliquez une validation en trois couches : 1) côté HTML avec type=\"number\" et les attributs min\u002Fmax, 2) côté PHP avec Validate::isPrice() qui vérifie le format décimal, et 3) un cast (int)\u002F(float) systématique avant toute requête SQL. Ajoutez également un token CSRF et vérifiez que l'id_product correspond à un produit existant via Validate::isLoadedObject().",{"q":142,"a":143},"Peut-on définir un prix minimum différent pour chaque produit en prix libre ?","Oui, en ajoutant un champ personnalisé au produit (via un module ou un override) qui stocke le prix minimum autorisé. Dans le contrôleur, récupérez cette valeur depuis la base de données au lieu d'utiliser une constante fixe. Sur PrestaShop 8.x, vous pouvez utiliser le système de champs personnalisés natif ou créer une table dédiée dans votre module.","Implémentez un système de prix libre sur PrestaShop via un override de Product (mise à jour du prix) et du ProductController (validation sécurisée avec bornes min\u002Fmax). Pour la production, préférez les SpecificPrice par client plutôt que la modification directe en base.",9,"2026-03-21T13:24:33.000Z",[],"PrestaShop pour les développeurs",{"footer":150},{"theme":151,"description":152,"hours":152,"logo":153,"contact":156,"social":157,"bottomBar":167},"dark",null,{"src":154,"href":155,"alt":95},"\u002Flogo-ac.svg","\u002F",{"email":152,"phone":152,"address":152,"cta":152},[158,161,164],{"platform":159,"href":160,"label":159},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":162,"href":163,"label":162},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":165,"href":166,"label":165},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":152},{"items":169},[170,178,184,190,198,206,212,218],{"id":171,"type":172,"label":173,"href":84,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":152,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":175,"children":176,"psChildren":177},41,"link",{"fr":174},"Expertise",0,[],[],{"id":179,"type":172,"label":180,"href":75,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":152,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":181,"children":182,"psChildren":183},42,{"fr":74},1,[],[],{"id":185,"type":172,"label":186,"href":36,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":152,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":187,"children":188,"psChildren":189},43,{"fr":35},2,[],[],{"id":191,"type":172,"label":192,"href":194,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":152,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":195,"children":196,"psChildren":197},44,{"fr":193},"Outils IA","\u002Foutils-ia",3,[],[],{"id":199,"type":172,"label":200,"href":29,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":202,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":203,"children":204,"psChildren":205},45,{"fr":201},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":207,"type":172,"label":208,"href":78,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":152,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":209,"children":210,"psChildren":211},46,{"fr":77},5,[],[],{"id":213,"type":172,"label":214,"href":96,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":152,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":215,"children":216,"psChildren":217},47,{"fr":92},6,[],[],{"id":219,"type":172,"label":220,"href":102,"icon":152,"description":152,"badge":152,"groupTitle":152,"style":152,"gridColumns":152,"cssClass":152,"psCategoryId":152,"showPsChildren":30,"position":221,"children":222,"psChildren":223},48,{"fr":101},7,[],[],{"header":225},{"logo":226,"topBar":229,"contactEmail":232,"features":233,"navBar":152},{"src":154,"alt":227,"text":95,"href":155,"class":228},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":152,"showLanguages":30,"align":230,"languages":231},"left",[],"contact@alexandrecarette.fr",{"showSearch":30,"showWishlist":30,"showLogin":20,"showContact":30,"showCart":30,"stickyHeader":20,"headerLayout":234},"inline",{"academy":236,"blog":237,"expertise":248},[],[238,242,245],{"title":239,"url":240,"score":181,"type":241},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":243,"url":244,"score":181,"type":241},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":246,"url":247,"score":181,"type":241},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[]]