[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fvScHhoLsoJgI2aeI0rBS1WuvMafhTGtstDk--vSPM-U":22,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":62,"megamenu":143,"$f2Rg1UA_zqhKQE3MCayuDwMi6AiVAZPCrGPaulOyvA5A":199,"header-db":213,"footer-db":226},{"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",{"title":23,"slug":24,"metaDescription":25,"category":26,"tags":27,"difficulty":35,"psVersions":36,"content":40,"faq":41,"tldr":57,"readingTime":58,"generatedAt":59,"publishDate":59,"relatedArticles":60,"sourceCategory":61},"Forcer l'ID produit lors de la création dans PrestaShop","forcer-id-product-creation-produit-prestashop","Comment imposer un id_product spécifique à la création d'un produit PrestaShop. Méthode ObjectModel::add() avec force_id, alternatives SQL et bonnes pratiques.","developpement",[28,29,30,31,32,33,34],"ObjectModel","Product","id_product","SQL","force_id","import","migration","avance",[37,38,39],"1.6","1.7","8.x","\u003Ch1>Forcer l'ID produit lors de la création dans PrestaShop\u003C\u002Fh1>\n\u003Cp>Lors d'une migration de catalogue, d'une synchronisation ERP ou d'un import personnalisé, il est fréquent de devoir créer des produits avec un identifiant précis plutôt que de laisser PrestaShop attribuer un auto-increment. Le réflexe naturel — affecter \u003Ccode>$product->id_product\u003C\u002Fcode> avant d'appeler \u003Ccode>add()\u003C\u002Fcode> — ne fonctionne pas. Voici pourquoi, et comment résoudre ce problème proprement.\u003C\u002Fp>\n\u003Ch2>Pourquoi `$product->id_product = 40` ne fonctionne pas\u003C\u002Fh2>\n\u003Cp>La classe \u003Ccode>Product\u003C\u002Fcode> hérite d'\u003Ccode>ObjectModel\u003C\u002Fcode>, le socle ORM de PrestaShop. Quand on appelle \u003Ccode>$product->add()\u003C\u002Fcode>, la méthode exécute un \u003Ccode>INSERT\u003C\u002Fcode> SQL classique. Par défaut, ObjectModel \u003Cstrong>ignore volontairement\u003C\u002Fstrong> toute valeur assignée à la clé primaire : il laisse MySQL générer l'auto-increment, puis récupère l'ID via \u003Ccode>Db::getInstance()->Insert_ID()\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Concrètement, dans \u003Ccode>classes\u002FObjectModel.php\u003C\u002Fcode>, la méthode \u003Ccode>add()\u003C\u002Fcode> construit la requête INSERT sans inclure le champ de clé primaire, sauf si on lui indique explicitement de le faire.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Ce code ne force PAS l'ID — il sera ignoré\n$product = new Product();\n$product-&gt;id = 40;\n$product-&gt;name = [(int)Configuration::get('PS_LANG_DEFAULT') =&gt; 'Mon produit'];\n$product-&gt;link_rewrite = [(int)Configuration::get('PS_LANG_DEFAULT') =&gt; 'mon-produit'];\n$product-&gt;add(); \u002F\u002F L'ID 40 est ignoré, MySQL attribue l'auto-increment\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>La solution native : le paramètre `force_id`\u003C\u002Fh2>\n\u003Cp>PrestaShop a prévu ce cas d'usage. La propriété \u003Ccode>force_id\u003C\u002Fcode> d'ObjectModel, combinée au paramètre \u003Ccode>$auto_date\u003C\u002Fcode> et \u003Ccode>$null_values\u003C\u002Fcode> de la méthode \u003Ccode>add()\u003C\u002Fcode>, permet d'imposer l'identifiant souhaité.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n$product = new Product();\n$product-&gt;force_id = true;  \u002F\u002F Clé du mécanisme\n$product-&gt;id = 40;          \u002F\u002F L'ID qui sera réellement utilisé\n$product-&gt;active = 1;\n$product-&gt;name = [\n    (int)Configuration::get('PS_LANG_DEFAULT') =&gt; 'Mon produit'\n];\n$product-&gt;link_rewrite = [\n    (int)Configuration::get('PS_LANG_DEFAULT') =&gt; 'mon-produit'\n];\n$product-&gt;id_category_default = 2;\n$product-&gt;id_tax_rules_group = 1;\n$product-&gt;price = 29.90;\n\nif ($product-&gt;add()) {\n    \u002F\u002F L'ID 40 est bien celui du produit créé\n    StockAvailable::setQuantity($product-&gt;id, 0, 10);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Quand \u003Ccode>force_id\u003C\u002Fcode> vaut \u003Ccode>true\u003C\u002Fcode>, ObjectModel inclut la clé primaire dans la requête \u003Ccode>INSERT\u003C\u002Fcode>. MySQL accepte la valeur à condition qu'elle ne provoque pas de doublon.\u003C\u002Fp>\n\u003Ch3>Ce qui se passe sous le capot\u003C\u002Fh3>\n\u003Cp>Dans \u003Ccode>ObjectModel::add()\u003C\u002Fcode> (fichier \u003Ccode>classes\u002FObjectModel.php\u003C\u002Fcode>), le flux est le suivant :\u003C\u002Fp>\n\u003Col>\n\u003Cli>Si `force_id` est `false` (défaut) : la clé primaire est exclue de l'INSERT\u003C\u002Fli>\n\u003Cli>Si `force_id` est `true` : la clé primaire est incluse dans les champs insérés\u003C\u002Fli>\n\u003Cli>Les tables liées (`_lang`, `_shop`) reçoivent automatiquement le bon ID\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>C'est précisément le mécanisme utilisé en interne par l'import CSV natif de PrestaShop lorsqu'on coche l'option « Forcer les ID ».\u003C\u002Fp>\n\u003Ch2>L'approche SQL directe : pourquoi l'éviter\u003C\u002Fh2>\n\u003Cp>Une approche de contournement consiste à créer le produit normalement, puis à modifier son ID via des requêtes SQL brutes :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F ⚠️ Approche fragile — à éviter en production\n$product-&gt;add();\n$old_id = $product-&gt;id;\n$new_id = 40;\n\n$tables = ['product', 'product_lang', 'product_shop'];\nforeach ($tables as $table) {\n    Db::getInstance()-&gt;execute(\n        'UPDATE `' . _DB_PREFIX_ . $table . '` SET id_product = ' . (int)$new_id .\n        ' WHERE id_product = ' . (int)$old_id\n    );\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette méthode pose plusieurs problèmes majeurs :\u003C\u002Fp>\n\u003Ch3>Tables oubliées\u003C\u002Fh3>\n\u003Cp>Un produit PrestaShop est référencé dans \u003Cstrong>plus de 20 tables\u003C\u002Fstrong>. Mettre à jour uniquement \u003Ccode>product\u003C\u002Fcode>, \u003Ccode>product_lang\u003C\u002Fcode> et \u003Ccode>product_shop\u003C\u002Fcode> laisse des orphelins dans :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>`ps_category_product`\u003C\u002Fli>\n\u003Cli>`ps_product_attribute`\u003C\u002Fli>\n\u003Cli>`ps_product_attribute_combination`\u003C\u002Fli>\n\u003Cli>`ps_stock_available`\u003C\u002Fli>\n\u003Cli>`ps_specific_price`\u003C\u002Fli>\n\u003Cli>`ps_image` et `ps_image_shop`\u003C\u002Fli>\n\u003Cli>`ps_feature_product`\u003C\u002Fli>\n\u003Cli>`ps_cart_product`\u003C\u002Fli>\n\u003Cli>`ps_order_detail`\u003C\u002Fli>\n\u003Cli>`ps_product_carrier`\u003C\u002Fli>\n\u003Cli>`ps_product_tag`\u003C\u002Fli>\n\u003Cli>Et bien d'autres selon les modules installés\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Contraintes de clé étrangère\u003C\u002Fh3>\n\u003Cp>Sur PrestaShop 8.x avec InnoDB, certaines tables utilisent des contraintes \u003Ccode>FOREIGN KEY\u003C\u002Fcode>. Modifier un ID sans respecter l'ordre de mise à jour provoque des erreurs d'intégrité référentielle.\u003C\u002Fp>\n\u003Ch3>Cache et index de recherche\u003C\u002Fh3>\n\u003Cp>L'ancien ID reste potentiellement en cache (Smarty, Redis, module de recherche). Le produit devient introuvable ou pointe vers une fiche fantôme.\u003C\u002Fp>\n\u003Ch2>Bonnes pratiques pour les imports avec ID forcé\u003C\u002Fh2>\n\u003Ch3>1. Vérifier la disponibilité de l'ID\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-php\">\nfunction isProductIdAvailable(int $id_product): bool\n{\n    return !(bool)Db::getInstance()-&gt;getValue(\n        'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'product` WHERE id_product = ' . (int)$id_product\n    );\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>2. Gérer l'auto-increment après import\u003C\u002Fh3>\n\u003Cp>Après avoir inséré des produits avec des ID imposés, l'auto-increment MySQL peut se retrouver inférieur au plus grand ID inséré. Cela provoquera un conflit lors de la prochaine création sans \u003Ccode>force_id\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\n-- Réaligner l'auto-increment après un import forcé\nALTER TABLE ps_product AUTO_INCREMENT = 1;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>MySQL recalculera automatiquement la valeur à MAX(id_product) + 1.\u003C\u002Fp>\n\u003Ch3>3. Encapsuler dans une transaction\u003C\u002Fh3>\n\u003Cp>Pour un import massif, encapsulez le tout dans une transaction afin de pouvoir annuler proprement en cas d'erreur :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\nDb::getInstance()-&gt;execute('START TRANSACTION');\n\ntry {\n    foreach ($products_to_import as $data) {\n        $product = new Product();\n        $product-&gt;force_id = true;\n        $product-&gt;id = (int)$data['id_product'];\n        $product-&gt;name = $data['name'];\n        $product-&gt;link_rewrite = $data['link_rewrite'];\n        \u002F\u002F ... autres champs\n\n        if (!$product-&gt;add()) {\n            throw new PrestaShopException(\n                'Échec création produit ID ' . $data['id_product']\n            );\n        }\n    }\n\n    Db::getInstance()-&gt;execute('COMMIT');\n} catch (Exception $e) {\n    Db::getInstance()-&gt;execute('ROLLBACK');\n    PrestaShopLogger::addLog($e-&gt;getMessage(), 3);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>4. Invalider les caches après import\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Vider le cache produit après un import massif\nCache::clean('Product::*');\nMedia::clearCache();\nTools::generateHtaccess();\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Cas d'usage légitimes\u003C\u002Fh2>\n\u003Cp>Forcer l'ID produit se justifie dans ces situations :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**Migration de boutique** : conserver les ID pour préserver les URLs, les statistiques et les relations commandes\u002Fproduits\u003C\u002Fli>\n\u003Cli>**Synchronisation ERP** : aligner les ID PrestaShop sur les codes articles de l'ERP\u003C\u002Fli>\n\u003Cli>**Environnement de développement** : reproduire un catalogue de production à l'identique pour déboguer\u003C\u002Fli>\n\u003Cli>**Multi-boutique** : harmoniser les catalogues entre instances\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>En dehors de ces cas, laissez PrestaShop gérer ses auto-increments. Forcer des ID sans raison ajoute de la complexité sans bénéfice.\u003C\u002Fp>\n\u003Ch2>Évolution selon les versions\u003C\u002Fh2>\n\u003Ctr>\u003Cth>Version\u003C\u002Fth>\u003Cth>Comportement\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>PrestaShop 1.6\u003C\u002Fth>\u003Cth>`force_id` disponible mais peu documenté\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>PrestaShop 1.7\u003C\u002Fth>\u003Cth>Identique, utilisé par l'import CSV natif\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>PrestaShop 8.x\u003C\u002Fth>\u003Cth>Toujours supporté, pas de changement de l'API ObjectModel\u003C\u002Fth>\u003C\u002Ftr>\n\u003Cp>Le mécanisme \u003Ccode>force_id\u003C\u002Fcode> est stable depuis PrestaShop 1.5 et reste la méthode officielle sur toutes les versions actuelles.\u003C\u002Fp>",[42,45,48,51,54],{"q":43,"a":44},"Pourquoi $product->id_product = 40 est ignoré par PrestaShop ?","La méthode add() d'ObjectModel exclut volontairement la clé primaire de la requête INSERT pour laisser MySQL gérer l'auto-increment. Pour forcer un ID, il faut activer la propriété $product->force_id = true avant d'appeler add(). C'est le même mécanisme que l'option « Forcer les ID » de l'import CSV natif.",{"q":46,"a":47},"Quelles tables sont impactées quand on change l'ID d'un produit par SQL direct ?","Un produit PrestaShop est référencé dans plus de 20 tables : product, product_lang, product_shop, category_product, product_attribute, stock_available, specific_price, image, feature_product, cart_product, order_detail, product_carrier, product_tag, et d'autres ajoutées par les modules. Modifier l'ID par SQL sans toutes les mettre à jour crée des orphelins et des incohérences graves.",{"q":49,"a":50},"Comment éviter les conflits d'auto-increment après un import avec force_id ?","Après un import avec des ID forcés, exécutez ALTER TABLE ps_product AUTO_INCREMENT = 1. MySQL recalculera automatiquement la valeur au maximum de la colonne id_product + 1, évitant ainsi les doublons lors des prochaines créations sans force_id.",{"q":52,"a":53},"Est-ce que force_id fonctionne aussi pour les déclinaisons et autres objets PrestaShop ?","Oui, force_id est une propriété de la classe ObjectModel dont héritent tous les objets PrestaShop : Product, Combination, Category, Customer, Order, etc. Le mécanisme est identique : activez force_id = true, assignez l'ID souhaité via la propriété id, puis appelez add().",{"q":55,"a":56},"Peut-on forcer l'ID produit via l'API Webservice de PrestaShop ?","Non, l'API Webservice ne permet pas nativement de forcer un id_product à la création. L'ID est toujours auto-généré. Pour imposer des ID spécifiques, utilisez un module ou un script CLI qui exploite directement la classe Product avec force_id = true.","Pour forcer un id_product à la création dans PrestaShop, utilisez $product->force_id = true avant add() plutôt que des UPDATE SQL manuels qui oublient des tables et cassent l'intégrité référentielle.",5,"2026-03-21T15:19:03.000Z",[],"PrestaShop pour les développeurs",{"columns":63},[64,80,110,131],{"title":65,"links":66},"Plateforme",[67,71,74,77],{"label":68,"href":69,"external":70},"Offre Starter (2 500 €)","\u002Foffre-starter",false,{"label":72,"href":73,"external":70},"Devenir Ambassadeur","\u002Fambassadeur",{"label":75,"href":76,"external":70},"Modules PrestaShop","\u002Fmodules",{"label":78,"href":79,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":81,"links":82},"Le Synedre",[83,86,89,92,95,98,101,104,107],{"label":84,"href":85,"external":70},"L'histoire","\u002Fsynedre",{"label":87,"href":88,"external":70},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":90,"href":91,"external":70},"L'équipe","\u002Fequipe",{"label":93,"href":94,"external":70},"Le réacteur en direct","\u002Freacteur",{"label":96,"href":97,"external":70},"Le Drill (entraînement)","\u002Fdrill",{"label":99,"href":100,"external":70},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":102,"href":103,"external":70},"Les agents IA","\u002Fagents-ia",{"label":105,"href":106,"external":70},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":108,"href":109,"external":70},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":111,"links":112},"Ressources",[113,116,119,122,125,128],{"label":114,"href":115,"external":70},"Blog","\u002Fblog",{"label":117,"href":118,"external":70},"Academy","\u002Facademy",{"label":120,"href":121,"external":70},"Dictionnaire","\u002Fdictionnaire",{"label":123,"href":124,"external":70},"Expertise PrestaShop","\u002Fexpertise",{"label":126,"href":127,"external":70},"Flywheel","\u002Fflywheel",{"label":129,"href":130,"external":70},"Manifeste","\u002Fmanifeste",{"title":132,"links":133},"À propos",[134,137,140],{"label":135,"href":136,"external":70},"Alexandre Carette","\u002Fa-propos",{"label":138,"href":139,"external":70},"Dossier de presse","\u002Fpresse",{"label":141,"href":142,"external":70},"Contact","\u002Fcontact",{"items":144},[145,154,160,166,174,182,187,193],{"id":146,"type":147,"label":148,"href":124,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":150,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":151,"children":152,"psChildren":153},41,"link",{"fr":149},"Expertise",null,0,[],[],{"id":155,"type":147,"label":156,"href":115,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":150,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":157,"children":158,"psChildren":159},42,{"fr":114},1,[],[],{"id":161,"type":147,"label":162,"href":76,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":150,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":163,"children":164,"psChildren":165},43,{"fr":75},2,[],[],{"id":167,"type":147,"label":168,"href":170,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":150,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":171,"children":172,"psChildren":173},44,{"fr":169},"Outils IA","\u002Foutils-ia",3,[],[],{"id":175,"type":147,"label":176,"href":69,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":178,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":179,"children":180,"psChildren":181},45,{"fr":177},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":183,"type":147,"label":184,"href":118,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":150,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":58,"children":185,"psChildren":186},46,{"fr":117},[],[],{"id":188,"type":147,"label":189,"href":136,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":150,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":190,"children":191,"psChildren":192},47,{"fr":132},6,[],[],{"id":194,"type":147,"label":195,"href":142,"icon":150,"description":150,"badge":150,"groupTitle":150,"style":150,"gridColumns":150,"cssClass":150,"psCategoryId":150,"showPsChildren":70,"position":196,"children":197,"psChildren":198},48,{"fr":141},7,[],[],{"academy":200,"blog":201,"expertise":212},[],[202,206,209],{"title":203,"url":204,"score":157,"type":205},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":207,"url":208,"score":157,"type":205},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":210,"url":211,"score":157,"type":205},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[],{"header":214},{"logo":215,"topBar":220,"contactEmail":223,"features":224,"navBar":150},{"src":216,"alt":217,"text":135,"href":218,"class":219},"\u002Flogo-ac.svg","Alexandre Carette — Architecte E-commerce Souverain","\u002F","h-10 w-10",{"message":150,"showLanguages":70,"align":221,"languages":222},"left",[],"contact@alexandrecarette.fr",{"showSearch":70,"showWishlist":70,"showLogin":20,"showContact":70,"showCart":70,"stickyHeader":20,"headerLayout":225},"inline",{"footer":227},{"theme":228,"description":150,"hours":150,"logo":229,"contact":230,"social":231,"bottomBar":241},"dark",{"src":216,"href":218,"alt":135},{"email":150,"phone":150,"address":150,"cta":150},[232,235,238],{"platform":233,"href":234,"label":233},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":236,"href":237,"label":236},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":239,"href":240,"label":239},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":150}]