[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fLidxBh4ztmnQ5pHS4_NP_4u_aKl4YOdEPxMWY522RqQ":22,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":59,"megamenu":140,"footer-db":196,"$fMUW8EOKLIP18xh9U-YT0SEnjTA3l0IE0RrFf1ru9C88":214,"header-db":228},{"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":33,"psVersions":34,"content":37,"faq":38,"tldr":54,"readingTime":55,"generatedAt":56,"publishDate":56,"relatedArticles":57,"sourceCategory":58},"Récupérer les personnalisations produit PrestaShop via ObjectModel","recuperer-personnalisations-produit-prestashop-objectmodel","Créez une classe ObjectModel pour gérer les personnalisations produit PrestaShop. Guide complet avec requêtes DbQuery, bonnes pratiques et code compatible 8.x.","developpement",[28,29,30,31,32],"ObjectModel","personnalisation produit","DbQuery","module PrestaShop","customization","intermediaire",[35,36],"1.7","8.x","\u003Ch2>Introduction\u003C\u002Fh2>\n\u003Cp>La personnalisation produit est une fonctionnalité native de PrestaShop qui permet aux clients de soumettre du texte ou des fichiers (gravure, impression, upload d'image) avant d'ajouter un article au panier. Ces données sont stockées dans les tables \u003Ccode>ps_customization\u003C\u002Fcode>, \u003Ccode>ps_customized_data\u003C\u002Fcode> et \u003Ccode>ps_customization_field\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Lorsque vous développez un module qui doit exploiter ces données — tableau de bord des personnalisations, export, traitement en production — vous avez besoin d'une classe dédiée pour interroger proprement la base. Voici comment structurer cette classe en suivant les conventions PrestaShop.\u003C\u002Fp>\n\u003Ch2>Architecture des tables de personnalisation\u003C\u002Fh2>\n\u003Cp>Avant de coder, il est essentiel de comprendre le schéma relationnel :\u003C\u002Fp>\n\u003Ctr>\u003Cth>Table\u003C\u002Fth>\u003Cth>Rôle\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`ps_customization`\u003C\u002Fth>\u003Cth>Lie une personnalisation à un panier, un produit et une déclinaison\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`ps_customization_field`\u003C\u002Fth>\u003Cth>Définit les champs disponibles (texte ou fichier) pour un produit\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`ps_customization_field_lang`\u003C\u002Fth>\u003Cth>Labels traduits de chaque champ\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`ps_customized_data`\u003C\u002Fth>\u003Cth>Stocke les **valeurs saisies** par le client (texte ou chemin fichier)\u003C\u002Fth>\u003C\u002Ftr>\n\u003Cp>La colonne \u003Ccode>type\u003C\u002Fcode> dans \u003Ccode>ps_customized_data\u003C\u002Fcode> distingue les fichiers (\u003Ccode>0\u003C\u002Fcode>) des textes (\u003Ccode>1\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Ch2>Créer la classe dans votre module\u003C\u002Fh2>\n\u003Cp>Créez le fichier \u003Ccode>classes\u002FCustomizationData.php\u003C\u002Fcode> dans votre module :\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\nif (!defined('_PS_VERSION_')) {\n    exit;\n}\n\nclass CustomizationData extends ObjectModel\n{\n    \u002F** @var int *\u002F\n    public $id_customization;\n\n    \u002F** @var int Type : 0 = fichier, 1 = texte *\u002F\n    public $type;\n\n    \u002F** @var int Index du champ *\u002F\n    public $index;\n\n    \u002F** @var string Valeur saisie par le client *\u002F\n    public $value;\n\n    \u002F** @var int Identifiant du module (si applicable) *\u002F\n    public $id_module;\n\n    \u002F**\n     * @see ObjectModel::$definition\n     *\u002F\n    public static $definition = [\n        'table' =&gt; 'customized_data',\n        'primary' =&gt; 'id_customization',\n        'fields' =&gt; [\n            'id_customization' =&gt; ['type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isUnsignedId', 'required' =&gt; true],\n            'type'             =&gt; ['type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isUnsignedInt', 'required' =&gt; true],\n            'index'            =&gt; ['type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isUnsignedInt', 'required' =&gt; true],\n            'value'            =&gt; ['type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isCleanHtml', 'required' =&gt; true],\n            'id_module'        =&gt; ['type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isUnsignedId'],\n        ],\n    ];\n\n    \u002F**\n     * Récupère toutes les valeurs de personnalisation.\n     *\n     * @return array\n     *\u002F\n    public static function getAllCustomizations()\n    {\n        $query = new DbQuery();\n        $query-&gt;select('cd.value, cd.type, cd.`index`, cd.id_customization');\n        $query-&gt;from('customized_data', 'cd');\n\n        return Db::getInstance(_PS_USE_SQL_SLAVE_)-&gt;executeS($query);\n    }\n\n    \u002F**\n     * Récupère les personnalisations d'un produit spécifique.\n     *\n     * @param int $idProduct\n     * @param int $idProductAttribute Déclinaison (0 = produit simple)\n     * @return array\n     *\u002F\n    public static function getByProduct($idProduct, $idProductAttribute = 0)\n    {\n        $query = new DbQuery();\n        $query-&gt;select('cd.value, cd.type, cd.`index`, c.id_cart, c.id_customization');\n        $query-&gt;from('customized_data', 'cd');\n        $query-&gt;innerJoin('customization', 'c', 'c.id_customization = cd.id_customization');\n        $query-&gt;where('c.id_product = ' . (int) $idProduct);\n        $query-&gt;where('c.id_product_attribute = ' . (int) $idProductAttribute);\n        $query-&gt;where('c.in_cart = 1');\n\n        return Db::getInstance(_PS_USE_SQL_SLAVE_)-&gt;executeS($query);\n    }\n\n    \u002F**\n     * Récupère les personnalisations d'une commande avec les labels traduits.\n     *\n     * @param int $idOrder\n     * @param int $idLang\n     * @return array\n     *\u002F\n    public static function getByOrder($idOrder, $idLang = null)\n    {\n        if (!$idLang) {\n            $idLang = (int) Configuration::get('PS_LANG_DEFAULT');\n        }\n\n        $query = new DbQuery();\n        $query-&gt;select('cd.value, cd.type, cfl.name AS field_label, od.product_name');\n        $query-&gt;from('customized_data', 'cd');\n        $query-&gt;innerJoin('customization', 'c', 'c.id_customization = cd.id_customization');\n        $query-&gt;innerJoin('order_detail', 'od', 'od.id_order = ' . (int) $idOrder\n            . ' AND od.product_id = c.id_product'\n            . ' AND od.product_attribute_id = c.id_product_attribute');\n        $query-&gt;leftJoin('customization_field_lang', 'cfl',\n            'cfl.id_customization_field = cd.`index` AND cfl.id_lang = ' . (int) $idLang\n            . ' AND cfl.id_shop = c.id_shop');\n        $query-&gt;orderBy('c.id_customization ASC, cd.`index` ASC');\n\n        return Db::getInstance(_PS_USE_SQL_SLAVE_)-&gt;executeS($query);\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Charger la classe dans votre module\u003C\u002Fh2>\n\u003Cp>Dans le fichier principal de votre module, déclarez le chargement automatique :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\npublic function __construct()\n{\n    \u002F\u002F ... configuration du module\n\n    parent::__construct();\n\n    require_once _PS_MODULE_DIR_ . $this-&gt;name . '\u002Fclasses\u002FCustomizationData.php';\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Sur PrestaShop 8.x, vous pouvez aussi utiliser l'autoload Composer du module en ajoutant dans \u003Ccode>composer.json\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">\n{\n    \"autoload\": {\n        \"classmap\": [\"classes\u002F\"]\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Puis lancez \u003Ccode>composer dump-autoload\u003C\u002Fcode> dans le répertoire du module.\u003C\u002Fp>\n\u003Ch2>Utilisation concrète dans un controller ou un hook\u003C\u002Fh2>\n\u003Ch3>Récupérer toutes les personnalisations\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-php\">\n$allCustomizations = CustomizationData::getAllCustomizations();\n\nforeach ($allCustomizations as $row) {\n    if ((int) $row['type'] === 1) {\n        \u002F\u002F Texte saisi par le client\n        echo 'Texte : ' . htmlspecialchars($row['value']);\n    } else {\n        \u002F\u002F Fichier uploadé (chemin relatif)\n        echo 'Fichier : ' . _PS_UPLOAD_DIR_ . $row['value'];\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Afficher les personnalisations d'une commande\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Dans un hook displayAdminOrderMain (PS 8.x) ou displayAdminOrder (PS 1.7)\npublic function hookDisplayAdminOrderMain(array $params)\n{\n    $idOrder = (int) $params['id_order'];\n    $customizations = CustomizationData::getByOrder($idOrder, $this-&gt;context-&gt;language-&gt;id);\n\n    $this-&gt;context-&gt;smarty-&gt;assign('customizations', $customizations);\n\n    return $this-&gt;display(__FILE__, 'views\u002Ftemplates\u002Fhook\u002Fadmin-order-customizations.tpl');\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Bonnes pratiques et pièges à éviter\u003C\u002Fh2>\n\u003Ch3>Toujours utiliser DbQuery plutôt que du SQL brut\u003C\u002Fh3>\n\u003Cp>\u003Ccode>DbQuery\u003C\u002Fcode> offre plusieurs avantages :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**Préfixe automatique** des tables (`ps_` est ajouté par `from()`)\u003C\u002Fli>\n\u003Cli>**Lisibilité** avec le chaînage des méthodes\u003C\u002Fli>\n\u003Cli>**Maintenabilité** : chaque clause est isolée et modifiable\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Cast systématique des identifiants\u003C\u002Fh3>\n\u003Cp>Chaque variable injectée dans une requête doit être castée avec \u003Ccode>(int)\u003C\u002Fcode> pour prévenir les injections SQL :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F ✅ Correct\n$query-&gt;where('c.id_product = ' . (int) $idProduct);\n\n\u002F\u002F ❌ Dangereux\n$query-&gt;where('c.id_product = ' . $idProduct);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Utiliser le replica SQL en lecture\u003C\u002Fh3>\n\u003Cp>\u003Ccode>_PS_USE_SQL_SLAVE_\u003C\u002Fcode> redirige les lectures vers le serveur esclave si configuré. Utilisez-le systématiquement pour les requêtes \u003Ccode>SELECT\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\nDb::getInstance(_PS_USE_SQL_SLAVE_)-&gt;executeS($query);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Attention à la colonne `index`\u003C\u002Fh3>\n\u003Cp>Le mot \u003Ccode>index\u003C\u002Fcode> est un mot réservé SQL. Encadrez-le toujours avec des backticks dans vos requêtes :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n$query-&gt;select('cd.`index`');\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Différence entre `in_cart` et personnalisation orpheline\u003C\u002Fh3>\n\u003Cp>La table \u003Ccode>ps_customization\u003C\u002Fcode> possède un champ \u003Ccode>in_cart\u003C\u002Fcode>. Une personnalisation avec \u003Ccode>in_cart = 0\u003C\u002Fcode> est un brouillon (le client a saisi du texte mais n'a pas encore ajouté au panier). Filtrez selon votre besoin.\u003C\u002Fp>\n\u003Ch2>Évolution PrestaShop 8.x\u003C\u002Fh2>\n\u003Cp>Sur PrestaShop 8.x, la gestion des personnalisations a été modernisée :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Les **CQRS Commands** (`AddCustomizationFieldCommand`, `UpdateCustomizationFieldCommand`) sont désormais disponibles pour les opérations back-office\u003C\u002Fli>\n\u003Cli>Le service `ProductCustomizationProvider` encapsule les requêtes de lecture\u003C\u002Fli>\n\u003Cli>Les hooks d'administration utilisent Symfony (`displayAdminOrderMain` remplace `displayAdminOrder`)\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Pour un module rétrocompatible 1.7 + 8.x, la classe \u003Ccode>ObjectModel\u003C\u002Fcode> avec \u003Ccode>DbQuery\u003C\u002Fcode> reste la solution la plus portable. Migrez vers les services Symfony uniquement si vous ciblez exclusivement PrestaShop 8.x+.\u003C\u002Fp>\n\u003Ch2>Conclusion\u003C\u002Fh2>\n\u003Cp>Créer une classe dédiée dans votre module pour accéder aux données de personnalisation est la bonne approche : vous isolez la logique SQL, vous respectez les conventions PrestaShop, et vous obtenez un code testable et réutilisable. Pensez à toujours filtrer par produit, commande ou panier selon le contexte, et à ne jamais exposer les valeurs sans les échapper côté template.\u003C\u002Fp>",[39,42,45,48,51],{"q":40,"a":41},"Comment récupérer les personnalisations d'un produit dans un module PrestaShop ?","Créez une classe dans le dossier classes\u002F de votre module qui étend ObjectModel. Utilisez DbQuery pour interroger la table ps_customized_data en la joignant à ps_customization pour filtrer par id_product. Pensez à utiliser Db::getInstance(_PS_USE_SQL_SLAVE_) pour les requêtes en lecture et à caster tous les identifiants avec (int) pour la sécurité.",{"q":43,"a":44},"Quelle est la différence entre ps_customization et ps_customized_data dans PrestaShop ?","La table ps_customization fait le lien entre une personnalisation, un panier, un produit et une déclinaison. Elle contient aussi le champ in_cart qui indique si l'article a été ajouté au panier. La table ps_customized_data stocke les valeurs concrètes saisies par le client : texte (type = 1) ou chemin vers un fichier uploadé (type = 0). Les deux tables sont liées par id_customization.",{"q":46,"a":47},"Comment afficher les personnalisations dans le back-office sur une page de commande PrestaShop ?","Utilisez le hook displayAdminOrderMain (PrestaShop 8.x) ou displayAdminOrder (1.7). Récupérez l'id_order depuis les paramètres du hook, puis joignez ps_customized_data avec ps_customization et ps_order_detail pour obtenir les valeurs avec le nom du produit associé. Ajoutez une jointure vers ps_customization_field_lang pour afficher les labels traduits des champs.",{"q":49,"a":50},"Pourquoi utiliser DbQuery plutôt qu'une requête SQL brute dans PrestaShop ?","DbQuery ajoute automatiquement le préfixe des tables (ps_), offre un chaînage de méthodes lisible et facilite la maintenance du code. Chaque clause (select, from, where, join) est isolée, ce qui permet de modifier une requête sans risquer de casser la syntaxe SQL. C'est la méthode recommandée par PrestaShop pour toutes les requêtes dans les modules.",{"q":52,"a":53},"Les personnalisations produit fonctionnent-elles avec le multiboutique PrestaShop ?","Oui, la table ps_customization contient un champ id_shop. Lorsque vous récupérez des personnalisations, ajoutez un filtre sur id_shop pour respecter le contexte multiboutique. La table ps_customization_field_lang est également liée à id_shop pour les traductions des labels de champs par boutique.","Guide complet pour créer une classe ObjectModel dédiée à la récupération des personnalisations produit PrestaShop, avec requêtes DbQuery par produit et par commande, bonnes pratiques de sécurité SQL et compatibilité 1.7\u002F8.x.",6,"2026-03-21T15:46:09.000Z",[],"PrestaShop pour les développeurs",{"columns":60},[61,77,107,128],{"title":62,"links":63},"Plateforme",[64,68,71,74],{"label":65,"href":66,"external":67},"Offre Starter (2 500 €)","\u002Foffre-starter",false,{"label":69,"href":70,"external":67},"Devenir Ambassadeur","\u002Fambassadeur",{"label":72,"href":73,"external":67},"Modules PrestaShop","\u002Fmodules",{"label":75,"href":76,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":78,"links":79},"Le Synedre",[80,83,86,89,92,95,98,101,104],{"label":81,"href":82,"external":67},"L'histoire","\u002Fsynedre",{"label":84,"href":85,"external":67},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":87,"href":88,"external":67},"L'équipe","\u002Fequipe",{"label":90,"href":91,"external":67},"Le réacteur en direct","\u002Freacteur",{"label":93,"href":94,"external":67},"Le Drill (entraînement)","\u002Fdrill",{"label":96,"href":97,"external":67},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":99,"href":100,"external":67},"Les agents IA","\u002Fagents-ia",{"label":102,"href":103,"external":67},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":105,"href":106,"external":67},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":108,"links":109},"Ressources",[110,113,116,119,122,125],{"label":111,"href":112,"external":67},"Blog","\u002Fblog",{"label":114,"href":115,"external":67},"Academy","\u002Facademy",{"label":117,"href":118,"external":67},"Dictionnaire","\u002Fdictionnaire",{"label":120,"href":121,"external":67},"Expertise PrestaShop","\u002Fexpertise",{"label":123,"href":124,"external":67},"Flywheel","\u002Fflywheel",{"label":126,"href":127,"external":67},"Manifeste","\u002Fmanifeste",{"title":129,"links":130},"À propos",[131,134,137],{"label":132,"href":133,"external":67},"Alexandre Carette","\u002Fa-propos",{"label":135,"href":136,"external":67},"Dossier de presse","\u002Fpresse",{"label":138,"href":139,"external":67},"Contact","\u002Fcontact",{"items":141},[142,151,157,163,171,179,185,190],{"id":143,"type":144,"label":145,"href":121,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":148,"children":149,"psChildren":150},41,"link",{"fr":146},"Expertise",null,0,[],[],{"id":152,"type":144,"label":153,"href":112,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":154,"children":155,"psChildren":156},42,{"fr":111},1,[],[],{"id":158,"type":144,"label":159,"href":73,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":160,"children":161,"psChildren":162},43,{"fr":72},2,[],[],{"id":164,"type":144,"label":165,"href":167,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":168,"children":169,"psChildren":170},44,{"fr":166},"Outils IA","\u002Foutils-ia",3,[],[],{"id":172,"type":144,"label":173,"href":66,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":175,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":176,"children":177,"psChildren":178},45,{"fr":174},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":180,"type":144,"label":181,"href":115,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":182,"children":183,"psChildren":184},46,{"fr":114},5,[],[],{"id":186,"type":144,"label":187,"href":133,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":55,"children":188,"psChildren":189},47,{"fr":129},[],[],{"id":191,"type":144,"label":192,"href":139,"icon":147,"description":147,"badge":147,"groupTitle":147,"style":147,"gridColumns":147,"cssClass":147,"psCategoryId":147,"showPsChildren":67,"position":193,"children":194,"psChildren":195},48,{"fr":138},7,[],[],{"footer":197},{"theme":198,"description":147,"hours":147,"logo":199,"contact":202,"social":203,"bottomBar":213},"dark",{"src":200,"href":201,"alt":132},"\u002Flogo-ac.svg","\u002F",{"email":147,"phone":147,"address":147,"cta":147},[204,207,210],{"platform":205,"href":206,"label":205},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":208,"href":209,"label":208},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":211,"href":212,"label":211},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":147},{"academy":215,"blog":216,"expertise":227},[],[217,221,224],{"title":218,"url":219,"score":154,"type":220},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":222,"url":223,"score":154,"type":220},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":225,"url":226,"score":154,"type":220},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[],{"header":229},{"logo":230,"topBar":233,"contactEmail":236,"features":237,"navBar":147},{"src":200,"alt":231,"text":132,"href":201,"class":232},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":147,"showLanguages":67,"align":234,"languages":235},"left",[],"contact@alexandrecarette.fr",{"showSearch":67,"showWishlist":67,"showLogin":20,"showContact":67,"showCart":67,"stickyHeader":20,"headerLayout":238},"inline"]