How to add a breadcrumb menu in Orchard Core - Orchard Core Nuggets

Zoltán Lehóczky's avatar
Navigation, Orchard Core Nuggets, Orchard Core, Breadcrumbs, Named style and script Tag Helpers, This is Lombiq! - This week in Orchard (09/05/2020)

breadcrumb menu is a simple but effective navigation aid that shows the user where they are in the site's content structure and which path they can take back. It's also part of the web accessibility guidelines. However, there's no feature built into Orchard Core for this. Nevertheless, how to create a breadcrumb menu?

It's actually really easy, you just have to copy a piece of code from Orchard Dojo! Oh wait, we're Orchard Dojo. So here you go:


@inject OrchardCore.ContentManagement.IContentAliasManager ContentAliasManager;
@inject OrchardCore.ContentManagement.IContentManager ContentManager;
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor;

@using OrchardCore.ContentManagement;
@using OrchardCore.Menu.Models;

@{
    // Retrieving the menu we want to build the breadcrum menu for, in this case the one with the alias "main-menu".
    var menu = await ContentManager.GetAsync(await ContentAliasManager.GetContentItemIdAsync("alias:main-menu"));

    // We'll need the current URL to be able to check which menu item corresponds to the page.
    var currentRelativeUrl = HttpContextAccessor.HttpContext.Request.Path;

    var breadcrumbItems = new Stack<ContentItem>();

    // Building the path in the menu tree to the current item.
    bool SearchActiveItem(IEnumerable<ContentItem> menuItems)
    {
        if (menuItems == null) return false;

        // Note that for the sake of simplicity this will work only with Link Menu Items, not with Conten Menu Items.
        foreach (var menuItem in menuItems.Select(item => item.As<LinkMenuItemPart>()).Where(item => item != null))
        {
            if (!string.IsNullOrEmpty(menuItem.Url))
            {
                var url = menuItem.Url;
                if (url.StartsWith("~")) url = url.Substring(1);

                if (url.Equals(currentRelativeUrl, StringComparison.OrdinalIgnoreCase))
                {
                    breadcrumbItems.Push(menuItem.ContentItem);
                    return true;
                }
                else
                {
                    if (SearchActiveItem(menuItem.ContentItem.As<MenuItemsListPart>()?.MenuItems))
                    {
                        breadcrumbItems.Push(menuItem.ContentItem);
                        return true;
                    }
                }
            }
        }

        return false;
    }


    SearchActiveItem(menu.As<MenuItemsListPart>().MenuItems);
}

@* Using the Bootstrap breadcrumb classes. *@
<ul class="breadcrumb">
    <li class="breadcrumb-item">
        <a href="@Url.Content("~/")">@T["Home"]</a>
    </li>
    @while (breadcrumbItems.TryPop(out var menuItem))
    {
        var linkItem = menuItem.As<LinkMenuItemPart>();
        <li class="breadcrumb-item">
            <a href="@Url.Content(linkItem.Url)">@linkItem.Name</a>
        </li>
    }
</ul>

Wait, wait, slow a bit down. What is this?

This is the code that would render a simple breadcrumb menu for the menu with the alias "main-menu". If you've set up your Orchard site with any of the built-in recipes you already should have such a menu. But do take a look at the code in detail, we have a lot of helpful comments in there!

Once you're clear on what this piece of code does you can copy it somewhere in your theme to display it. For example, you can just put it into the Layout shape template. A cleaner approach would be to put it into its own separate template, like BreadcrumbMenu.cshtml, and display it in one of the many ways possible.

Pretty much that's it! Now let's suppose you built e.g. a menu like this:

A multi-level menu built in Orchard Core, as visible on the Orchard admin

With the above snippet you can have a breadcrumb menu like this when you open the Module Development page:

A breadcrumb menu displayed on the Orchard Core frontend, using the default Bootstrap styling

This just uses the default Bootstrap breadcrumbs styling.

And that's it, we're done with our breadcrumbs, enjoy! To be fair, this could use some work to make it bulletproof. We could e.g. optimize away the whole lookup when we're on the homepage. Then, it only supports only a single menu item for a given page. Nevertheless, it should get you going. If you'd like to see a generic and more advanced breadcrumb menu feature in Orchard check out this issue.

Did you like this post? It's part of our Orchard Core Nuggets series where we answer common Orchard questions, be it about user-facing features or developer-level issues. Check out the other posts for more such bite-sized Orchard Core tips and let us know if you have another question!

7 Comments

  • Vitaly said Reply

    Thanks for the breadcrumb.
    How can i adopt this one to be able display the PAGE path :
    Menu Item : Company
    Page User ist : UsersList
    Page user : UsersList /John
    PageDetails :John / Details
    For navigation i am using the ID of item.
    @page "/ Company / {UsersList } / {id} / {User}/ Details"

    URL : yahoo / Userlist / fhseofja343 / John / Details

  • Zoltán Lehóczky said Reply

    The technique detailed in this blog post only take the menu into account. If you have a dynamically generated structure, like a List, you'll need to handle that in addition to this. Until we have a generic breadcrumb feature (see: https://github.com/OrchardCMS/OrchardCore/issues/5936) you can e.g. detect the UsersList and User content items from the URL.

    • Vitaly said Reply

      What about this project?
      https://github.com/zHaytam/SmartBreadcrumbs
      looks like its possible to adopt for solution?

      • Zoltán Lehóczky said Reply

        I think it would be easier to just implement breadcrumbs in Orchard directly. However, you can certainly use that library too, just it'll be disconnected from the Orchard menu.

  • Vitaly said Reply

    Is there any news about this?

    • Zoltán Lehóczky said Reply

      What kind of news are you awaiting Vitaly? I've replied to your last message above.

Add a Comment