Tom Dudfield Logo
Digital Agencies,  Sitecore

Sitecore shared placeholders

Author

Tom Dudfield

Date Published

Atomic design principles

Having recently attended SUGCON Europe 2016 in Copenhagen, I arrived back in Bournemouth buzzing with different ideas that we could make use of at Redweb.

One of my favourite talks was Atomic Design To The Max by Tim Braga. Tim talked about the journey his team had taken at Collette to implement Atomic Design.

They faced a challenge while implementing Atomic Design for their new header and footer. The problem with Sitecore, is that normally you statically bind the header and footer to a placeholder to avoid content editors having to set it on individual pages. The downside is you lose some of Sitecore's nice features such as A/B testing and personalisation. It also means you can't make use of Dynamic Placeholders that Atomic Design is heavily reliant on (hopefully one day Sitecore will add Dynamic Placeholders into the core product).

Tim has come up with a solution for Sitecore 7 that allows content editors to set header and footer renderings on a Home item which is then shared across all other items.

When implementing this on a Sitecore 8 solution, I ran into issues where the code didn't behave as expected, so I've had to tweak the code to get it working. I've taken the opportunity to enhance it slightly, you can now control the placeholder names and Home Item ID within configuration. I have also removed the need for the JS changes by adding another Sitecore pipeline - RemoveSharedRenderings.

1using System.Collections.Generic;
2using System.Linq;
3using System.Xml.Linq;
4using Sitecore;
5using Sitecore.Data;
6using Sitecore.Data.Fields;
7using Sitecore.Data.Items;
8using Sitecore.Diagnostics;
9using Sitecore.Mvc.Extensions;
10using Sitecore.Mvc.Pipelines.Response.GetXmlBasedLayoutDefinition;
11using Sitecore.Mvc.Presentation;
12
13namespace Library.DotNet.Sc.Pipelines.GetXmlBasedLayoutDefinition
14{
15 public class GetFromLayoutFieldWithSharedPlaceholders : GetFromLayoutField
16 {
17 private readonly List<string> _placeholders = new List<string>();
18
19 public void AddPlaceholder(string placeholders)
20 {
21 if (!string.IsNullOrEmpty(placeholders))
22 {
23 _placeholders.Add(placeholders);
24 }
25 }
26
27 public string HomeItemTemplateId { get; set; }
28
29 public override void Process(GetXmlBasedLayoutDefinitionArgs args)
30 {
31 if (args.Result == null)
32 {
33 XElement content = GetFromField(args);
34 if (content != null)
35 {
36 Item item = PageContext.Current.Item;
37 if (item != null && item.TemplateID != new ID(HomeItemTemplateId))
38 {
39 Log.Debug("GetFromLayoutField - Process : Not on homepage");
40 Item homeItem = Context.Database.GetItem(Context.Site.StartPath);
41 if (homeItem != null)
42 {
43 Field homePageLayoutField = homeItem.Fields[FieldIDs.LayoutField];
44 if (homePageLayoutField != null)
45 {
46 string fieldValue = LayoutField.GetFieldValue(homePageLayoutField);
47 if (!fieldValue.IsWhiteSpaceOrNull())
48 {
49 XElement homePageLayout = XDocument.Parse(fieldValue).Root;
50 XElement dXElement = content.Element("d");
51 if (dXElement != null && homePageLayout != null)
52 {
53 XElement dXElementInHomePageLayout = homePageLayout.Element("d");
54 if (dXElementInHomePageLayout != null)
55 {
56 var layoutElements = dXElementInHomePageLayout.Elements().ToList();
57
58 foreach (var placeholder in _placeholders)
59 {
60 dXElement.Add(ExtractContentsFromLayout(layoutElements, placeholder));
61 }
62 }
63 }
64 }
65 }
66 }
67 }
68 }
69
70 args.Result = content;
71 }
72 }
73
74 private List<XElement> ExtractContentsFromLayout(IEnumerable<XElement> layoutElements, string placeholder)
75 {
76 Log.Debug(string.Format("GetFromLayoutField - Process : Starting to extract for placeholder {0}:", placeholder));
77
78 List<XElement> elements = new List<XElement>();
79
80 if (layoutElements.Any())
81 {
82 foreach (XElement element in layoutElements)
83 {
84 if (element.HasAttributes)
85 {
86 if (element.Attribute("ph") != null)
87 {
88 string value = element.Attribute("ph").Value.ToLowerInvariant();
89 if (!string.IsNullOrEmpty(value) && (value.StartsWith("/" + placeholder.ToLowerInvariant()) || value.Equals(placeholder.ToLowerInvariant())))
90 {
91 elements.Add(element);
92 }
93 }
94 }
95 }
96 }
97 Log.Debug("GetFromLayoutField - Process : Done with extract");
98
99 return elements;
100 }
101 }
102}


Sitecore User Group Dorset Logo
Sitecore,  Digital Agencies,  Software Development

I am organising the first Sitecore User Group in Dorset, it will be held in Redweb’s Loading Bar on Thursday 29th September from 6pm.

Sitecore Symposium 2016
Sitecore,  Digital Agencies

I was fortunate enough to be able to attend Sitecore Symposium this year hosted in New Orleans.