Main Content

How to add a mega menu to WordPress

Mega Menu

This code worked at the time, now I’m not so sure. Use at your own risk.

Have you ever wanted to add a mega menu to WordPress? There are plugins that claim to do it, but why use a plugin when you can add just a bit of code. Here is one, pretty simple, solution that works for me.

This code was tested in the default WordPress theme. It can work in any theme, however the instructions may very based on how the theme creator coded the theme.

First thing you’ll need to do is create a menu with WordPress’ built in menu system. Top level links are all you need. Also make sure that this is set to the ‘primary’ menu and test your site. If you don’t see the menu, the code below won’t work. Make sure that’s visible and working before we start.

Ready to go?

In the header.php theme file, find the wp_nav_menu function. This function is what calls the menu on your site. If you have more than one menu, find the one that you want to add a mega menu to.

Add this code $walker = new description_walker; above the wp_nav_menu function and then add ‘walker’ => description_walker to the wp_nav_menu.


$walker = new description_walker;
wp_nav_menu( array( 'theme_location' => 'primary', 'walker' => $walker ) );

Now we want to add a new class in the functions.php file that will serve as the code that inserts the mega menu where we want it when the menu loads.

Don’t worry, I’ll explain what you need to know. Just put it at the bottom of your functions file.


<?php
/* I'm not so certain this works right anymore, but some may find it useful. See https://www.twistermc.com/36600/wordpress-mega-menu/ for full details. */
class description_walker extends Walker_Nav_Menu {
protected $topLevelId = NULL;
protected $topLevelCount = NULL;
protected $templateURL = NULL;
function description_walker() {
$this->templateURL = get_theme_root() . '/' . get_template() . '/';
}
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
if ($depth == 0)
$this->topLevelId = $item->ID;
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="'. esc_attr( $class_names ) . '"';
$output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$attributes .= ' class= "main-link"';
$prepend = ''; // top level
$append = ''; // top level
$description = '';
$item_output = $args->before;
$item_output .= '<a '. $attributes .'>';
$item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append;
$item_output .= $description.$args->link_after;
$item_output .= '</a>';
if ($this->topLevelId == 8675309) {
ob_start();
require $this->templateURL . '/dropDown1.php';
$item_output .= ob_get_contents();
ob_end_clean();
}
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
$output .= '</li>';
}
}

view raw

walker.php

hosted with ❤ by GitHub

Good news, the base code is in place!

At this point and time, your site, and menu, should still load properly. You don’t have any mega menus just yet though. If you’re getting errors, stop now and fix them.

Next, find the ID of the menu you want to add you mega menu to. This is done by using Firebug or Chrome’s inspector to inspect the main menu item and grab out its ID. Ignore the words, and just get the number.

Menu ID

Once you have that ID, edit the walker code that we just pasted in the functions.php file and look for the if statement that references the topLevelId. Swap 8675309 out with yours.

if ($this->topLevelId == 8675309)

Next, create a file that will contain the mega menu. In the example, I called it dropDown1.php. Stick this file in your themes folder.

In our dropDown1.php file start the file with ul li and end it with /li /ul. This code makes WordPress know there is a sub-menu on rollover.

missing code

Now add anything you want in that li. It can be HTML, CSS, JS, Images, WordPress functions; anything goes.

That’s it. Test your code and you should have a mega menu.

Don’t forget to add CSS styles to make it look good. Chances are any links you add in your mega menu will inherit styles from the default menu so be sure to update them.

Want more than one mega menu? Just copy the if statement and change the topLevelId to correspond with a different menu item and create a new php file for the menu.


10 Responses

  1. John says:

    Nice man, badly wanted to implement without a plugin and this did just that and forced me to explore the walker class more thoroughly, much appreciated

  2. phr4pp says:

    thanks a lot. helped me quite a bit with a new project 😉

  3. IELTS NEPAL says:

    is there a way without having to edit the id for the mega menu ?

  4. Lisa says:

    HI this is exactly the functionality that i am looking for. I can’t get it to work with my WP. I am using the bones responsive theme. The function is bones_main_nav( array( ‘walker’ => $walker ) ); which i presume will work the same way as wp_nav_menu?

  5. Josh says:

    Spent a few hours looking for something like this. Works great, thanks!!

  6. Alex says:

    Hi Thomas McMahon! Could you provide me with the dropDown1.php file, pls, I can’t get it. Thanks

    • Thomas says:

      This tutorial is about making that file. There isn’t any downloads available.

      Also, it’s been a while since I wrote this, hopefully it still works.

  7. havi says:

    wow thanks ..

Leave a Reply