How to add a Category-based Mega Menu in Wordpress Without a Plugin

Mega Menu is a content-rich menu where each category (or menu item) shows items (or child list) of that category either as a text list or image & text list. Look at the image for this post. On the main navigation menu, you will see menu list items: Level 1, Fitness, Mind, Body, etc. The first item there is a "normal" list item (a link to a page) while the rest are categories in Wordpress.
  • Disclaimer: I won't help you with the styling though via style.css or jquery. Proceed at your own risk.
If you look at my main menu here in, you'll see a toggleable menu item that goes by the name of topics. If you toggle that, you'll see different toggleable lists of recent posts according to labels. We'll do something similar to that except that the menu items (or first-level child menu-items) are categories and each of them contains a child list of recent posts on their own in Wordpress.

Basically, what we're going to do is create a mega menu based on recent posts by Category. So let's begin:

We're going to edit the walker class function so add this code on your navigation menu in header.php (or edit your code for wp_nav_menu):

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

The new code should look similar to this:

You can change the array items according to your liking (e.g. change theme_location to another instead of primary), just don't change walker.

Add category menu items on your primary menu via your Wordpress dashboard

Refresh your website (homepage) and see if your menu is showing new category items.

Hover and inspect element of a category menu-item.

My hovered li menu-item has this:
class="menu-item menu-item-type-taxonomy menu-item-object-category"

Go to a post or a single page that belongs to a category featured on your menu. Inspect element of that category menu-item.

My li menu-item now has this:
class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent"

Whatever your results, we are going to need that later

In your functions.php file, add this walker function:

class description_walker extends Walker_Nav_Menu {
    function start_el(&$output, $item, $depth, $args) {
        global $wp_query;

        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
        $class_names = $value = '';

        $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 = '';
        $append = '';
        $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 ($class_names == ' class="menu-item menu-item-type-taxonomy menu-item-object-category"' or $class_names == ' class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent"') {
            ob_start(); ?>
            <ul class="cat-sub-menu">
<?php $the_query = new WP_Query( array( 'category_name' => $item->title, 'posts_per_page' => 5 ) );
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
if ( has_post_thumbnail() ) { ?>
<li><a href="<?php the_permalink(); ?>" class="cat-sub" rel="bookmark"><div class="thumbnail"><?php the_post_thumbnail(); ?></div><div class="cat-title"><?php the_title(); ?></div></a></li>
<?php } else { // if no featured image is found ?>
<li><a href="<?php the_permalink(); ?>" class="cat-sub" rel="bookmark"><div class="thumbnail"></div><div class="cat-title"><?php the_title(); ?></div></a></li>
wp_reset_postdata(); ?>
   </ul> <?php
            $item_output .= ob_get_contents();

        $item_output .= $args->after;
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );

Now, pay close attention to this code from above:

In the first line from the picture directly above, replace the class names generated from your results from instructions 4 and 5 in if($class_names ==

Basically, what you're going to do is to replace the content with your result from Step 4 the first occurrence of $class_names == which is highlighted in lime from Step 6 and then put the result from Step 5 on the next (the next occurrence of  $class_names == after "or") which is highlighted in orange from Step 6.

Make sure to pay close attention to the space before class="menu-item

Style your Mega Menu through your style.css file

I cannot share my styling because it could be highly different from your template. All you have to know (as you can see from the above image) is that I assign the ul list a class of cat-sub-menu and its child list of class cat-sub.

If you want to show more than five posts in the mega menu, change via posts_per_page.

I have a live working website for this at

We love to hear from you


More from Zirev