[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":22,"$f_WqhWqwzQMk80nOdNlgunlHGSN2yTB6n0I97lQpZQYk":103,"megamenu":148,"footer-db":204,"header-db":222,"$fp3VTs1h0vPUusA-H2lvxBZ-QgYZnJBfNJNeGpYE1UI8":233},{"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":115,"psVersions":116,"content":120,"faq":121,"tldr":143,"readingTime":144,"generatedAt":145,"publishDate":145,"relatedArticles":146,"sourceCategory":147},"Gérer les réponses AJAX dans un module PrestaShop : validation et UX","gerer-reponses-ajax-module-prestashop-validation-ux","Apprenez à gérer proprement les réponses AJAX dans un module PrestaShop : validation côté serveur, affichage conditionnel des erreurs et contrôle du bouton submit.","developpement",[109,110,111,112,113,114],"ajax","module prestashop","javascript","validation formulaire","jquery","front-end","intermediaire",[117,118,119],"1.6","1.7","8.x","\u003Ch2>Introduction\u003C\u002Fh2>\n\u003Cp>Lorsqu'on développe un module PrestaShop avec un formulaire côté front-office, la gestion AJAX des soumissions est incontournable pour offrir une expérience utilisateur fluide. Un point technique revient souvent : comment différencier les cas de succès et d'erreur dans le callback \u003Ccode>success\u003C\u002Fcode> de jQuery, afin d'adapter le comportement de l'interface — par exemple désactiver le bouton d'envoi uniquement après un envoi réussi, tout en affichant les erreurs de validation sans bloquer le formulaire.\u003C\u002Fp>\n\u003Cp>Cet article détaille l'architecture complète d'un formulaire AJAX dans un module PrestaShop, de la structure JSON côté PHP au traitement conditionnel côté JavaScript.\u003C\u002Fp>\n\u003Ch2>Architecture de la réponse JSON côté PHP\u003C\u002Fh2>\n\u003Cp>Le principe fondamental est de renvoyer un objet JSON structuré depuis le fichier PHP de traitement AJAX. Cette réponse doit contenir au minimum deux informations : un indicateur de succès et les messages associés.\u003C\u002Fp>\n\u003Ch3>Structure recommandée\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F\u002F modules\u002Fmonmodule\u002Fajax.php\n\nrequire_once dirname(__FILE__) . '\u002F..\u002F..\u002Fconfig\u002Fconfig.inc.php';\nrequire_once dirname(__FILE__) . '\u002F..\u002F..\u002Finit.php';\n\n\u002F\u002F Vérification du token CSRF (obligatoire en 8.x)\nif (!Tools::getToken(false)) {\n    die(json_encode([\n        'success' =&gt; false,\n        'errors' =&gt; ['security' =&gt; 'Token de sécurité invalide.']\n    ]));\n}\n\nif (Tools::getValue('ajax') === 'true') {\n    $errors = [];\n    $email = Tools::getValue('from');\n    $tel = Tools::getValue('tel');\n    $idContact = (int) Tools::getValue('id_contact');\n\n    \u002F\u002F Validation email\n    if (empty($email) || !Validate::isEmail($email)) {\n        $errors['from'] = 'Veuillez saisir une adresse email valide.';\n    }\n\n    \u002F\u002F Validation téléphone\n    if (empty($tel) || !Validate::isPhoneNumber($tel)) {\n        $errors['tel'] = 'Veuillez saisir un numéro de téléphone valide.';\n    }\n\n    \u002F\u002F Validation contact\n    if ($idContact &lt;= 0) {\n        $errors['id_contact'] = 'Veuillez sélectionner un contact.';\n    }\n\n    if (!empty($errors)) {\n        die(json_encode([\n            'success' =&gt; false,\n            'errors' =&gt; $errors\n        ]));\n    }\n\n    \u002F\u002F Traitement métier (envoi email, insertion BDD, etc.)\n    \u002F\u002F ...\n\n    die(json_encode([\n        'success' =&gt; true,\n        'message' =&gt; 'Votre demande a bien été envoyée. Nous vous recontactons rapidement.'\n    ]));\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Le point clé : le champ \u003Ccode>success\u003C\u002Fcode> (booléen) permet au JavaScript de brancher sa logique. Le champ \u003Ccode>errors\u003C\u002Fcode> est un objet associatif où chaque clé correspond à un champ du formulaire, ce qui facilite l'affichage ciblé des erreurs.\u003C\u002Fp>\n\u003Ch3>Utiliser les classes Validate de PrestaShop\u003C\u002Fh3>\n\u003Cp>PrestaShop fournit la classe \u003Ccode>Validate\u003C\u002Fcode> avec des dizaines de méthodes statiques prêtes à l'emploi. Utilisez-les systématiquement plutôt que des regex maison :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>`Validate::isEmail($value)` — validation email\u003C\u002Fli>\n\u003Cli>`Validate::isPhoneNumber($value)` — numéro de téléphone\u003C\u002Fli>\n\u003Cli>`Validate::isCleanHtml($value)` — protection XSS\u003C\u002Fli>\n\u003Cli>`Validate::isGenericName($value)` — noms sans caractères spéciaux dangereux\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>Traitement conditionnel en JavaScript\u003C\u002Fh2>\n\u003Cp>Côté front-end, le callback \u003Ccode>success\u003C\u002Fcode> de \u003Ccode>$.ajax\u003C\u002Fcode> se déclenche dès que le serveur renvoie une réponse HTTP 200, \u003Cstrong>quel que soit le contenu\u003C\u002Fstrong>. C'est pourquoi il faut tester le champ \u003Ccode>success\u003C\u002Fcode> du JSON pour différencier un envoi réussi d'une erreur de validation.\u003C\u002Fp>\n\u003Ch3>Implémentation complète\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-javascript\">\n$(document).ready(function () {\n  var $form = $('.callback');\n  var $submitBtn = $form.find('[type=\"submit\"]');\n  var $result = $('#result');\n\n  $form.on('submit', function (e) {\n    e.preventDefault();\n\n    \u002F\u002F Nettoyage des erreurs précédentes\n    $result.empty();\n    $form.find('.field-error').removeClass('field-error');\n\n    $.ajax({\n      type: 'POST',\n      url: baseDir + 'modules\u002Fmonmodule\u002Fajax.php',\n      data: $form.serialize() + '&ajax=true',\n      dataType: 'json',\n      beforeSend: function () {\n        $submitBtn.prop('disabled', true).text('Envoi en cours...');\n      },\n      success: function (response) {\n        if (response.success) {\n          \u002F\u002F Succès : afficher le message et verrouiller le formulaire\n          $result\n            .removeClass('alert-danger')\n            .addClass('alert alert-success')\n            .html(response.message);\n          $submitBtn.prop('disabled', true).text('Message envoyé');\n        } else {\n          \u002F\u002F Erreurs de validation : afficher et réactiver le bouton\n          $submitBtn.prop('disabled', false).text('Envoyer');\n          var errorHtml = '&lt;ul&gt;';\n          $.each(response.errors, function (field, message) {\n            errorHtml += '&lt;li&gt;' + message + '&lt;\u002Fli&gt;';\n            \u002F\u002F Surbrillance du champ en erreur\n            $('#' + field).addClass('field-error');\n          });\n          errorHtml += '&lt;\u002Ful&gt;';\n          $result\n            .removeClass('alert-success')\n            .addClass('alert alert-danger')\n            .html(errorHtml);\n        }\n      },\n      error: function () {\n        $submitBtn.prop('disabled', false).text('Envoyer');\n        $result\n          .addClass('alert alert-danger')\n          .html('Une erreur technique est survenue. Veuillez réessayer.');\n      }\n    });\n  });\n});\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Points techniques importants\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>\u003Ccode>e.preventDefault()\u003C\u002Fcode> vs \u003Ccode>return false\u003C\u002Fcode>\u003C\u002Fstrong> : Les deux empêchent la soumission classique du formulaire, mais \u003Ccode>e.preventDefault()\u003C\u002Fcode> est préférable. \u003Ccode>return false\u003C\u002Fcode> appelle également \u003Ccode>stopPropagation()\u003C\u002Fcode>, ce qui peut bloquer d'autres écouteurs d'événements (modules analytics, hooks JavaScript de PrestaShop).\u003C\u002Fp>\n\u003Cp>\u003Cstrong>\u003Ccode>$form.serialize()\u003C\u002Fcode>\u003C\u002Fstrong> plutôt que la concaténation manuelle : la sérialisation automatique est plus fiable, gère l'encodage URL des caractères spéciaux et s'adapte si vous ajoutez des champs au formulaire.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>\u003Ccode>.prop('disabled', true)\u003C\u002Fcode> vs \u003Ccode>.attr('disabled', true)\u003C\u002Fcode>\u003C\u002Fstrong> : Depuis jQuery 1.6, \u003Ccode>.prop()\u003C\u002Fcode> est la méthode correcte pour les propriétés booléennes comme \u003Ccode>disabled\u003C\u002Fcode>, \u003Ccode>checked\u003C\u002Fcode> ou \u003Ccode>selected\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2>Adaptation pour PrestaShop 8.x\u003C\u002Fh2>\n\u003Cp>Sur PrestaShop 8.x, plusieurs ajustements sont nécessaires par rapport aux versions 1.6\u002F1.7.\u003C\u002Fp>\n\u003Ch3>Utiliser un contrôleur front plutôt qu'un fichier PHP direct\u003C\u002Fh3>\n\u003Cp>L'accès direct à un fichier PHP dans le dossier du module (\u003Ccode>modules\u002Fmonmodule\u002Fajax.php\u003C\u002Fcode>) fonctionne mais n'est pas la bonne pratique sur PS 8.x. Préférez un \u003Ccode>ModuleFrontController\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F\u002F modules\u002Fmonmodule\u002Fcontrollers\u002Ffront\u002Fajax.php\n\nclass MonModuleAjaxModuleFrontController extends ModuleFrontController\n{\n    public function initContent()\n    {\n        \u002F\u002F Désactiver le rendu du template\n        $this-&gt;ajax = true;\n        parent::initContent();\n    }\n\n    public function displayAjax()\n    {\n        $errors = [];\n        $email = Tools::getValue('from');\n        $tel = Tools::getValue('tel');\n\n        if (empty($email) || !Validate::isEmail($email)) {\n            $errors['from'] = 'Adresse email invalide.';\n        }\n\n        if (empty($tel) || !Validate::isPhoneNumber($tel)) {\n            $errors['tel'] = 'Numéro de téléphone invalide.';\n        }\n\n        if (!empty($errors)) {\n            $this-&gt;ajaxRender(json_encode([\n                'success' =&gt; false,\n                'errors' =&gt; $errors\n            ]));\n            return;\n        }\n\n        \u002F\u002F Traitement...\n\n        $this-&gt;ajaxRender(json_encode([\n            'success' =&gt; true,\n            'message' =&gt; 'Demande envoyée avec succès.'\n        ]));\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>L'URL AJAX côté JavaScript devient alors :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-javascript\">\nurl: prestashop.urls.base_url + 'module\u002Fmonmodule\u002Fajax'\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Sécurité CSRF avec les tokens\u003C\u002Fh3>\n\u003Cp>Sur PrestaShop 8.x, pensez à inclure le token dans vos requêtes AJAX :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-javascript\">\ndata: $form.serialize() + '&ajax=true&token=' + prestashop.static_token,\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>JavaScript sans jQuery\u003C\u002Fh3>\n\u003Cp>PrestaShop 8.x charge encore jQuery, mais si vous développez un module tourné vers l'avenir, voici l'équivalent en JavaScript vanilla avec \u003Ccode>fetch\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-javascript\">\ndocument.addEventListener('DOMContentLoaded', function () {\n  const form = document.querySelector('.callback');\n  const submitBtn = form.querySelector('[type=\"submit\"]');\n  const resultDiv = document.getElementById('result');\n\n  form.addEventListener('submit', async function (e) {\n    e.preventDefault();\n    resultDiv.innerHTML = '';\n    submitBtn.disabled = true;\n    submitBtn.textContent = 'Envoi en cours...';\n\n    try {\n      const formData = new FormData(form);\n      formData.append('ajax', 'true');\n\n      const response = await fetch(\n        prestashop.urls.base_url + 'module\u002Fmonmodule\u002Fajax',\n        { method: 'POST', body: formData }\n      );\n      const data = await response.json();\n\n      if (data.success) {\n        resultDiv.className = 'alert alert-success';\n        resultDiv.textContent = data.message;\n      } else {\n        submitBtn.disabled = false;\n        submitBtn.textContent = 'Envoyer';\n        resultDiv.className = 'alert alert-danger';\n        resultDiv.innerHTML = Object.values(data.errors)\n          .map(msg =&gt; '&lt;p&gt;' + msg + '&lt;\u002Fp&gt;')\n          .join('');\n      }\n    } catch (err) {\n      submitBtn.disabled = false;\n      submitBtn.textContent = 'Envoyer';\n      resultDiv.className = 'alert alert-danger';\n      resultDiv.textContent = 'Erreur technique. Veuillez réessayer.';\n    }\n  });\n});\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Bonnes pratiques UX pour les formulaires AJAX\u003C\u002Fh2>\n\u003Ch3>Feedback visuel immédiat\u003C\u002Fh3>\n\u003Cp>Désactivez le bouton dès le clic (\u003Ccode>beforeSend\u003C\u002Fcode>) pour éviter les doubles soumissions, mais réactivez-le en cas d'erreur de validation. Le texte du bouton doit refléter l'état : « Envoyer » → « Envoi en cours... » → « Message envoyé » ou retour à « Envoyer ».\u003C\u002Fp>\n\u003Ch3>Affichage ciblé des erreurs\u003C\u002Fh3>\n\u003Cp>Plutôt qu'un message d'erreur global, associez chaque erreur au champ concerné. Le CSS minimal pour la surbrillance :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-css\">\n.field-error {\n  border-color: #e74c3c !important;\n  box-shadow: 0 0 0 2px rgba(231, 76, 60, 0.2);\n}\n\n.alert {\n  padding: 12px 16px;\n  border-radius: 4px;\n  margin-top: 10px;\n}\n.alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }\n.alert-danger { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Gestion du callback `error`\u003C\u002Fh3>\n\u003Cp>N'oubliez jamais le callback \u003Ccode>error\u003C\u002Fcode> de \u003Ccode>$.ajax\u003C\u002Fcode>. Sans lui, une erreur réseau ou serveur (timeout, 500) laissera l'utilisateur face à un bouton désactivé sans explication.\u003C\u002Fp>\n\u003Ch2>Erreurs courantes à éviter\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>**Oublier `dataType: 'json'`** : sans cette option, jQuery ne parse pas automatiquement la réponse et `jsonData` sera une chaîne brute.\u003C\u002Fli>\n\u003Cli>**Concaténer les données manuellement** : `'data=true&from=' + val` est fragile. `$form.serialize()` gère l'encodage et évolue avec le formulaire.\u003C\u002Fli>\n\u003Cli>**Appeler `die()` sans `header('Content-Type: application\u002Fjson')`** : certains navigateurs peuvent mal interpréter la réponse. Ajoutez toujours l'en-tête.\u003C\u002Fli>\n\u003Cli>**Mélanger `html()` pour succès et erreurs dans le même conteneur** sans réinitialiser les classes CSS : l'utilisateur voit un message de succès stylé en rouge, ou inversement.\u003C\u002Fli>\n\u003C\u002Ful>",[122,125,128,131,134,137,140],{"q":123,"a":124},"Comment empêcher la double soumission d'un formulaire AJAX dans PrestaShop ?","Désactivez le bouton submit dans le callback beforeSend de $.ajax avec $submitBtn.prop('disabled', true), puis réactivez-le uniquement en cas d'erreur de validation ou d'erreur réseau (callback error). En cas de succès, le bouton reste désactivé pour empêcher tout renvoi.",{"q":126,"a":127},"Faut-il utiliser un fichier PHP direct ou un ModuleFrontController pour l'AJAX PrestaShop ?","Sur PrestaShop 1.6, un fichier PHP dans le dossier du module était courant. Sur PrestaShop 1.7 et 8.x, la bonne pratique est d'utiliser un ModuleFrontController avec la méthode displayAjax(). Cela garantit le chargement du contexte PrestaShop (tokens CSRF, cookies, multilingue) et respecte l'architecture MVC du CMS.",{"q":129,"a":130},"Comment afficher les erreurs de validation champ par champ en AJAX ?","Structurez votre réponse JSON avec un objet errors dont les clés correspondent aux identifiants des champs (ex: {\"errors\": {\"tel\": \"Numéro invalide\", \"from\": \"Email invalide\"}}). Côté JavaScript, parcourez cet objet avec $.each() pour afficher chaque message à côté du champ concerné et lui appliquer une classe CSS de surbrillance.",{"q":132,"a":133},"Quelle est la différence entre return false et e.preventDefault() dans un formulaire AJAX ?","e.preventDefault() empêche uniquement le comportement par défaut du formulaire (la soumission classique). return false fait la même chose mais appelle aussi stopPropagation(), ce qui bloque la propagation de l'événement aux éléments parents. Dans PrestaShop, préférez e.preventDefault() pour ne pas interférer avec d'autres scripts (analytics, hooks JS de modules).",{"q":135,"a":136},"Comment sécuriser une requête AJAX dans un module PrestaShop 8.x ?","Incluez le token statique de PrestaShop dans votre requête AJAX (prestashop.static_token) et vérifiez-le côté serveur. Utilisez systématiquement Tools::getValue() pour récupérer les données POST, Validate::isCleanHtml() pour prévenir les attaques XSS, et des requêtes préparées si vous interagissez avec la base de données.",{"q":138,"a":139},"Pourquoi ma réponse AJAX PrestaShop renvoie du texte au lieu du JSON ?","Trois causes fréquentes : vous n'avez pas ajouté header('Content-Type: application\u002Fjson') avant le die(json_encode(...)), vous n'avez pas spécifié dataType: 'json' dans l'appel $.ajax, ou PrestaShop injecte du HTML (notices PHP, debug toolbar) dans la sortie. Désactivez le mode debug et vérifiez qu'aucun echo ou var_dump ne précède votre json_encode.",{"q":141,"a":142},"Comment remplacer jQuery par du JavaScript natif pour l'AJAX dans PrestaShop 8 ?","Utilisez l'API Fetch avec async\u002Fawait. Créez un FormData à partir du formulaire, envoyez-le avec fetch() en POST, puis parsez la réponse avec response.json(). L'avantage : aucune dépendance externe, meilleure performance, et compatibilité native avec tous les navigateurs modernes. PrestaShop 8 charge encore jQuery, mais cette approche prépare la transition.","Pour gérer différentes actions dans le callback success d'une requête AJAX PrestaShop, structurez votre réponse PHP en JSON avec un champ booléen success et un objet errors associatif, puis branchez votre logique JavaScript (désactivation du bouton, affichage ciblé des erreurs) en fonction de ce flag.",7,"2026-03-21T14:29:20.000Z",[],"PrestaShop pour les développeurs",{"items":149},[150,159,165,171,179,187,193,199],{"id":151,"type":152,"label":153,"href":84,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":155,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":156,"children":157,"psChildren":158},41,"link",{"fr":154},"Expertise",null,0,[],[],{"id":160,"type":152,"label":161,"href":75,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":155,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":162,"children":163,"psChildren":164},42,{"fr":74},1,[],[],{"id":166,"type":152,"label":167,"href":36,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":155,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":168,"children":169,"psChildren":170},43,{"fr":35},2,[],[],{"id":172,"type":152,"label":173,"href":175,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":155,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":176,"children":177,"psChildren":178},44,{"fr":174},"Outils IA","\u002Foutils-ia",3,[],[],{"id":180,"type":152,"label":181,"href":29,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":183,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":184,"children":185,"psChildren":186},45,{"fr":182},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":188,"type":152,"label":189,"href":78,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":155,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":190,"children":191,"psChildren":192},46,{"fr":77},5,[],[],{"id":194,"type":152,"label":195,"href":96,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":155,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":196,"children":197,"psChildren":198},47,{"fr":92},6,[],[],{"id":200,"type":152,"label":201,"href":102,"icon":155,"description":155,"badge":155,"groupTitle":155,"style":155,"gridColumns":155,"cssClass":155,"psCategoryId":155,"showPsChildren":30,"position":144,"children":202,"psChildren":203},48,{"fr":101},[],[],{"footer":205},{"theme":206,"description":155,"hours":155,"logo":207,"contact":210,"social":211,"bottomBar":221},"dark",{"src":208,"href":209,"alt":95},"\u002Flogo-ac.svg","\u002F",{"email":155,"phone":155,"address":155,"cta":155},[212,215,218],{"platform":213,"href":214,"label":213},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":216,"href":217,"label":216},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":219,"href":220,"label":219},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":155},{"header":223},{"logo":224,"topBar":227,"contactEmail":230,"features":231,"navBar":155},{"src":208,"alt":225,"text":95,"href":209,"class":226},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":155,"showLanguages":30,"align":228,"languages":229},"left",[],"contact@alexandrecarette.fr",{"showSearch":30,"showWishlist":30,"showLogin":20,"showContact":30,"showCart":30,"stickyHeader":20,"headerLayout":232},"inline",{"academy":234,"blog":235,"expertise":246},[],[236,240,243],{"title":237,"url":238,"score":162,"type":239},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":241,"url":242,"score":162,"type":239},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":244,"url":245,"score":162,"type":239},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[]]