WordPress generates HTML markup for menu items and we only have the freedom to style the markup using CSS. Its fine if you are a good web designer and can style the generated markup. But what if you are integrating frameworks like Bootstrap or Foundation Or have a different markup in mind for styling. WordPress generated markup is different then the navigation bar markup for Bootstrap or Foundation. In this post I will provide the best solution for generating custom markup for WordPress menu items which can be for any framework or for your own styling.
In this post we will generate WordPress menu markup for Bootstrap framework.
wp_nav_menu() function in wordpress allows you to customize class and id of the generated HTML by passing desired options as argument to it. But its very limited and complicated. In this post I will provide a method to collect the menu items in a parent and child relationship up to 2 depth level.
WordPress provides a function wp_get_nav_menu_items() which returns all menu items of a provided menu slug or name in form of WP_Post objects.
There are many member variables of the WP_Post object. For creating a custom menu we need to care only about menu_item_parent and db_id member variables. There is a special relationship between these two variables. “menu_item_parent of top most parent element is 0. But menu_item_parent of other child and sub-child’s is equal to their parent’s db_id.”
Now let’s first print all the menu items and check weather the above relationship is verified or not.
header.php
if (($locations = get_nav_menu_locations()) && isset($locations[$menu_name]))
{
$menu = wp_get_nav_menu_object($locations[$menu_name]);
$menu_items = wp_get_nav_menu_items($menu->term_id);
print_r($menu_items);
}
The above code prints an array of WP_Post object. Each object in the array represents menu item of the menu named “main”. If you test the above code you will see that the relationship between menu_item_parent and db_id.
Now we will take advantage of this relationship and build a two dimensional array containing top level parent element and its childs, i.e., depth 2.
header.php
$parent = array();
$menu_name = 'main';
if (($locations = get_nav_menu_locations()) && isset($locations[$menu_name]))
{
$menu = wp_get_nav_menu_object($locations[$menu_name]);
$menu_items = wp_get_nav_menu_items($menu->term_id);
$parent_id = 0;
foreach((array)$menu_items as $key => $menu_item)
{
if($menu_item->menu_item_parent == 0)
{
$parent_id = $menu_item->db_id;
$title = $menu_item->title;
$url = $menu_item->url;
array_push($parent, array("title" => $title, "url" => $url, "child" => array()));
}
else if($menu_item->menu_item_parent == $parent_id)
{
$title = $menu_item->title;
$url = $menu_item->url;
array_push($parent[count($parent) - 1]["child"], array("title" => $title, "url" => $url));
}
else{}
}
}
?>
In the above code we are creating a $parent variable and storing top level menu items and their respective child items in form of two dimensional array in it. We are only storing the link and name of the menu items in the $parent variable.
Now we can loop over the items and print our custom markup for bootstrap navbar.
header.php
<?php
foreach ($parent as $key => $value)
{
if(empty($value["child"]))
{
echo "<li><a href='" . $value["url"] . "'>" . $value["title"] . "</a></li>";
}
else
{
echo '<li class="dropdown"><a href="' . $value["url"] . '" class="dropdown-toggle" data-toggle="dropdown">' . $value["title"] . ' <b class="caret"></b></a><ul class="dropdown-menu">';
foreach ($value["child"] as $key => $value)
{
echo '<li><a href="' . $value["url"] . '">' . $value["title"] . '</a></li>';
}
echo '</ul></li>';
}
}
?>
</ul>
In the above we loop through the $parent variable and then echo the appropriate bootstrap markup for top level menu items and also for child menu items if any exists.
Conclusion
You can customize the above code to include more than 2 depth levels. And also instead of creating a bootstrap navbar you can create your own navigation menu or integrate any other framework like foundation.