Chaque menu 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 par menu, 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

J'utiliserai simplement 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 utilisent une requête en plus.

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.