💻 DéveloppementIntermédiaire PS 1.6 PS 1.7 PS 8.x

Trier le menu PrestaShop par ordre alphabétique (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.

En bref : 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.

Publié le 21 mars 2026 5 min de lecture Alexandre Carette

Le problème : un menu trié par position, pas par nom

Par défaut, le module blocktopmenu (devenu ps_mainmenu à partir de PrestaShop 1.7) affiche les pages CMS et les catégories CMS dans l'ordre défini par le champ position 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.

La solution consiste à modifier les requêtes SQL des deux méthodes responsables du rendu des pages et catégories CMS dans le menu : getCMSPages() et getCMSCategories().

Solution : modifier le ORDER BY des requêtes SQL

Étape 1 — Identifier les méthodes concernées

Deux méthodes dans le fichier principal du module contrôlent la récupération des éléments CMS :

MéthodeRôleFichier `getCMSPages()`Récupère les pages CMS d'une catégorie`blocktopmenu.php` (1.6) ou `ps_mainmenu.php` (1.7+) `getCMSCategories()`Récupère les catégories CMSIdem

Étape 2 — Modifier getCMSPages()

Dans la méthode getCMSPages(), repérez la clause ORDER BY en fin de requête SQL :


// AVANT — tri par position manuelle
ORDER BY `position`

// APRÈS — tri alphabétique par titre
ORDER BY cl.`meta_title` ASC

Voici la méthode complète modifiée :


protected function getCMSPages($id_cms_category, $id_shop = false, $id_lang = false)
{
    $id_shop = ($id_shop !== false) ? (int)$id_shop : (int)Context::getContext()->shop->id;
    $id_lang = $id_lang ? (int)$id_lang : (int)Context::getContext()->language->id;

    $where_shop = '';
    if (Tools::version_compare(_PS_VERSION_, '1.6.0.12', '>=') == true) {
        $where_shop = ' AND cl.`id_shop` = ' . (int)$id_shop;
    }

    $sql = 'SELECT c.`id_cms`, cl.`meta_title`, cl.`link_rewrite`
        FROM `' . _DB_PREFIX_ . 'cms` c
        INNER JOIN `' . _DB_PREFIX_ . 'cms_shop` cs
          ON (c.`id_cms` = cs.`id_cms`)
        INNER JOIN `' . _DB_PREFIX_ . 'cms_lang` cl
          ON (c.`id_cms` = cl.`id_cms`)
        WHERE c.`id_cms_category` = ' . (int)$id_cms_category . '
          AND cs.`id_shop` = ' . (int)$id_shop . '
          AND cl.`id_lang` = ' . (int)$id_lang .
        $where_shop . '
          AND c.`active` = 1
        ORDER BY cl.`meta_title` ASC';

    return Db::getInstance()->executeS($sql);
}

Étape 3 — Modifier getCMSCategories()

Même principe pour les catégories CMS. Remplacez ORDER BY position par un tri sur cl.name :


// AVANT
ORDER BY `position`

// APRÈS
ORDER BY cl.`name` ASC

Extrait de la méthode modifiée (partie requête non-récursive) :


protected function getCMSCategories($recursive = false, $parent = 1, $id_lang = false, $id_shop = false)
{
    $id_lang = $id_lang ? (int)$id_lang : (int)Context::getContext()->language->id;
    $id_shop = ($id_shop !== false) ? $id_shop : Context::getContext()->shop->id;

    $join_shop = '';
    $where_shop = '';

    if (Tools::version_compare(_PS_VERSION_, '1.6.0.12', '>=') == true) {
        $join_shop = ' INNER JOIN `' . _DB_PREFIX_ . 'cms_category_shop` cs
            ON (bcp.`id_cms_category` = cs.`id_cms_category`)';
        $where_shop = ' AND cs.`id_shop` = ' . (int)$id_shop
            . ' AND cl.`id_shop` = ' . (int)$id_shop;
    }

    if ($recursive === false) {
        $sql = 'SELECT bcp.`id_cms_category`, bcp.`id_parent`, bcp.`level_depth`,
                bcp.`active`, bcp.`position`, cl.`name`, cl.`link_rewrite`
            FROM `' . _DB_PREFIX_ . 'cms_category` bcp'
            . $join_shop . '
            INNER JOIN `' . _DB_PREFIX_ . 'cms_category_lang` cl
              ON (bcp.`id_cms_category` = cl.`id_cms_category`)
            WHERE bcp.`id_parent` = ' . (int)$parent . '
              AND cl.`id_lang` = ' . (int)$id_lang .
            $where_shop . '
              AND bcp.`active` = 1
            ORDER BY cl.`name` ASC';
    }
    // ... suite de la méthode pour le mode récursif
}

Point important : le champ s'appelle cl.name (et non cl.meta_title) car la table cms_category_lang utilise la colonne name tandis que cms_lang utilise meta_title.

Bonne pratique : utiliser un override plutôt qu'une modification directe

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 override :

PrestaShop 1.6

Créez le fichier override/modules/blocktopmenu/blocktopmenu.php :


<?php
if (!defined('_PS_VERSION_')) {
    exit;
}

class BlockTopMenuOverride extends BlockTopMenu
{
    protected function getCMSPages($id_cms_category, $id_shop = false, $id_lang = false)
    {
        // Coller ici la méthode modifiée avec ORDER BY cl.`meta_title` ASC
    }

    protected function getCMSCategories($recursive = false, $parent = 1, $id_lang = false, $id_shop = false)
    {
        // Coller ici la méthode modifiée avec ORDER BY cl.`name` ASC
    }
}

Puis videz le cache PrestaShop pour que l'override soit pris en compte.

PrestaShop 1.7 et 8.x — ps_mainmenu

À partir de PrestaShop 1.7, le module s'appelle ps_mainmenu. Le principe reste identique, mais le fichier d'override se place dans :


override/modules/ps_mainmenu/ps_mainmenu.php

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 ORDER BY cl.name ASC reste valide.

Alternative moderne : tri côté template avec Smarty

Si vous ne souhaitez pas toucher au PHP, une alternative consiste à trier les éléments directement dans le template Smarty via le modificateur sort :


{foreach from=$cms_pages|@ksort item=page}
    <li><a href="{$page.link}">{$page.meta_title}</a></li>
{/foreach}

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.

Considérations pour le tri alphabétique

Collation et accents

Le tri SQL dépend de la collation de votre base de données. Avec utf8_general_ci (par défaut sur PrestaShop), les caractères accentués sont triés correctement (é après e, etc.). Si vous utilisez utf8mb4_unicode_ci, le tri sera encore plus précis pour les langues européennes.

Boutiques multilingues

Le tri alphabétique se fait naturellement dans la langue active grâce au filtre cl.id_lang. Chaque langue aura donc son propre ordre alphabétique, ce qui est le comportement attendu.

Performance

Remplacer ORDER BY position par ORDER BY cl.name ASC n'a aucun impact mesurable sur les performances. Les tables CMS contiennent rarement plus de quelques centaines de lignes, et MariaDB/MySQL gère ce tri de manière transparente.

#blocktopmenu #menu #tri alphabétique #override #CMS #navigation

Questions fréquentes

Tout ce que vous devez savoir sur ce sujet.

Un projet PrestaShop ?

Discutons-en directement.

★★★★★

193 projets livrés

Gratuit & sans engagement — réponse sous 24h

Alexandre Carette

Alexandre Carette

Expert PrestaShop & Architecture E-commerce

Développeur PrestaShop depuis 2014, 193 projets livrés. Je conçois des architectures headless Nuxt + PrestaShop et des outils d'automatisation IA pour les e-commerçants.