Making menus in Orchard a little better

#orchard

Posted by admin on September 01, 2019

After keeping an eye on the Orchard forums and then doing some work on a clients website that has been implemented in Orchard, I soon became one of those people needing a decent menu. So, I thought to myself, well what does orchard have that I can use, after all - I don’t really want to have to do a lot of work just for a menu.

Note : This is all based around the last iteration of Orchard within Visual Studio 2008 framework 3.5.

So what does Orchard have that I can use…

  1. Admin page for Menu
  2. Allows you to store menu positions as 1 1.1 1.1.1 2 2.2 etc…
  3. You can override the menu within your theme

Okay, so I got to thinking, if I can store the positions broken down like this, why cant i retrieve them like this, and go on to build the necessary menu steps? Well I can… here is how..

Step 1: In your theme, create a Menu.ascx file.

And drop this code in to it. (this is a modified version of the one located in Orchard.Themes)

<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Mvc.ViewModels.BaseViewModel>" %>
<%@ Import Namespace="Orchard.Utility.Extensions"%><%
    var menu = Model.Menu.FirstOrDefault();
    if (menu != null && menu.Items.Count() > 0) { %>
    <ul class="menu" role="navigation"><%
        int counter = 0, count = menu.Items.Count() - 1;
        int previousLevel = 1;
        int currentLevel = 1;
        foreach (var menuItem in menu.Items.OrderBy(m => m.Position)) {
            var sbClass = new StringBuilder(10);
            if (counter == 0)
                sbClass.Append("first ");
            if (counter == count) {
                sbClass.Append("last ");
            }
            if (string.Equals(menuItem.Href, Request.ToUrlString(), StringComparison.InvariantCultureIgnoreCase))
                sbClass.Append("current ");


        currentLevel = menuItem.Position.Split(<span class="str">'.'</span>).Length;
        <span class="kwrd">if</span> ((previousLevel == currentLevel) &amp;&amp; counter &gt;= 1){ %&gt;
            &lt;/li&gt;
        &lt;%}
        <span class="kwrd">if</span> (previousLevel &lt; currentLevel) {
            sbClass.Append(<span class="str">"first "</span>);%&gt;
            &lt;ul&gt;
        &lt;% }
        <span class="kwrd">if</span> (previousLevel &gt; currentLevel) {
            <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; (previousLevel - currentLevel); i++) { %&gt;
            &lt;/li&gt; &lt;/ul&gt;
        &lt;% } %&gt; &lt;/li&gt; &lt;%}
        var classValue = sbClass.ToString().TrimEnd();
        var linkAttributes = <span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">object</span>&gt;();
        <span class="kwrd">if</span> (!<span class="kwrd">string</span>.IsNullOrEmpty(menuItem.AccessKey))
            linkAttributes.Add(<span class="str">"accesskey"</span>, menuItem.AccessKey);
        %&gt;
            &lt;li&lt;%=!<span class="kwrd">string</span>.IsNullOrEmpty(classValue) ? <span class="kwrd">string</span>.Format(<span class="str">" class=\"{0}\""</span>, classValue) : <span class="str">""</span> %&gt;&gt;&lt;%=Html.Link(menuItem.Text, menuItem.Href, linkAttributes)%&gt;

        &lt;% previousLevel = currentLevel;
           <span class="kwrd">if</span> (counter == count) { %&gt;
            &lt;/li&gt;
        &lt;% <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 1; i &lt; previousLevel; i++) { %&gt;
            &lt;/ul&gt; &lt;/li&gt;
        &lt;% } }

        ++counter;
    } %&gt;
&lt;/ul&gt;
<% } %>

Next head to your manage menu section in the admin screens…. usually http://localhost:30320/Admin/Navigation

Set up your positions like below… Click Update All

image_thumb1

Next head back to your front page, and you should start seeing html like so....

<div class="menucontainer">
    <ul class="menu" id="nav-one">
        <li class="first"><a href="/">Home</a></li>
        <li><a href="/Test/Gallery">Portfolio</a>

            <ul class="nested">
                <li class="last"><a href="/Test/Gallery/Item/University Work">University Work</a></li>
            </ul>
        </li>
    </ul>
</div>

I admit, I have done this in a little bit of a rush, so there could be one or two bugs creeping around.

Okay once this is done… So can then apply Suckerfish or what ever over the top… i used http://be.twixt.us/jquery/suckerFish.php which is the jquery equivalent.

Happy Orchard Picking everyone.

Note : Fixed issue with it not showing the ‘First’ class correctly. 29/July/2010

Note : Fixed issue with missing closing . 04/Aug/2010

Nick