Default Menu Blocks
by Jeff Amaral
The Challenge:
Display the second level menu items of the currently active page, fully expanded, in the left sidebar of every page but the node edit form. And have this configuration saved in code so that every member of your development team can have it all work automatically.
Drupal menus allow you to hierarchically organize the content on your site. In Drupal 7, there are four system menus available by default: Navigation, Management, User menu, and Main menu. The Main menu is generally used for primary navigation (AKA the links generally shown at the top of every page).
All menus in Drupal can be displayed in one of two ways: as a variable in your theme settings or as a block. These blocks are limited. They will display the full menu (including top-level items) and, by default, only expand one of those top-level items if you are on a child page.
Want to show only the second level of the menu with the current page activated? Or the third? Want to expand all of the menu items so you can suckerfish them? You can’t.
Because of these deficiencies, lots of Drupal site builders turn to Menu Block, an incredibly popular and useful module.
With Menu Block, you just visit the Blocks admin page and create a new menu block pointing to the menu and level desired. Then you can just go to the blocks admin page and toss the new block into the region of your choice.
It’s great that you can do this so easily via the Drupal web interface, but what if you want that menu block and its placement available automatically, so that the rest of your development team doesn’t need to copy your steps or your actual database? What if you want to deploy it automatically to a staging or production server? You’ll need to somehow store the menu block configuration in code.
The Features module is currently the most common way to do that. There are other ways, and Drupal 8 will have configuration management built in, but for now, Features is the way to go.
Unfortunately for us, Menu Blocks cannot (currently) be exported via Features. Fortunately for us, hook_menu_block_blocks() exists. This hook allows developers to define a Menu Block in a wee bit of code. Let’s do so.
Requirements
In addition to Menu Block, we’ll use Context for exportable block placement, so the first step is to download and enable the required modules:
- Menu Block
- Chaos Tools (ctools)
- Context (be sure to enable the Context UI module)
- Features
Create a custom module using Features
First, let’s create a new, empty feature module. We’ll put our custom code there. We could have just created a plain, old, custom module, but since we know that we’ll need an exported Context, too, we’ll do it this way.
Go to admin/structure/features and click Create Feature. Give it the name ‘Sidebar Menu’, the description ‘Provides a second level menu block and places it in the left sidebar’, and for the version, enter ‘7.x–1.0’.
Under Advanced Options, click the Generate feature button, and your new, empty feature module will be saved to sites/all/modules/sidebar_menu.
Create a menu block in code
Normally, we’d create a menu block via the web interface. Go to Structure > Blocks > Add menu block and click on the Advanced options button to see what options are available.
But we’re not going to create the new menu block here, we’re going to create it in code, like this:
Enter the above code in the file sites/all/modules/sidebar_menu/sidebar_menu.module. Here’s how it maps to the web interface:
Enable the Sidebar Menu feature and go to Structure > Blocks. You’ll now see a block called ‘Current Menu Children’. We’re just here to verify that it exists, so there’s no need to place the block anywhere. We’ll use Context for that.
Create a new Context to place the block
Go to Structure > Context > Add and enter the following:
- Name: sitewide_sidebar_menu
- Require all conditions: [checked]
Add a Sitewide context condition and check ‘Always active’.
Add a Path condition and enter ~node/*/edit.
Add a Blocks reaction and put the ‘Current Menu Children’ block (under menu_block) in the Sidebar first region.
Save the context.
Test it!
At this point, you can visit any page in the main menu, and if it has any child menu items, the second level of the menu will appear in the sidebar, all expanded and everything! Let’s add the new context to the feature we created earlier.
Update the feature module
Go to Structure > Features > Recreate (next to Sidebar Menu). In the Components section, expand the Context section and check sitewide_sidebar_menu. In the Dependencies section, add Menu Block.
Expand Advanced Options again and click Generate feature to update the feature module and include the exported context.
At this point, you can commit the sidebar_menu feature module to your source code management system to share it with other developers. All they need to do is update their code with your changes and enable the feature.