Dynamic content in navigation

August 01, 2014 Digital Experience

Making a dynamic navigation that incorporates product offerings, content or specials can drastically improve the end user experience. This blog post explains a technique that allows you to extend the navigation to include any type of content. 

Currently Sitefinity can display only items of type PageNode (i.e. Pages) in the out of the box Navigation controls.

In order to display dynamic content, you would need custom navigation control, which will be bound to the SitefinitySiteMapDataSource - our control that provides a cached data source of the pages sitemap. You can subscribe to the navigation control's ItemDataBound event, and insert new items under the desired page, by using the Sitefinity API to retrieve a collection of the content items of the desired type.

For example:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MixedNavigation.ascx.cs" Inherits="SitefinityWebApp.SupportSamples.MixedNavigation" %>
<%@ Register TagPrefix="sfNav" Namespace="Telerik.Sitefinity.Web.UI.NavigationControls" Assembly="Telerik.Sitefinity" %>
  
<sfNav:SitefinitySiteMapDataSource id="navDataSource" runat="server" ShowStartingNode="false" />
<telerik:RadMenu id="rmNavigation" runat="server" DataSourceID="navDataSource"></telerik:RadMenu>

and its code-behind logic:

using System;
using System.Globalization;
using System.Linq;
using Telerik.Sitefinity.Modules.Ecommerce.Catalog;
using Telerik.Sitefinity.Services;
using Telerik.Sitefinity.Web;
  
namespace SitefinityWebApp.SupportSamples
{
    public partial class MixedNavigation : System.Web.UI.UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //Subscribe to ItemDataBound so you can insert new items under desired node on data binding
            rmNavigation.ItemDataBound += rmNavigation_ItemDataBound;
        }
  
        void rmNavigation_ItemDataBound(object sender, Telerik.Web.UI.RadMenuEventArgs e)
        {
            if (e.Item.DataItem is PageSiteNode)
            {
                var page = e.Item.DataItem as PageSiteNode;
                //Check if the current item is the desired PageNode
                if (page.Title == ParentPageToPlaceUnder)
                {
                    //Get the collection of items
                    var manager = CatalogManager.GetManager();
                    var products = manager.GetProducts()
                        .Where(p => p.Status == Telerik.Sitefinity.GenericContent.Model.ContentLifecycleStatus.Live && p.visible == true)
                        .ToList();
                    //Get the ContentLocationService - it stores the URL statistics for all Sitefinity data items
                    var contLocationService = SystemManager.GetContentLocationService();
                    //Get the current culture, to ensure you're resolving the correct URL
                    var culture = CultureInfo.CurrentUICulture;
                    //iterate through the collection and add a new item in the navigation with the item's Title and resolved URL
                    foreach (var product in products)
                    {
                        var itemAbsoluteUrl = "";
                        //Please ensure your items are displayed at least on one page in the site, otherwise GetItemDefaultLocation() will be null
                        //You can get a list of the generated item locations by going to:
                        //Sitefinity backend -> Content -> Your desired content type -> Pages where items of your content type are published
                        if (contLocationService.GetItemDefaultLocation(product, culture) != null)
                            itemAbsoluteUrl = contLocationService.GetItemDefaultLocation(product).ItemAbsoluteUrl;
                        e.Item.Items.Add(new Telerik.Web.UI.RadMenuItem(product.Title, itemAbsoluteUrl));
                    }
                }
            }
        }
  
        //You can configure the desired page to insert the new items under - it will be displayed as a public property int he widget property editor as well
        public string ParentPageToPlaceUnder
        {
            get
            {
                return parentPageToPlaceUnder;
            }
            set
            {
                this.parentPageToPlaceUnder = value;
            }
        }
  
        //you can configure a default page to insert the new items under
        private string parentPageToPlaceUnder = "MyTargetPage";
    }
}

For your convenience I've attached the full sample to this blog post here, please feel free to modify it as per your specific requirements. You can also find here a short demonstrative video of the sample used on a  Sitefinity page.

 You can also consider assigning related products or other data directly to pages through custom fields for pages, which will allow your business users to define exactly what custom dynamic content will appear in the mega menu. You can review the documentation for querying custom fields for pages to find out what API methods to use.

 

Vassil Vassilev