1

Our Sitecore 9.0 MVC solution makes extensive use of personalization rules to conditionally hide certain Renderings. But we have marketing automation software that scans the DOM for certain data-tracking attributes on all of the components (renderings). We would like to be able to tell if a component has been hidden and instead of rendering that component to the DOM, just render a non-visible "stub" like so:

<div class="data-tracking-hidden" data-tracking-bladetype="Large Hero" data-tracking-bladename="Large Hero 1" data-tracking-rule="Default" style="display: none;" />

I am planning on having the Models for these components throw their data-tracking attributes into a Dictionary in the HttpContext.Current.Items when they're instantiated, with the Rendering ID as the key. This Dictionary would only hold the renderings that will be hidden. That part isn't too hard. Then when the actual rendering takes place I need to somehow check if the current Rendering has an ID matching one in the Dictionary, and if so render the stub div with data-tracking attributes taken from this Dictionary, instead of skipping the Rendering altogether.

This is where I am having trouble. From my research so far, I think I have to override the Personalize Processor in the mvc.customizeRendering Pipeline using patch:instead. Or add a new Processor before this one using patch:before. I added a new class RenderHiddenComponents that inherits from CustomizeRenderingProcessor and have been debugging trying to find the right part of the Pipeline to plug into but no luck so far.

Does this seem like the right Pipeline and Processor to update to accomplish this task? And once I get inside the Processor and have access to args.Rendering, how would I 1. make sure it renders instead of hides and 2. make it render the one-line stub div instead of the actual component?

Perhaps I need to create a new component for this purpose with a Controller Rendering, Controller, Model, and View. The Model would contain the data-tracking field values, and the View would just be the hidden div that holds those values. Then in the Pipeline, somehow change the Rendering to this new one instead of hiding it. Or maybe there's a simpler way. Any ideas are appreciated, thanks.

2 Answers 2

2

You don't need to modify any piplines to do this. Create your component that renders the non-visible div, and then in your personalization, create a rule that runs only when your component is hidden. Instead of hiding the main component, just swap it out for your stub component.

In the personalization dialog. Turn on the Personalize the presentation of the component toggle, then in your rule, click the ... button under presentation and select your stub component, then set the content:

enter image description here

1
  • Yes that would work for one component on one page. But we have thousands of pages with many components each, so I need an approach that is more universal. Thanks.
    – pirsqua
    Feb 28, 2020 at 17:18
2

Ok, there is a better way to do this without using pipelines. We want to change what the Hide Rendering action does from hiding the Rendering to displaying a different Rendering that is just the one-line hidden div with the data-tracking attributes we want. In the Content Tree, we can search for "Hide Rendering":

In the Type field the value is "Sitecore.Rules.ConditionalRenderings.HideRenderingAction,Sitecore.Kernel". So this is the method that is run when a Rendering is hidden. Using dotPeek, here is the implementation of that method:

This is super simple. The key line is "ruleContext.References.Remove(ruleContext.Reference);". Instead of removing the rendering, we want to set the rendering to a new one that serves up a View with just the one-line div. So we just have to change the Hide Rendering content item's Type field to point to a class and assembly in our own solution. This is the same as the default implementation except for the last line:

using Sitecore;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.Rules.Actions;
using Sitecore.Rules.ConditionalRenderings;

namespace MySolution.Website.Rules
{
    /// <summary>
    /// This class replaces "Sitecore.Rules.ConditionalRenderings.HideRenderingAction,Sitecore.Kernel", which is set
    /// on the /sitecore/system/Settings/Rules/Definitions/Elements/Conditional Renderings/Hide Rendering item in Sitecore
    /// </summary>
    public class ReplaceHiddenRenderingWithStub<T> : RuleAction<T> where T : ConditionalRenderingsRuleContext
    {
        public static string RenderHiddenComponentRendering = "{01CC3FFF-B8A3-45A0-8565-068D01A1F594}";

        public override void Apply(T ruleContext)
        {
            Assert.ArgumentNotNull((object)ruleContext, nameof(ruleContext));
            if (Context.PageMode.IsExperienceEditor)
                ruleContext.Reference.SetRendering(RenderingIDs.HiddenRendering);
            else
                ruleContext.Reference.SetRendering(ID.Parse(RenderHiddenComponentRendering));
        }
    }
}

The RenderHiddenComponentRendering string is the ID of the new Rendering we're replacing the old Rendering with. Now point that new Controller Rendering in Sitecore to a new Controller with a name like RenderHiddenComponentController. Our base Controller has a DataSourceItem property which uses RenderingContext.Current.Rendering.DataSource to get at the current item being rendered, and from there we can get the data-tracking attributes to the Model and add them to our new View.

Now any time a component is hidden by a personalization rule, we instead render the little hidden div, so our marketing analytics software can parse the page and better understand the personalization by seeing what components were hidden.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.