I have what some may consider a unique approach to WordPress Menus. Without going into extreme detail (but if you want extreme detail be sure to sign up to get notified when @clientwp Second Edition arrives!) I rarely use Menus for client projects. From time to time however, they’re the perfect fit.
I found myself adding breadcrumbs to a client site this week, but quickly realized that the mix of Pages and Custom Post Types didn’t lend itself too well when it came to matching the main navigation system I had set up. This is further complicated by the fact that the site uses what I’d surely classify as a “mega” menu due to the vast number of links. For a number of reasons (mostly usability but also technical (read: literal limits to the number of inputs PHP would accept)) I had to break up this mega menu into five separate WordPress Menus. This made working with the large number of links (especially inserting a new one into the middle of the menu) much more approachable and maintainable for the client.
This was further complicated by the nature of Menus. As some background: WordPress Menus are can be built out of pretty much anything. Pages, Posts, Taxonomy terms, Custom Posts, Custom Links. When WordPress objects (e.g. Pages) are used for Menu items their ID
is used when exporting/importing the contents of the Menu. This is problematic when you’re trying to build a Menu in your development environment, move it to your staging environment for your client to work with and then move it from staging to production. Unless your IDs are somehow magically the same even after years of iterating on the site (or you utilized WP Migrate DB Pro like a hawk at all times) you would quickly run into issues when trying to import a Menu item for a WordPress object ID that was different or didn’t exist. That is perhaps the main reason you need a plugin to export Menus, I haven’t dug into that quite yet.
As a workaround, we’ve been using Custom Links for this mega menu from the start. This actually worked out well and continues to do so, but it proved to be a roadblock when it came to implementing breadcrumbs. This site has so much content being worked on by so many people, the actual hierarchy of the Pages doesn’t exactly match that of the Menu, especially since the Menu has undergone a number of iterations and restructuring based on usage of the site. Changing permalinks and major groupings of Pages isn’t something the client wanted to take on. Understandable. This was problematic for pretty much every breadcrumb solution out there, however. Most existing breadcrumb plugins out there work their magic based on page hierarchy which didn’t apply, and the others did so based on URI segments which would work perfectly but as per the Page organization and Menu changing so often, it wouldn’t easily apply.
Another breadcrumb plugin?
There’s no shortage of breadcrumb plugins (110 as of this writing) and while I try to avoid building things that already exist, there wasn’t anything out there that explicitly used Menus to define the structure of the breadcrumb trail. So I built one: Menu Breadcrumb does what’s on the tin, it generates a breadcrumb trail from a Menu. It’s also on GitHub if you’re in to that sort of thing (and you should be!).
I put together some docs on usage but again the primary purpose of this plugin is to output accurate breadcrumbs based on a Menu, nothing else (yet). The quickest implementation looks like this:
<?php if ( function_exists( 'menu_breadcrumb') ) { menu_breadcrumb( 'main' ); } ?> |
Assuming main
is your Menu location (not ID, slug, name) you’ll get a breadcrumb trail based on the current URL you’re viewing in the context of that Menu. To customize the output a bit, here is a more detailed usage of the menu_breadcrumb()
function:
<?php | |
if ( function_exists( 'menu_breadcrumb') ) { | |
menu_breadcrumb( | |
'main', // Menu Location to use for breadcrumb | |
' » ', // separator between each breadcrumb | |
'<p class="menu-breadcrumb">', // output before the breadcrumb | |
'</p>' // output after the breadcrumb | |
); | |
} | |
?> |
It’s pretty simple, you can customize the separator and inject some markup before/after the breadcrumb trail. There are additional docs that let you get a bit more fine-grained with your usage, however:
<?php | |
$menu_breadcrumb = new Menu_Breadcrumb( 'main' ); // 'main' is the Menu Location | |
$breadcrumb_array = $menu_breadcrumb->generate_trail(); | |
$breadcrumb_markup = $menu_breadcrumb->generate_markup( $breadcrumb_array, ' » ' ); |
Something like this is super useful given my client site circumstances from above. I have five separate Menus working together to define the global navigation for a specific site. My breadcrumb trail will be based only on one of those Menus at a given time, so Menu Breadcrumb allows me to programmatically iterate through an array of Menu locations, each time checking for a breadcrumb trail, and output only what I need.
Of note: Menu Breadcrumb will first check to see if the Menu Walker did the hard work of finding the current Menu item object, but if it didn’t it will also support using Custom URLs as Menu items when generating the breadcrumb. All of my Menus in this case were built that way so it was an important use case to cover.
Menu Breadcrumb 1.0
Pretty much every plugin I’ve written has been inspired by a challenge with a client project. This one is admittedly a bit more niche than most, but I hope to have generalized it enough to be valuable in more common use cases. I could be the only one in 1/5 the entire Internet powered by WordPress that wants to have breadcrumbs based on a Menu, but that’s okay.
Now that my client site requirement is met, I’m trying to come up with other ideas that will further generalize the application and hopefully make it more useful. The biggest issue now is that no breadcrumbs are generated if you’re viewing a URL that’s not in any Menu. I’m hoping to roll in some Hierarchy-like automagic to account for those circumstances, but to date the only progress I’ve made on that is logging it as an Issue.
I hope at least one of you find the plugin to be useful, if not today some time down the line when you find yourself in the strange boat of wanting to build breadcrumbs like this. Enjoy!
Comments
Awesome plugin, Jonathan! I often build menus based on page hierarchy (I bet you do the same) but sometimes the sitemap is just too complicated for that. This plugin is an awesome way to keep your breadcrumbs in sync with your navigation when you have to use a menu!
Breadcrumb Navxt, the successor to the well known WordPress plugin Breadcrumb Navigation XT, was composed from the beginning to be superior to its predecessor. This plugin produces locational breadcrumb trails for your WordPress controlled website or site. These breadcrumb trails are very adaptable to suit the needs of pretty much any site running WordPress. The Administrative interface makes setting alternatives simple, while an immediate class access is accessible for topic engineers and more brave clients.
I found the answer where to find ‘Menu Location’ name.
Go to your WordPress Dashboard->Appearance->Menus, then go to the tab ‘Manage Locations’, you should see a table with ‘Theme Location’ and ‘Assigned Menu’, then View Page Source code, and find , your Menu Location is ‘main-nav’. Maybe there is an easier way to find that out, if there is please share it.
Other than that the plugin works as expected. Thank you Jonathan for writing and sharing it!
I am a fan of this plugin, but am running into the same problem that was mentioned here: https://wordpress.org/support/topic/category-menus. That is, if the page being displayed is an archive, Menu Breadcrumb is not able to detect that it is the current page, and it ends up missing from the breadcrumb. This may be due to a custom permalink structure (think “/blog/” for the blog root) or to ‘with_front’ defined as false for a custom taxonomy. In any event I may start hacking the code to get this to work.
Great plugin, works for me as expected! Thumbs up for the simplicity as I don’t need the many different options of other breadcrumb plugin!