Sitecore Root Item

      3 Comments on Sitecore Root Item

For my first post, I figured I’d start with something simple but was a recent discovery.  I’ve been using Sitecore since v6.4 (now v7.5) but this was something I didn’t know was available and still required a little tweaking before it functioned exactly the way I needed.

Often you need a piece of content or configuration that you would consider to be “global” in the sense of being consistent everywhere for an entire site.  This is normally the case if your site is sharing a Sitecore instance with several others.  Sitecore understands sites the same way ASP.NET and IIS do, either by a given domain or virtual (or physical) directory.  It’s made that much more obvious when you look at how a site is configured in the Web.config

<site
name="example"
virtualFolder="/"
physicalFolder="/"
rootPath="/sitecore/content/Example Site"
startItem="/Home"
...

From the content tree, that would something like this:

findgnosis - sitecore root item - 001

In the past, if I were on the Home item and I wanted to get the item that represented the root of the site, I would do so by traversing through the current page’s ancestors and checking against the template(s) of each.

        public static Item SiteRoot
        {
            get
            {
                return Gnosis.Sitecore.Data.Utility.FindFirstAncestorByBaseTemplate("Base Site Root");
            }
        }

        public static Item FindFirstAncestorByBaseTemplate(string baseTemplateName)
        {
            return FindFirstAncestorByBaseTemplate(global::Sitecore.Context.Item, baseTemplateName);
        }

        public static Item FindFirstAncestorByBaseTemplate(Item current, string baseTemplateName)
        {
            if (current == null)
            {
                throw new Exception("Current item is NULL");
            }
            
            Item result = null;

            while (result == null && current.Parent != null)
            {
                if (ItemHasBaseTemplate(current.Parent, baseTemplateName))
                {
                    result = current.Parent;
                }
                else
                {
                    current = current.Parent;
                }
            }

            return result;
        }

        public static bool ItemHasBaseTemplate(Item i, string baseTemplateName)
        {
            if (i.Template == null)
            {
                throw new Exception(string.Format("Item {0} ({1}) has no template", i.Name, i.Paths.FullPath));
            }
            return TemplateHasBaseTemplate(i.Template, baseTemplateName);
        }

        public static bool TemplateHasBaseTemplate(TemplateItem t, string baseTemplateName)
        {
            if (t.Name == baseTemplateName)
            {
                return true;
            }

            foreach (TemplateItem b in t.BaseTemplates)
            {
                if (TemplateHasBaseTemplate(b, baseTemplateName))
                {
                    return true;
                }
            }

            return false;
        }

Probably not the most efficient method but it does work.  You can inject some level of caching to improve it but at the end of the day, it still ends up adding runtime processing.

If you’re data is organized as I described and you have an entry in the Web.config to identify it as a site, Sitecore actually has a hook into it the class “Sitecore.Sites.SiteContext” with a static instance of it at “Sitecore.Context.Site”.  The only catch is, nothing on SiteContext contains an instance of an Item, so I wrote a quick shortcut:

        public static Item SiteItem
        {
            get
            {
                return Sitecore.Context.Database.GetItem(Sitecore.Context.Site.RootPath);
            }
        }

Now, I can make a reference to that item anywhere in my code, like in the middle of some MVC Razor syntax:

<p>Welcome to @Sitecore75Sandbox.Utility.SiteItem["Site Name"]<p>

For all I know, Sitecore’s internal logic to define Sitecore.Context.Site isn’t perfect but it has to be better than digging through the content tree!

3 thoughts on “Sitecore Root Item

  1. Mike Edwards

    When using this solution you should be aware that sometimes this can have unexpected behaviour in the Page Editor/Preview when you have a multi site solution.
    For example I might have http://www.sitea.com and http://www.siteb.com configured in Sitecore which works find in normal mode. However on your CMS you might go to cms.sitea.com and from there try to edit siteb.com in page editor. This causes a problem because Sitecore has seen that you have come in on cms.sitea.com and used the root path for sitea and not siteb. In this scenario the ancestor solution is better.

    1. celston Post author

      That’s an interesting situation you describe, Mike. Could it possibly be worked around by making sure the order of the “sites/site” nodes in the Web.config go for most specific to least specific. In other words to your example, having cms.sitea.com appear before sitea.com or vice-versa?

  2. Hosting

    I m not sure if there is a better practice of doing so, but I just called the context database and then grabbed the root item. This happened to be sitecore Where I can then grab the global item from there.

Leave a Reply