Chaque menu de navigation Wordpress est généré par la fonction wp_nav_menu() qui demande énormément de requêtes au chargement d'une page.

Pour remplacer toutes ces requêtes par une seule, je vais utiliser deux hooks appartenant à cette fonction :

  • 'wp_nav_menu' à la fin pour enregistrer en base de donnée le menu final en HTML.
  • 'pre_wp_nav_menu' au début pour court-circuiter la fonction wp_nav_menu().

J'utiliserai simplement les fonctions update_option() et get_option() pour enregistrer et obtenir le menu HTML dans la table des options de la base de donnée Wordpress.
Je préfère cette méthode plutôt que d'utiliser des transients avec les fonctions set_transient() et get_transient() qui nécessitent une requête en plus pour vérifier si le transient existe.

Avec le hook 'wp_nav_menu'

Ce hook va nous permettre d'enregistrer le menu HTML à la fin de la fonction wp_nav_menu(). Comme l'architecture du menu peut être différente d'une page à une autre, il suffit de se rendre sur chaque page de son site pour enregistrer toutes les versions du menu, après avoir insérer le code suivant :

<?php

class Hooks_Theme{

    static public function init_hooks(){
        add_filter('wp_nav_menu', array(__CLASS__, 'set_option_nav_menu'), 10, 2 );
        add_filter('pre_wp_nav_menu', array(__CLASS__, 'get_option_nav_menu'), 10, 2 );
    }

    static public function set_option_nav_menu( $nav_menu, $args ){
        
        if( $args->theme_location == 'main-menu' || $args->theme_location == 'top-menu' ){
            
            global $wp_query;
            $nav_slug = $args->theme_location;
            $nav_page = 'nav_'.$nav_slug.'_home';
            
            if( $wp_query->is_page ){
                $nav_page = 'nav_'.$nav_slug.'_page_'.$wp_query->query['pagename'];
            }elseif( $wp_query->is_tax ){
                $nav_page = 'nav_'.$nav_slug.'_tax_'.$wp_query->query['taxonomy'].'_'.$wp_query->query['term'];
            }elseif( $wp_query->is_archive ){
                $nav_page = 'nav_'.$nav_slug.'_archive_'.$wp_query->query['post_type'];
            }elseif( $wp_query->is_single ){
                $nav_page = 'nav_'.$nav_slug.'_single_'.$wp_query->query['post_type'];
            }
            
            update_option($nav_page, $nav_menu);
        }
        
        return $nav_menu;
    }
}

Et le hook 'pre_wp_nav_menu'

Ce hook 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 wp_nav_menu().

<?php

class Hooks_Theme{

    /* Code précédent */

    static public function get_option_nav_menu( $nav_menu, $args ){
        
        if( $args->theme_location == 'main-menu' || $args->theme_location == 'top-menu' ){
            
            global $wp_query;
            $nav_slug = $args->theme_location;
            $nav_page = 'nav_'.$nav_slug.'_home';

            if( $wp_query->is_page ){
                $nav_page = 'nav_'.$nav_slug.'_page_'.$wp_query->query['pagename'];
            }elseif( $wp_query->is_tax ){
                $nav_page = 'nav_'.$nav_slug.'_tax_'.$wp_query->query['taxonomy'].'_'.$wp_query->query['term'];
            }elseif( $wp_query->is_archive ){
                $nav_page = 'nav_'.$nav_slug.'_archive_'.$wp_query->query['post_type'];
            }elseif( $wp_query->is_single ){
                $nav_page = 'nav_'.$nav_slug.'_single_'.$wp_query->query['post_type'];
            }
            
            if( false !== ( $rec = get_option($nav_page) ) ){
                $nav_menu = $rec;
            }
        }
        
        return $nav_menu;
    }
}

Hooks_Theme::init_hooks();

Au final cela fait quelques lignes en plus dans la table options de votre base de donnée mais économise jusqu'à plusieurs dizaines de requêtes en fonction de l'importance de vos menus.

Il suffira ensuite d'aller sur chaque page de votre site afin d'enregistrer la forme HTML de votre menu en fonction de chaque page.