SiteMap

Sitecore, Utveckling

Sitecore C# Sitemap in two columns

I recently build a dynamic generated SiteMap User Control for a multi site Sitecore solution translated in multiple languages. I wanted it to render links to publishable page items in two columns instead of just printing it out as a long list on the page.

SiteMap

Sitecore SiteMap C# UserControl


Live example: LoFric.com

Function: The Site Map gathers all publishable page items into a list, divides the list in two, finds the closest item on top level 1 from the middle of the list and inserts a column break there so that the first item in column two is a level 1 item. This way the Site Map will always render properly on a multi site Sitecore CMS solution with various amount of content translated in many languages. The Site Map output will always be presented in a balanced two column layout using ul-li html.

You can easily adjust the business logic to work in any .NET based CMS system. Just adjust the way it gathers the items to the list. The output rendering logic will remain.

The UserControl SiteMap.ascx-file:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SiteMap.ascx.cs" Inherits="Website.Sublayouts.SiteMap" %>
<div id="SiteMap">
<asp:Literal ID="SiteMapLiteral" runat="server"></asp:Literal>
</div>

The C# code behind file

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sitecore.Data.Items;
using Sitecore.Data.Managers;
using Sitecore.Links;
using Website.Helpers;
 

namespace Website.Sublayouts
{
    public partial class SiteMap : UserControl
    {
        readonly StringBuilder _sb = new StringBuilder();
        readonly List<SiteMapItems> _sitemapItems = new List<SiteMapItems>();
        private int _previousLevel;
 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                SiteMapLiteral.Text = CreateSiteMap(StartItem);
            }
        }
 
 
        private string CreateSiteMap(Item item)
        {
            BuildSiteMapList(item.Parent, 0);
 
            GenerateHtml();
 
            return _sb.ToString();
        }
 
 
        public struct SiteMapItems
        {
            public int Level;
            public string Name;
            public string Url;
 
            public SiteMapItems(int level, string name, string url)
            {
                Level = level;
                Name = name;
                Url = url;
            }
        }
 
 
        private void BuildSiteMapList(Item startItem, int level)
        {
            var items = GetItems(startItem);
 
            foreach (Item item in items)
            {
                var currentLevel = level;
                var name = Server.HtmlEncode(GetFieldValueOrItemName(item, "MenuText"));
                var url = LinkManager.GetItemUrl(item);
 
                _sitemapItems.Add(new SiteMapItems(level, name, url));
 
                if (ItemHasRendableChildren(item))
                {
                    BuildSiteMapList(item, ++currentLevel);
                }
            }
        }
 
 
        private int GetColumnBreakIndex()
        {
            var numberOfItems = _sitemapItems.Count;
            if (numberOfItems > 0)
            {
                var middleItem = (int)Math.Round((decimal)numberOfItems / 2, 0);
 
                var closestItemBeforeMiddle = _sitemapItems.FindLastIndex(middleItem, middleItem - 1, Level1Item);
                var closestItemAfterMiddle = _sitemapItems.FindIndex(middleItem, middleItem - 1, Level1Item);
 
                return closestItemAfterMiddle - middleItem >= middleItem - closestItemBeforeMiddle ? closestItemBeforeMiddle : closestItemAfterMiddle;
            }
            return -1;
        }
 
 
        private static bool Level1Item(SiteMapItems item)
        {
            if (item.Level == 1)
            {
                return true;
            }
            {
                return false;
            }
        }
        
        
        private bool ItemHasRendableChildren(Item item)
        {
            var items = GetItems(item);
            return items.Count > 0;
        }
 
 
        private List<Item> GetItems(Item item)
        {
            new List<Item>();
            var items = item.Children.Where(i => ItemShouldBeRendered(i)).ToList<Item>();

            return items;
        }
 
 
        private void GenerateHtml()
        {
            var counter = 0;       // foreach index
            var columnBreakIndex = GetColumnBreakIndex();
 
            _sb.Append("<div id=\"SiteMapLeftColumn\"><ul>");
 
            foreach (var item in _sitemapItems)
            {
                if (counter == columnBreakIndex)
                    ContinueInNextColumn(item);
 
                if (item.Level > _previousLevel)
                {
                    _sb.Append("<li><ul>");
                    _previousLevel = item.Level;
                }
                else if (item.Level < _previousLevel)
                {
                    for (int i = item.Level; i < _previousLevel; i++)
                    {
                        _sb.Append("</ul></li>");
                    }
                    _previousLevel = item.Level;
                }
 
                _sb.Append(string.Format("<li{0}><a href=\"{1}\" target=\"_self\">{2}</a></li>", CssClass(item.Level), item.Url, item.Name));
 
                counter++;
            }
            _sb.Append("</ul></div>");
        }
 
 
        private void ContinueInNextColumn(SiteMapItems item)
        {
            for (int i = 0; i < item.Level; i++)
            {
                _sb.Append("</ul></li>");
            }
 
            _sb.Append("</div><div id=\"SiteMapRightColumn\">");
 
            for (int i = 0; i < item.Level; i++)
            {
                _sb.Append("<ul><li>");
            }
            _sb.Append("<ul>");
 
            _previousLevel = item.Level;
        }
 
 
        private static string CssClass(int level)
        {
            switch (level)
            {
                case 3: // unneccessary to set a class on this level
                    return string.Empty;
 
                default:
                    return (" class=\"level" + level + "\"");
            }
        }

        public static bool ItemShouldBeRendered(Item item)
        {
            var hasLanguageVersion = ItemHasContextLanguage(item);
            var published = item.Publishing.UnpublishDate > DateTime.Now;
            var valid = item.Publishing.ValidTo > DateTime.Now;
            return (hasLanguageVersion && published && valid);
        }

        public static bool ItemHasContextLanguage(Item item)
        {
            Item latestVersion = item.Versions.GetLatestVersion();
            return ((latestVersion != null) && (latestVersion.Versions.Count > 0));
        }

        public static Item CurrentItem
        {
            get
            {
                return Sitecore.Context.Item;
            }
        }

        public static string GetFieldValueOrItemName(Item item, string fieldName)
        {
            string _returnValue;
            string _itemDisplayName;

            _itemDisplayName = string.IsNullOrEmpty(item.DisplayName) ? item.Name : item.DisplayName;

            if (item.Fields[fieldName] == null)
            {
                _returnValue = _itemDisplayName;
            }
            else
            {
                _returnValue = string.IsNullOrEmpty(item.Fields[fieldName].ToString()) ? _itemDisplayName : item.Fields[fieldName].ToString();
            }
            return _returnValue;
        }
    }
}

The Style.css-file:

#SiteMapLeftColumn { width: 300px; float: left; margin-right: 20px; }
#SiteMapRightColumn { width: 300px; float: right; margin-top: 37px; }
#SiteMap { margin: 20px 0 0 0; }
#SiteMap ul { list-style: none; padding: 0; margin: 0; }
#SiteMap li { margin: 4px 0 0 20px; font-size:1em;  }
#SiteMap li.level0 { font-weight: 100; font-size: 1.8em; }
#SiteMap li.level1 { font-weight: 100; font-size: 1.8em; margin-top: 20px; }
#SiteMap li.level2 { font-weight: 800; list-style: url('/Images/menu/MenuArrL02Light.png') outside; margin-top: 10px; }
#SiteMap li.level4 { list-style: disc outside; font-size:0.95em; }

, ,

By  -      


Kommentera

E-postadressen publiceras inte. Obligatoriska fält är märkta *