Add second menu to Twenty Twelve theme

Here’s a step by step guide to adding a second menu area to a Twenty Twelve child theme. This menu will act the same as the default menu on mobile devices and display below the header area.

If you don’t know what a child theme is you can read more about it on the WordPress Codex or read my own article on how to Create a WordPress child theme

Prepare the child theme

  • Create a Twenty Twelve Child theme or you can download a blank one Here (make sure to edit the top of the style.css file to reflect your own name and theme name)
  • In the child theme folder, create a directory called “js” (without quotes)
  • Copy from the Twenty Twelve folder, header.php and inside the js folder copy navigation.js
  • Create a file called functions.php
  • Upload functions.php to your child theme folder
  • Upload header.php to your child theme folder
  • Upload navigation.js to your child theme folder inside the js folder

Your child theme now contains the proper files and directory structure for the next part. Follow these template modifications for the files in your child theme folder.

Template modifications

Open functions.php and add this. This code dequeues the original Twenty Twelve navigation.js file and queues our ownIt also registers our second menu area.

<?php

// de-queue navigation js
add_action('wp_print_scripts','tto_dequeue_navigation');
	function tto_dequeue_navigation() {
		wp_dequeue_script( 'twentytwelve-navigation' );
}
// load the new navigation js
	function tto_custom_scripts()
{

// Register the new navigation script
	wp_register_script( 'lowernav-script', get_stylesheet_directory_uri() . '/js/navigation.js', array(), '1.0', true );

// Enqueue the new navigation script 
	wp_enqueue_script( 'lowernav-script' );
}
add_action( 'wp_enqueue_scripts', 'tto_custom_scripts' );

// Add the new menu
register_nav_menus( array(
	'primary' => __( 'Top Menu (Above Header)', 'tto' ),
	'secondary' => __( 'Lower Menu (Below Header))', 'tto'),
) );

?>

Save and close functions.php

Add the menu to the header

Open header.php and around line 48 find this line

</header><!-- #masthead -->

Directly above that line add the following code. This adds a second menu call to the header.

<!-- Lower Navigation -->
<nav id="lower-navigation" class="main-navigation" role="navigation">
	<h3 class="menu-toggle"><?php _e( 'Lower Menu', 'twentytwelve' ); ?></h3>
	<div class="skip-link assistive-text"><a href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentytwelve' ); ?>"><?php _e( 'Skip to content', 'twentytwelve' ); ?></a></div>
	<?php wp_nav_menu( array( 'theme_location' => 'secondary', 'menu_class' => 'nav-menu', 'fallback_cb' => false ) ); ?>
</nav><!-- #lower-navigation -->

You can change the name of the menu that appears on mobile by changing “Lower Menu” to whatever you prefer in this code.

We’re going to use the fallback_cb menu parameter so the new menu won’t list your pages in case you decide you don’t want to have it active. But remember, this will require you to create a new menu in Appearance > Menus and activate it before you’ll see the menu.

Save and close header.php

Add the javascript for mobile

Open /js/navigation.js, scroll to the very bottom and add the following code. We’re simply adding a copy of the current javascript but using a different ID #lower-navigation for the new menu. This will make the menu act the same as the default menu on mobile devices.

I’m not very good with javascript so there might be a better way to use a second ID for getElementById, if you know of one please let me know and I’ll update this.

// Lower Navigation
( function() {
	var button = document.getElementById( 'lower-navigation' ).getElementsByTagName( 'h3' )[0],
	    menu   = document.getElementById( 'lower-navigation' ).getElementsByTagName( 'ul' )[0];

	if ( undefined === button )
		return false;

	// Hide button if menu is missing or empty.
	if ( undefined === menu || ! menu.childNodes.length ) {
		button.style.display = 'none';
		return false;
	}

	button.onclick = function() {
		if ( -1 == menu.className.indexOf( 'nav-menu' ) )
			menu.className = 'nav-menu';

		if ( -1 != button.className.indexOf( 'toggled-on' ) ) {
			button.className = button.className.replace( ' toggled-on', '' );
			menu.className = menu.className.replace( ' toggled-on', '' );
		} else {
			button.className += ' toggled-on';
			menu.className += ' toggled-on';
		}
	};
} )();

Save and close navigation.js and activate your new child theme. Now visit Appearance > menus, create a new menu and add it to the new lower menu area.

If everything went well you should see a second menu in your Twenty Twelve child theme. Be sure to resize the browser and test the menu.

Bonus

Some of you might want to only display the lower menu, but you can’t because Twenty Twelve displays your pages if there isn’t a menu active. Here’s how to do it.

