Les menus de navigation WordPress sont générés par la fonction wp_nav_menu() qui demande énormément de ressources. Chaque onglet de menu nécessite au minimum une dizaine de requêtes vers la base de donnée. Imaginez, avec un menu de dix onglets, on arrive très vite à une centaine de requêtes qui vont ralentir le chargement des pages de votre site. Je vous propose d'améliorer les performances de cette fonction en regroupant toutes ces requêtes en une seule avec un peu de programmation.

Principe de fonctionnement

Le principe est d'utiliser deux hooks appartenant à la fonction wp_nav_menu() :

  • wp_nav_menu pour récupérer et enregistrer le menu HTML final généré par la fonction,
  • pre_wp_nav_menu pour court-circuiter la fonction avec le menu HTML précédemment enregistré.

Note : j'utiliserai les fonctions update_option() et get_option() pour enregistrer et obtenir le menu HTML plutôt que d'utiliser des transients avec les fonctions set_transient() et get_transient() qui nécessitent une requête supplémentaire pour vérifier si le transient existe.


La structure HTML d'un menu change en fonction du type de page (page, poste, archives, etc.) sur lequel on se trouve. Par exemple, sur la page "Nos engagements", l'onglet "Nos engagements" du menu principal s'affichera en plus clair grâce au code CSS pour indiquer que l'on se trouve bien sur la page courante. Cela est dû a une modification de la structure HTML du menu, soit en ajoutant une classe à l'onglet "Nos engagements", soit en changeant la balise <a> du lien de l'onglet par une balise <span>, etc.

Le but sera alors d'enregistrer les différentes structures HTML du menu grâce à la fonction update_option() qui ajoutera une nouvelle option à la table options de la base de donnée de votre site WordPress. Chaque option est créée ou appelée avec une clé unique. Si par exemple le menu a la même apparence sur la page d'accueil et sur la page des mentions légales, on fera appel à la même clé. Dans un premier temps nous allons créer une fonction qui sera utilisée dans les deux hooks et qui nous retournera cette clé :

function get_nav_option_name(){
        
    global $wp_query;
    $page = '_home';
        
    if( $wp_query->is_page && isset($wp_query->query['pagename']) ){
        $page = '_page_'.$wp_query->query['pagename'];
    }elseif( $wp_query->is_single ){
        $post_type = 'post';
        if( isset($wp_query->query['post_type']) ) $post_type = $wp_query->query['post_type'];
        $page = '_single_'.$post_type;
    }elseif( $wp_query->is_category ){
        $page = '_category_'.$wp_query->query['category_name'];
    }elseif( $wp_query->is_tax ){
        $page = '_tax_'.$wp_query->query['taxonomy'].'_'.$wp_query->query['term'];
    }elseif( $wp_query->is_posts_page ){
        $page = '_archive_post';
    }elseif( $wp_query->is_post_type_archive ){
        $page = '_archive_'.$wp_query->query['post_type'];
    }
    
    return $page;
}

Utilisation du hook wp_nav_menu

Ce hook placé à la fin de la fonction wp_nav_menu() va nous permettre d'enregistrer le menu HTML en insérant le code suivant, soit dans un plugin de votre conception, soit dans le fichier functions.php de votre thème :

function set_option_menu_html( $menu_html, $args ){
    
    if( $args->theme_location == 'main-menu' || $args->theme_location == 'top-menu' ){
        
        $option_name = 'nav_'.$args->theme_location.get_nav_option_name();
        
        update_option($option_name, $menu_html, false);
    }
    
    return $menu_html;
}

add_filter('wp_nav_menu', 'set_option_menu_html', 10, 2);

Utilisation du hook pre_wp_nav_menu

Ce hook placé au début de la fonction wp_nav_menu() va nous permettre de récupérer le menu HTML enregistré avec la méthode précédente et s'il existe pour la page actuelle, il va court-circuiter la fonction.

function get_option_menu_html( $null, $args ){
    
    if( $args->theme_location == 'main-menu' || $args->theme_location == 'top-menu' ){
        
        $option_name = 'nav_'.$args->theme_location.get_nav_option_name();
        
        if( false !== ( $menu_html = get_option($option_name) ) ){
	    $null = $menu_html;
        }
    }
    
    return $null;
}

add_filter('pre_wp_nav_menu', 'get_option_menu_html', 10, 2);

Dernière étape

Il suffira de parcourir chaque page de votre site afin d'enregistrer toutes les versions HTML différentes du menu en fonction des pages. Bien entendu, les conditions de ce code devront s'adapter à vos besoins : si vous créer d'autres types de pages spécifiques ou si certains onglets doivent s'afficher autrement, par exemple en fonction d'un utilisateur connecté et en fonction de son rôle. Vous aurez donc créé un certain nombre d'options qui seront chargées par défaut sur chaque page de votre site. Elles peuvent être relativement lourdes (beaucoup plus que les options natives utilisées par WordPress). Il peut alors être intéressant de régler l'autoload de ces options à off en mettant le 3e paramètre de la fonction update_option() à false. Au final cela résultera d'une requête en plus mais dérisoire comparée à toutes les requêtes que vous allez éviter en suivant cette astuce et qui contribuera à un site web plus performant.


Info : cette astuce n'est pas très adaptée à un menu où l'on modifierait les onglets régulièrement. Par exemple, dans le cas où l'on veut mettre en évidence un nouvel article ou produit et l'afficher dans le menu principal. Si celui-ci change chaque semaine, voir chaque jour, il faudra refaire la manip suivante à chaque fois :

  • désactiver le hook pre_wp_nav_menu pour enlever le coupe-circuit,
  • parcourir votre site afin d'enregistrer votre nouveau menu HTML pour chaque page,
  • réactiver le hook pre_wp_nav_menu.

Retour