[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fF6kMk-0_oLSkfK4HZg-JIvIq5Cj_r3_uuFkmwEbYZ5g":22,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":61,"$f0hCx5Z7nF6y5GFnhl3FR9gB0wk8AK3fB0s7mGmWna4k":142,"footer-db":157,"megamenu":176,"header-db":230},{"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":34,"psVersions":35,"content":39,"faq":40,"tldr":56,"readingTime":57,"generatedAt":58,"publishDate":58,"relatedArticles":59,"sourceCategory":60},"Trier le menu PrestaShop par ordre alphabétique (blocktopmenu)","trier-menu-prestashop-ordre-alphabetique-blocktopmenu","Comment modifier le module blocktopmenu pour afficher les pages CMS et catégories par ordre alphabétique dans PrestaShop 1.6, 1.7 et 8.x.","developpement",[28,29,30,31,32,33],"blocktopmenu","menu","tri alphabétique","override","CMS","navigation","intermediaire",[36,37,38],"1.6","1.7","8.x","\u003Ch2>Le problème : un menu trié par position, pas par nom\u003C\u002Fh2>\n\u003Cp>Par défaut, le module \u003Cstrong>blocktopmenu\u003C\u002Fstrong> (devenu \u003Cstrong>ps_mainmenu\u003C\u002Fstrong> à partir de PrestaShop 1.7) affiche les pages CMS et les catégories CMS dans l'ordre défini par le champ \u003Ccode>position\u003C\u002Fcode> en base de données. C'est logique quand on gère manuellement quelques pages, mais dès que le catalogue de contenus grossit — 20, 30 pages CMS ou plus — le tri alphabétique devient indispensable pour offrir une navigation claire à vos visiteurs.\u003C\u002Fp>\n\u003Cp>La solution consiste à modifier les requêtes SQL des deux méthodes responsables du rendu des pages et catégories CMS dans le menu : \u003Ccode>getCMSPages()\u003C\u002Fcode> et \u003Ccode>getCMSCategories()\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2>Solution : modifier le ORDER BY des requêtes SQL\u003C\u002Fh2>\n\u003Ch3>Étape 1 — Identifier les méthodes concernées\u003C\u002Fh3>\n\u003Cp>Deux méthodes dans le fichier principal du module contrôlent la récupération des éléments CMS :\u003C\u002Fp>\n\u003Ctr>\u003Cth>Méthode\u003C\u002Fth>\u003Cth>Rôle\u003C\u002Fth>\u003Cth>Fichier\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`getCMSPages()`\u003C\u002Fth>\u003Cth>Récupère les pages CMS d'une catégorie\u003C\u002Fth>\u003Cth>`blocktopmenu.php` (1.6) ou `ps_mainmenu.php` (1.7+)\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`getCMSCategories()`\u003C\u002Fth>\u003Cth>Récupère les catégories CMS\u003C\u002Fth>\u003Cth>Idem\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ch3>Étape 2 — Modifier getCMSPages()\u003C\u002Fh3>\n\u003Cp>Dans la méthode \u003Ccode>getCMSPages()\u003C\u002Fcode>, repérez la clause \u003Ccode>ORDER BY\u003C\u002Fcode> en fin de requête SQL :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F AVANT — tri par position manuelle\nORDER BY `position`\n\n\u002F\u002F APRÈS — tri alphabétique par titre\nORDER BY cl.`meta_title` ASC\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Voici la méthode complète modifiée :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\nprotected function getCMSPages($id_cms_category, $id_shop = false, $id_lang = false)\n{\n    $id_shop = ($id_shop !== false) ? (int)$id_shop : (int)Context::getContext()-&gt;shop-&gt;id;\n    $id_lang = $id_lang ? (int)$id_lang : (int)Context::getContext()-&gt;language-&gt;id;\n\n    $where_shop = '';\n    if (Tools::version_compare(_PS_VERSION_, '1.6.0.12', '&gt;=') == true) {\n        $where_shop = ' AND cl.`id_shop` = ' . (int)$id_shop;\n    }\n\n    $sql = 'SELECT c.`id_cms`, cl.`meta_title`, cl.`link_rewrite`\n        FROM `' . _DB_PREFIX_ . 'cms` c\n        INNER JOIN `' . _DB_PREFIX_ . 'cms_shop` cs\n          ON (c.`id_cms` = cs.`id_cms`)\n        INNER JOIN `' . _DB_PREFIX_ . 'cms_lang` cl\n          ON (c.`id_cms` = cl.`id_cms`)\n        WHERE c.`id_cms_category` = ' . (int)$id_cms_category . '\n          AND cs.`id_shop` = ' . (int)$id_shop . '\n          AND cl.`id_lang` = ' . (int)$id_lang .\n        $where_shop . '\n          AND c.`active` = 1\n        ORDER BY cl.`meta_title` ASC';\n\n    return Db::getInstance()-&gt;executeS($sql);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Étape 3 — Modifier getCMSCategories()\u003C\u002Fh3>\n\u003Cp>Même principe pour les catégories CMS. Remplacez \u003Ccode>ORDER BY\u003C\u002Fcode> \u003Ccode>position\u003C\u002Fcode> par un tri sur \u003Ccode>cl.name\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F AVANT\nORDER BY `position`\n\n\u002F\u002F APRÈS\nORDER BY cl.`name` ASC\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Extrait de la méthode modifiée (partie requête non-récursive) :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\nprotected function getCMSCategories($recursive = false, $parent = 1, $id_lang = false, $id_shop = false)\n{\n    $id_lang = $id_lang ? (int)$id_lang : (int)Context::getContext()-&gt;language-&gt;id;\n    $id_shop = ($id_shop !== false) ? $id_shop : Context::getContext()-&gt;shop-&gt;id;\n\n    $join_shop = '';\n    $where_shop = '';\n\n    if (Tools::version_compare(_PS_VERSION_, '1.6.0.12', '&gt;=') == true) {\n        $join_shop = ' INNER JOIN `' . _DB_PREFIX_ . 'cms_category_shop` cs\n            ON (bcp.`id_cms_category` = cs.`id_cms_category`)';\n        $where_shop = ' AND cs.`id_shop` = ' . (int)$id_shop\n            . ' AND cl.`id_shop` = ' . (int)$id_shop;\n    }\n\n    if ($recursive === false) {\n        $sql = 'SELECT bcp.`id_cms_category`, bcp.`id_parent`, bcp.`level_depth`,\n                bcp.`active`, bcp.`position`, cl.`name`, cl.`link_rewrite`\n            FROM `' . _DB_PREFIX_ . 'cms_category` bcp'\n            . $join_shop . '\n            INNER JOIN `' . _DB_PREFIX_ . 'cms_category_lang` cl\n              ON (bcp.`id_cms_category` = cl.`id_cms_category`)\n            WHERE bcp.`id_parent` = ' . (int)$parent . '\n              AND cl.`id_lang` = ' . (int)$id_lang .\n            $where_shop . '\n              AND bcp.`active` = 1\n            ORDER BY cl.`name` ASC';\n    }\n    \u002F\u002F ... suite de la méthode pour le mode récursif\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Point important :\u003C\u002Fstrong> le champ s'appelle \u003Ccode>cl.name\u003C\u002Fcode> (et non \u003Ccode>cl.meta_title\u003C\u002Fcode>) car la table \u003Ccode>cms_category_lang\u003C\u002Fcode> utilise la colonne \u003Ccode>name\u003C\u002Fcode> tandis que \u003Ccode>cms_lang\u003C\u002Fcode> utilise \u003Ccode>meta_title\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2>Bonne pratique : utiliser un override plutôt qu'une modification directe\u003C\u002Fh2>\n\u003Cp>Modifier directement le fichier du module fonctionne, mais vos changements seront écrasés à la prochaine mise à jour du module. La solution propre consiste à créer un \u003Cstrong>override\u003C\u002Fstrong> :\u003C\u002Fp>\n\u003Ch3>PrestaShop 1.6\u003C\u002Fh3>\n\u003Cp>Créez le fichier \u003Ccode>override\u002Fmodules\u002Fblocktopmenu\u002Fblocktopmenu.php\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\nif (!defined('_PS_VERSION_')) {\n    exit;\n}\n\nclass BlockTopMenuOverride extends BlockTopMenu\n{\n    protected function getCMSPages($id_cms_category, $id_shop = false, $id_lang = false)\n    {\n        \u002F\u002F Coller ici la méthode modifiée avec ORDER BY cl.`meta_title` ASC\n    }\n\n    protected function getCMSCategories($recursive = false, $parent = 1, $id_lang = false, $id_shop = false)\n    {\n        \u002F\u002F Coller ici la méthode modifiée avec ORDER BY cl.`name` ASC\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Puis videz le cache PrestaShop pour que l'override soit pris en compte.\u003C\u002Fp>\n\u003Ch3>PrestaShop 1.7 et 8.x — ps_mainmenu\u003C\u002Fh3>\n\u003Cp>À partir de PrestaShop 1.7, le module s'appelle \u003Cstrong>ps_mainmenu\u003C\u002Fstrong>. Le principe reste identique, mais le fichier d'override se place dans :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-\">\noverride\u002Fmodules\u002Fps_mainmenu\u002Fps_mainmenu.php\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Sur PrestaShop 8.x, les requêtes SQL sont similaires mais vérifiez que la structure des tables n'a pas évolué dans votre version. La logique \u003Ccode>ORDER BY cl.name ASC\u003C\u002Fcode> reste valide.\u003C\u002Fp>\n\u003Ch2>Alternative moderne : tri côté template avec Smarty\u003C\u002Fh2>\n\u003Cp>Si vous ne souhaitez pas toucher au PHP, une alternative consiste à trier les éléments directement dans le template Smarty via le modificateur \u003Ccode>sort\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-smarty\">\n{foreach from=$cms_pages|@ksort item=page}\n    &lt;li&gt;&lt;a href=\"{$page.link}\"&gt;{$page.meta_title}&lt;\u002Fa&gt;&lt;\u002Fli&gt;\n{\u002Fforeach}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette approche est moins performante (le tri se fait à chaque affichage plutôt qu'en base de données) et offre moins de contrôle, mais elle a l'avantage de ne nécessiter aucune modification PHP.\u003C\u002Fp>\n\u003Ch2>Considérations pour le tri alphabétique\u003C\u002Fh2>\n\u003Ch3>Collation et accents\u003C\u002Fh3>\n\u003Cp>Le tri SQL dépend de la \u003Cstrong>collation\u003C\u002Fstrong> de votre base de données. Avec \u003Ccode>utf8_general_ci\u003C\u002Fcode> (par défaut sur PrestaShop), les caractères accentués sont triés correctement (é après e, etc.). Si vous utilisez \u003Ccode>utf8mb4_unicode_ci\u003C\u002Fcode>, le tri sera encore plus précis pour les langues européennes.\u003C\u002Fp>\n\u003Ch3>Boutiques multilingues\u003C\u002Fh3>\n\u003Cp>Le tri alphabétique se fait naturellement dans la langue active grâce au filtre \u003Ccode>cl.id_lang\u003C\u002Fcode>. Chaque langue aura donc son propre ordre alphabétique, ce qui est le comportement attendu.\u003C\u002Fp>\n\u003Ch3>Performance\u003C\u002Fh3>\n\u003Cp>Remplacer \u003Ccode>ORDER BY position\u003C\u002Fcode> par \u003Ccode>ORDER BY cl.name ASC\u003C\u002Fcode> n'a aucun impact mesurable sur les performances. Les tables CMS contiennent rarement plus de quelques centaines de lignes, et MariaDB\u002FMySQL gère ce tri de manière transparente.\u003C\u002Fp>",[41,44,47,50,53],{"q":42,"a":43},"Comment trier le menu principal de PrestaShop par ordre alphabétique ?","Modifiez les méthodes getCMSPages() et getCMSCategories() dans le fichier du module blocktopmenu (PrestaShop 1.6) ou ps_mainmenu (PrestaShop 1.7\u002F8.x) en remplaçant ORDER BY `position` par ORDER BY cl.`meta_title` ASC pour les pages et ORDER BY cl.`name` ASC pour les catégories. Utilisez de préférence un override pour ne pas perdre vos modifications lors des mises à jour.",{"q":45,"a":46},"Quelle est la différence entre blocktopmenu et ps_mainmenu ?","blocktopmenu est le nom du module de menu principal dans PrestaShop 1.6. À partir de PrestaShop 1.7, il a été renommé ps_mainmenu. La logique interne reste très similaire, notamment les méthodes getCMSPages() et getCMSCategories() qui fonctionnent de la même manière.",{"q":48,"a":49},"Pourquoi utiliser un override plutôt que modifier directement le module ?","Un override préserve vos modifications lors des mises à jour du module. Si vous modifiez directement blocktopmenu.php ou ps_mainmenu.php, vos changements seront écrasés à chaque mise à jour. L'override se place dans le dossier override\u002Fmodules\u002F et surcharge uniquement les méthodes que vous souhaitez modifier.",{"q":51,"a":52},"Le tri alphabétique fonctionne-t-il avec les caractères accentués en français ?","Oui, grâce à la collation de la base de données. PrestaShop utilise par défaut utf8_general_ci qui gère correctement les accents français. Le tri SQL classera correctement les mots commençant par é, è, ê après les mots en e, de manière naturelle pour un lecteur francophone.",{"q":54,"a":55},"Comment trier aussi les catégories produits par ordre alphabétique dans le menu ?","Les catégories produits sont gérées par une méthode différente dans le module de menu. Recherchez la méthode qui construit l'arbre de catégories (souvent generateCategoriesMenu) et appliquez le même principe : remplacez le ORDER BY position par ORDER BY cl.name ASC dans la requête SQL correspondante, toujours via un override.","Pour trier le menu blocktopmenu (ou ps_mainmenu) par ordre alphabétique, remplacez ORDER BY `position` par ORDER BY cl.`meta_title` ASC dans getCMSPages() et ORDER BY cl.`name` ASC dans getCMSCategories(), idéalement via un override pour survivre aux mises à jour.",5,"2026-03-21T13:31:50.000Z",[],"PrestaShop pour les développeurs",{"columns":62},[63,79,109,130],{"title":64,"links":65},"Plateforme",[66,70,73,76],{"label":67,"href":68,"external":69},"Offre Starter (2 500 €)","\u002Foffre-starter",false,{"label":71,"href":72,"external":69},"Devenir Ambassadeur","\u002Fambassadeur",{"label":74,"href":75,"external":69},"Modules PrestaShop","\u002Fmodules",{"label":77,"href":78,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":80,"links":81},"Le Synedre",[82,85,88,91,94,97,100,103,106],{"label":83,"href":84,"external":69},"L'histoire","\u002Fsynedre",{"label":86,"href":87,"external":69},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":89,"href":90,"external":69},"L'équipe","\u002Fequipe",{"label":92,"href":93,"external":69},"Le réacteur en direct","\u002Freacteur",{"label":95,"href":96,"external":69},"Le Drill (entraînement)","\u002Fdrill",{"label":98,"href":99,"external":69},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":101,"href":102,"external":69},"Les agents IA","\u002Fagents-ia",{"label":104,"href":105,"external":69},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":107,"href":108,"external":69},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":110,"links":111},"Ressources",[112,115,118,121,124,127],{"label":113,"href":114,"external":69},"Blog","\u002Fblog",{"label":116,"href":117,"external":69},"Academy","\u002Facademy",{"label":119,"href":120,"external":69},"Dictionnaire","\u002Fdictionnaire",{"label":122,"href":123,"external":69},"Expertise PrestaShop","\u002Fexpertise",{"label":125,"href":126,"external":69},"Flywheel","\u002Fflywheel",{"label":128,"href":129,"external":69},"Manifeste","\u002Fmanifeste",{"title":131,"links":132},"À propos",[133,136,139],{"label":134,"href":135,"external":69},"Alexandre Carette","\u002Fa-propos",{"label":137,"href":138,"external":69},"Dossier de presse","\u002Fpresse",{"label":140,"href":141,"external":69},"Contact","\u002Fcontact",{"academy":143,"blog":144,"expertise":156},[],[145,150,153],{"title":146,"url":147,"score":148,"type":149},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back",1,"blog",{"title":151,"url":152,"score":148,"type":149},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":154,"url":155,"score":148,"type":149},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[],{"footer":158},{"theme":159,"description":160,"hours":160,"logo":161,"contact":164,"social":165,"bottomBar":175},"dark",null,{"src":162,"href":163,"alt":134},"\u002Flogo-ac.svg","\u002F",{"email":160,"phone":160,"address":160,"cta":160},[166,169,172],{"platform":167,"href":168,"label":167},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":170,"href":171,"label":170},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":173,"href":174,"label":173},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":160},{"items":177},[178,186,191,197,205,213,218,224],{"id":179,"type":180,"label":181,"href":123,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":160,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":183,"children":184,"psChildren":185},41,"link",{"fr":182},"Expertise",0,[],[],{"id":187,"type":180,"label":188,"href":114,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":160,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":148,"children":189,"psChildren":190},42,{"fr":113},[],[],{"id":192,"type":180,"label":193,"href":75,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":160,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":194,"children":195,"psChildren":196},43,{"fr":74},2,[],[],{"id":198,"type":180,"label":199,"href":201,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":160,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":202,"children":203,"psChildren":204},44,{"fr":200},"Outils IA","\u002Foutils-ia",3,[],[],{"id":206,"type":180,"label":207,"href":68,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":209,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":210,"children":211,"psChildren":212},45,{"fr":208},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":214,"type":180,"label":215,"href":117,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":160,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":57,"children":216,"psChildren":217},46,{"fr":116},[],[],{"id":219,"type":180,"label":220,"href":135,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":160,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":221,"children":222,"psChildren":223},47,{"fr":131},6,[],[],{"id":225,"type":180,"label":226,"href":141,"icon":160,"description":160,"badge":160,"groupTitle":160,"style":160,"gridColumns":160,"cssClass":160,"psCategoryId":160,"showPsChildren":69,"position":227,"children":228,"psChildren":229},48,{"fr":140},7,[],[],{"header":231},{"logo":232,"topBar":235,"contactEmail":238,"features":239,"navBar":160},{"src":162,"alt":233,"text":134,"href":163,"class":234},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":160,"showLanguages":69,"align":236,"languages":237},"left",[],"contact@alexandrecarette.fr",{"showSearch":69,"showWishlist":69,"showLogin":20,"showContact":69,"showCart":69,"stickyHeader":20,"headerLayout":240},"inline"]