NReed.Dev

Sitecore | Optimizely | .NET

Sitecore 10 Placeholder Inheritance

What do you do when you want a Rendering exclusively on a specific page?

The usual way is to create a placeholder specifically for that page and add all the Renderings to that specific placeholder. The problem with that is now you have to add new Renderings to every. Single. Page. Specific. Placeholder.

Here is where inheritance can simplify things.

Next we can have one placeholder that has a Base Placeholder Setting(s). This will allow us to add any net new Renderings to one placeholder!

C#
using System.Collections.Generic;
using System.Linq;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Pipelines.GetPlaceholderRenderings;
using Sitecore.XA.Foundation.Abstractions;
using Sitecore.XA.Foundation.PlaceholderSettings.Services;
using GetAllowedRenderings = Sitecore.XA.Foundation.PlaceholderSettings.Pipelines.GetPlaceholderRenderings.GetAllowedRenderings;

namespace Website.Foundation.PlaceholderSettings.Pipelines.GetPlaceholderRenderings
{
    public class GetAllowedCompositeRenderings : GetAllowedRenderings
    {
        public GetAllowedCompositeRenderings(ILayoutsPageContext layoutsPageContext, IContext context) : base(layoutsPageContext, context)
        {
        }

        public new void Process(GetPlaceholderRenderingsArgs args)
        {
            Assert.IsNotNull(args, nameof(args));
            base.Process(args);

            var placeholderRenderings = args?.PlaceholderRenderings ?? new List<Item>();

            var placeholderRendering = placeholderRenderings.FirstOrDefault();
            if (placeholderRendering != null)
            {
                if (args != null)
                {
                    args.HasPlaceholderSettings = true;
                    var renderings = GetRenderings(placeholderRendering, out var _);

                    if (renderings != null) args.PlaceholderRenderings.AddRange(renderings);
                }
            }

            if (args?.PlaceholderRenderings != null && args.PlaceholderRenderings.Any()) args.Options.ShowTree = false;
        }

        protected override List<Item> GetRenderings(Item placeholderItem, out bool allowedControlsSpecified)
        {
            var list = base.GetRenderings(placeholderItem, out allowedControlsSpecified) ?? new List<Item>();

            var inheritedSettingsField = (MultilistField)placeholderItem?.Fields["BasePlaceholderSettings"];

            if (inheritedSettingsField != null)
                foreach (var item in inheritedSettingsField.GetItems())
                    list.InsertRange(0, base.GetRenderings(item, out allowedControlsSpecified));

            return list.Distinct().ToList();
        }
    }
}

The Sitecore item needs to be created. It MUST inherit from the Base Placeholder in SXA. Which is located at <mark>/sitecore/templates/Foundation/Experience Accelerator/Placeholder Settings/Base/_Base Placeholder</mark>

This is the guid of the Placeholder Settings item in Sitecore 10.x {1CE3B36C-9B0C-4EB5-A996-BFCB4EAA5287}

Now once we have created our new placeholder we need to assign it to the Placeholder Settings for our Page.

This can be done by going to the Placeholder Settings in the Presentation Details and selecting Placeholder Settings. The Placeholder key needs to match the placeholder of what you are inheriting.

Save and publish and voila! Now you can have both placeholders where you have all of your reusable components and have page specific components.


Leave a Reply

Your email address will not be published. Required fields are marked *