Open header.php and find around line 42

<?php wp_nav_menu( array( 'theme_location' => 'primary', 'menu_class' => 'nav-menu' ) ); ?>

Change it to

<?php wp_nav_menu( array( 'theme_location' => 'primary', 'menu_class' => 'nav-menu', 'fallback_cb' => false ) ); ?>

Now visit Appearance > Menus and remove the menu from the top menu area and save. Adding the fallback_cb menu parameter prevents the menu from displaying your pages when there is no menu active.

If you want to remove the margin above the header and bring the header image closer to the top, you can add this to your CSS.

#site-navigation.main-navigation {
    margin-top: 0 ;
}

Enjoy your new menu and let me know how it worked out for you!

62 thoughts on “Add second menu to Twenty Twelve theme

  1. Thomas Schmidt

    I tried this and it works. The tutorial is perfect.

    But what I wanted is a second level navigation that pops up if the selected page of the main navigation has sub pages. The best solution would be if the navigation already pops up while hovering over the first navi. So the user does not have to click when he wants to access a nested page.

    1. Zeaks

      Hi Thomas. I know what you mean. The menu will only open if it’s clicked on, I think mostly because if it stayed open, and the site had alot of nav links, it would require scrolling past the menu, even if the user just wanted to view what’s on the current page.

  2. Zeaks

    Hi Matt, are you copying the code above to your functions.php, or are you copying the actual functions.php file from the parent theme to your child theme?

    Also, re-check the javascript code for navigation.js in the latest Twenty Twelve the code has been changed slightly, I just updated it.

      1. Zeaks

        If you copy the entire file, all the functions inside your child theme function.php will conflict with the parent functions. Create a new file functions.php. Only add new functions, or override functions that you need.

        Your entire functions.php file should contain only this in it (and any custom functions you want to add for other things)

        < ?php
        
        // de-queue navigation js
        add_action('wp_print_scripts','tto_dequeue_navigation');
            function tto_dequeue_navigation() {
                wp_dequeue_script( 'twentytwelve-navigation' );
        }
        // load the new navigation js
            function tto_custom_scripts()
        {
        
        // Register the new navigation script
            wp_register_script( 'lowernav-script', get_stylesheet_directory_uri() . '/js/navigation.js', array(), '1.0', true );
        
        // Enqueue the new navigation script 
            wp_enqueue_script( 'lowernav-script' );
        }
        add_action( 'wp_enqueue_scripts', 'tto_custom_scripts' );
        
        // Add the new menu
        register_nav_menus( array(
            'primary' => __( 'Top Menu (Above Header)', 'tto' ),
            'secondary' => __( 'Lower Menu (Below Header))', 'tto'),
        ) );
        
        ?>
    1. Zeaks

      Hi Joanne, yes there is and I should of pointed that out. In the section you added to header.php, the line that reads

      change the word Menu to whatever you like. In my own theme I’ve used Main Menu, and Lower Menu.

      I’ll update this post and include that information. Thanks

  3. Toure

    Very nice. What I am looking for though is a good way to resize body width of a child theme without using directly using css. Setting the body width within functions.php as it’s done in parent theme.

  4. JR

    Hi! This tutorial works perfectly as you can see in http://www.buscarhotelesbaratos.es. In my site i use one of the menus to show information about the site (About, Contact, Press media kit…) and the other to show the categories of the site.
    Now i would like to modify the aspect of top menu to display text smaller, remove the lines, etc etc. I want that my visitors see that the main menu is the categories menu (the second) and leave the other leave less prominent in case they need information about the site or contact with me. Can you help me? Thanks a lot and sorry for my english!

    1. Zeaks

      The borders are defined by this

      .main-navigation ul.nav-menu, .main-navigation div.nav-menu > ul {
          border-bottom: 1px solid #EDEDED;
          border-top: 1px solid #EDEDED;
      }

      You should be able to add the id lower-navigation to it to remove them.

      #lower-navigation .main-navigation ul.nav-menu, #lower-navigation  .main-navigation div.nav-menu > ul {
          border-bottom: 0;
          border-top: 0;
      }

      Use the #lower-navigation conditional to apply styles to that particular menu.

  5. mark

    …and if i want a menu1 with (about, services, portfolio, contact), and a secondary Portfolio menu that appear only after portfolio press? The menu1 remain on top of the site and the portfolio menu appear in another position…
    how can i do?
    thanks
    good, very good tutorial..

  6. Pingback: 如何给Twenty Twelve主题创建新菜单区域 | SayBlog.Me

  7. Peter Grab

    Hallo – I gave you the url of my test-site – as you see there are two menus – the first one from top is my secondary menu. I tried both versions you suggested: the #lower-navigation id – css as suggested in style.css of my child-theme – did’nt function – then i tried out the menu-id parameter and again in the style.css of the child-theme didn’t function.
    this style.css looks as:
    /*
    Theme Name: mytwentytwelve
    Author: Peter Grab
    Description: Child Theme von twentytwelve
    Template: twentytwelve
    */
    @import url(../twentytwelve/style.css);

    #sec-menu .main-navigation ul.nav-menu, #sec-menu .main-navigation div.nav-menu > ul {
    border-bottom: 0;
    border-top: 0;
    }

    now i’m a complete novice to css in general and for wordpress in special – Could you please give me a tip?

    the first menu – thats my secondary – should have no lines above and under it – it should be complete at the top border of the page and it should be written with smaller letters let me say 10px

    1. Zeaks

      You’re right, it’s not working properly with that CSS. I’ll need to look into this more.
      You can use the ID alone to do what you need to though, be sure to add it to @media so it only affects the desktop menu and not th emobile menu.

      @media screen and (min-width: 600px) {
           #sec-menu {
              border: none;
              margin-top: -20px; 
              }
           #sec-menu a { font-size: 10px; }
      }
  8. rolanstein

    Hi Zeaks

    I’m confused: when should the @media be used with CSS and when doesn’t it matter, pls? I want to keep my modded Twenty Twelve child theme responsive, and am concerned that I might already have made changes to the style sheet, for example, that may be compromised the responsiveness. In other words, I guess, should the @media thingo be used every time a CSS change is made or CSS added to the style sheet? If not, when exactly, pls?

    Cheers
    Ross

    1. Zeaks

      Hi Rolanstein, unless you want to make changes to how your theme looks on mobile devices, you should always use @media. Here’s an example, lets say you want a red border around your navigation menu, if you added #access { border: 1px solid red; } then both the mobile menu and the regular menu would display the border.

      If you added @media around it, then only the desktop version would show the border.

      Twenty Twelve was designed for mobiles first, then using @media conditionals it was designed to work for desktop browsers.

      Some things won’t matter such as, widget titles, post titles, comment areas, since they should look the same on both mobile and desktop. Anything for the layout, and menu I would use @media since they both display differently on mobile.

      If you want to show me your changes you’ve made on a forum post or pastebin.com, I’ll let you know what you should add within @media tags

      1. rolanstein

        Very helpful and clear, Zeaks. Thanks a lot.

        I will take you up on your kind offer. Makes sense to check whether I’ve messed anything up before continuing and applying your advice in the future. Haven’t used pastebin before, but let’s see how this embed goes:

        Cheers
        rolanstein

  9. Zeaks

    Hi Rolanstein, I had to removed your post, it was too long for comments, open a forum post if you need to paste a lot of code, it’s easier to read that way.
    Your stylesheet looks good other than I would probably put the body .site { css within @media like this.

    @media screen and (min-width: 600px) {
    	body .site {
    		padding: 0 40px;
    		padding: 0 2.857142857rem;
    		margin-top: 0px;
    		margin-top: 3.428571429rem;
    		margin-bottom: 48px;
    		margin-bottom: 3.428571429rem;
    		box-shadow: 0 2px 6px rgba(100, 100, 100, 0.3);
    	}
    }

    Images and everything else would apply to mobile view and desktop view, so it’s fine. If you notice something doesn’t look right on mobile, check to make sure you didn’t add css for the area without @media conditionals.

    1. rolanstein

      Whoops – sorry about that long section of code, Zeaks. I was intending initially to embed it using pastebin (this is what you’ve done with the section of my stylesheet you’ve just posted, I think?), but couldn’t work out how to do it! Duh…

      Thanks, as ever, for your advice and willingness to assist. Will adjust the positioning of the body .site code as you suggest.

      Hadn’t noticed your forums menu item. Will check them out.

      Cheers!
      rolanstein

  10. Zeaks

    Thanks for letting me know, I’ve noticed the forums have been quiet since I changed themes, I’ve added another link in the sidebar menu and I’ve added info on posting code to the comment form

  11. G

    Hi, I am a beginner on wordpress. I followed the changes proposed step by step. It worked perfectly when applied to the Child Theme, Thanks! I now have 2 Menus in my Appearance section. Is it possible to have only one of the Menus displayed on my pages. Example: Page 1 would have the Lower Menu and Page 2 would display the Standard Menu?

    1. Zeaks

      You can use body classes to hide the menu for certain pages or you can use an if statement to not display it for some pages.
      Untested example:

      < ?php if( ! is_page('703') && ! is_page('2') ):?>
      
      < ?php endif;?>

      This would hide it on page ID 703 and 2. the ! tells it if it isn’t page 703 or page 2, then display the menu.

      To find the id of the page you can view the page in FireBug or visit admin > pages > all pages. Hover your mouse over the page and look at the URL, it should say something like this http://yoursite.com/wp-admin/post.php?post=703&action=edit and 703 would be the ID.

      1. Gerald

        Hi Zeaks,

        thanks for the awesome write up. Worked a treat.

        I’m also trying to make it so the sub menu only appears on a certain page.

        Where does the code up above go? I tried it in my style.css but it didn’t do anything.

        Is there a reverse of the way you have it so instead of listing every page it doesn’t show up on, you make it default not show up on a page except the one listed?

        Thanks again

  12. premmarga

    Hello Zeaks, now I´ve got it working, I only don´t get it what I have to change to get the second menu on the top, above the header like in http://babybirds.de/. You already gave Paul an answer on this, but I don´t know where to move the position of the menu, and I would like to call it topmenu, written already in the function.php, but where to change this the other files.
    I hope you can help me. her is my website http://www.ahoi-kultur.de

    1. Zeaks

      Hi Premmarga, there is already a menu area above the header. If youw ant to add another one on top of that, simply move the menu call

      
      

      To just abover the menu that’s already there. if you can;t figure this out, open a forum post and link your header code to pastebin.com

  13. ravi

    HI Zeaks
    A big thanks to you, I am using wordpress from last 1.5 years and whatever i have learnt in wordpress is only because of your blog. thanks a lot buddy.

    I am using 2 menus in my website and i have copied your code to my child theme but the problem is only one menu is able to toggle when screen gets smaller. other menu does not toggle.

  14. David

    Nice tutorial. Works great. My client wanted a second menu, but at the footer so this was perfect. I put the code at the top of footer.php and renamed the menu titles to “footer menu”. Works like a charm.

      1. davidborrink

        Zeke, I’ve got another situation like above. I placed the script and modified header file (both menus are in the header on this other site), and the main menu button is not responding in mobile, and the second added menu button is visible but the menu items are listed below it on this one. It doesn’t toggle, either. This site is in development so I’ve got no link to share for this one.

        So the site above in the previous note has the new added menu working fine. The second site has the menu “on” with no “off”.

        Any idea what’s going?

  15. davidborrink

    On the second site, if it’s any help, I renamed the div for the added menu to “upper-navigation” instead of “site-navigation” because this menu needed different styling that the other.

    That means I took all the styles of “site-navigation”, made copies and renamed them “upper-navigation” so the menus could look different. Is it possible that I’m missing a key piece of CSS that has the menu in the “on” state since I created a new div in the menus? I’m not seeing it in the parent TwentyTwelve CSS at first glance. Maybe you can tip me off to something I’m overlooking.

  16. davidborrink

    I removed the script from the first site and turned off my second menu. It would appear that it’s the script to add the mobile functions to the second menu is the problem. The first menu is working fine again with the default script. I’m no javascript expert, but I’m tossing out a guess that the latest version of TwentyTwelve is conflicting with your script?

    1. davidborrink

      Ho boy. Double goofs.

      1. I just discovered tonight that I used your javascript example by itself and never tacked it on to a copy of the full javascript file from the parent theme. [facepalm] No wonder it didn’t work.

      2. I didn’t have the mobile menu’s CSS files from the parent theme in the child theme. Since I restyled the new menu differently than the main menu—and both have their own class—I needed to have an additional copy of the mobile CSS files with the class alterred. That made the menus closed as they needed to be. And gave them full function.

  17. davidborrink

    Zeak, I figured out a MAJOR reason why this suddenly wasn’t working and you need to know about it. It has to do with the updated Twenty Twelve theme (version 1.5) released with WordPress 4.0.

    There is a key line in the menus that changed. See this forum post: https://wordpress.org/support/topic/mobile-menu-doesnt-work?replies=24 for the details. The h3 class has become a button class.

    You will need to change the code in your javascript from “.getElementsByTagName( ‘h3′ )” to “.getElementsByClassName( ‘menu-toggle’ )”

    That completely solved my problem.

    (AND PLEASE feel free to delete all my comments above except the first one on August 30! People don’t need to read all my struggles with my goofed up attempts to not follow your instructions

Leave a Comment

Your email address will not be published. Required fields are marked *

*
*