Skip to main content
2 of 2
added 3397 characters in body

Sitecore's personalization is a fantastic and powerful feature, but it can require special performance considerations depending on how you use it.

Code-Based Approach

The first thing that you should ask yourself is do my content authors really need to be able to control the personalization of these menus themselves? If the answer is yes, then feel free to skip the rest of this approach. Otherwise, read on.

The fastest possible solution on all visits that you could implement would be a purely code-based solution. Obviously, I'm not going to recommend that you hard-code links or IDs, but what you can do is put checkbox fields on your links that say whether they display if a predefined condition is met. This is not a rule-based or other dynamic condition; think simple, like "Administrators only" or something similar that your application can be made aware of without having to run rules or other dynamic logic.

If you can make a code-based solution work for your use-case then this will likely be the most performant solution on every visit.

Separate Renderings per Link Approach

In the case that you mentioned, so long as your menus have 10 or fewer links each and only display on each page once, my recommendation would be that you use a separate rendering for each of the links and personalize the rendering to hide (be excluded from the menu) should the exclusion conditions pass. This will likely be the simplest solution for your content authors, and should not have any noticeable impact on page load speed. This solution is, however, less performant than using groups of links.

Groups of Links with One Rendering Approach

If you have more than 10 links or if you display your menu multiple times per page, my recommendation would be that you configure groups of links to display for a single rendering. This should be less rules for Sitecore to have to execute when it renders the menu, so that should save you on performance, but it does cost you in the editor-friendliness category.

Cheating and Customizing Sitecore's Caching Approach (Top Choice)

The problem with the personalization-based approaches isn't usually the performance cost of rendering the data (which can be expensive for renderings with lots of business logic), but rather the performance cost of running the rules to figure out what data should actually be rendered. If you need to have editor-friendly personalization control and still have a performant solution, then my advice is to cheat and customize Sitecore's Caching so that you can cache the result once you've rendered it once.

The idea with this approach is that you can add Sitecore Caching support to enable to you cache based on the same conditions that you use for personalizing your renderings. This is a bit of a confusing concept, but it may be easier to wrap your mind around it with an example. Consider that you are personalizing based on favorite color: Red, Blue, Green, Pink, Purple, Orange or Other. The first thing that you do is implement the Separate Renderings Per Link Approach, adding one rendering per link and personalizing each rendering to hide if the exclusion conditions are met. You then customize your Sitecore Caching to include a setting for varying your caching by favorite color. You can call this setting Vary By Favorite Color and include it in the caching options of the rendering. You would then extend the GenerateCacheKey processor to add a key for the current visitor's (or the current user, if favorite color is stored in the User Profile) favorite color, if available. The result would be that the first time the rendering is requested for one of the colors, the personalization rules would run and the page would take a little longer to load. However, on all subsequent loads for a visitor/user with that favorite color, the personalization rules would be skipped, as the output would have already been cached.

The following code sample will get you what you are looking for:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Sitecore.Analytics;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.Layouts;
using Sitecore.Mvc.Extensions;
using Sitecore.Mvc.Pipelines.Response.RenderRendering;
using Sitecore.Mvc.Presentation;
using Sitecore.Rules.ConditionalRenderings;

namespace MyNamespace.Pipelines.MvcRenderRendering
{
    public class GenerateCacheKey : Sitecore.Mvc.Pipelines.Response.RenderRendering.GenerateCacheKey
    {
        /// <summary>
        /// Holds the name of the Sitecore checkbox field that controls whether the cache key 
        /// should vary by favorite color of the user/visitor
        /// </summary>
        private const string VaryByFavoriteColorFieldName = "VaryByFavoriteColor";

        /// <summary>
        /// Generates the cache key with all caching variance parts added
        /// </summary>
        protected override string GenerateKey(Rendering rendering, RenderRenderingArgs args)
        {
            var cacheKey = base.GenerateKey(rendering, args);
            
            // if set to vary caching by favorite color add the favorite color part to the key
            if (IsCacheVaryByFavoriteColor(rendering))
            {
                cacheKey += GetFavoriteColorPart();
            }

            return cacheKey;
        }

        /// <summary>
        /// Checks if the rendering is set to vary caching by favorite color
        /// </summary>
        private bool IsCacheVaryByFavoriteColor(Rendering rendering)
        {
            // so long as the VaryByFavoriteColor checkbox field exists and is checked, we should be varying by favorite color
            return rendering.RenderingItem.InnerItem[VaryByFavoriteColorFieldName] != null && rendering.RenderingItem.InnerItem[VaryByFavoriteColorFieldName] == "1";
        }

        /// <summary>
        /// Gets the part of the cache key that will vary by favorite color
        /// </summary>
        public virtual string GetFavoriteColorPart()
        {           
            ...logic for getting favorite color from user profile or from tracking session...

            return !string.IsNullOrEmpty(favoriteColor)
                ? $"_#favoriteColor:{favoriteColor}" // adds a string unique to the favorite color to the cache key
                : string.Empty;
        }
    }
}

Note that the above processor should replace the native GenerateCacheKey processor and you will need to add the VaryByFavoriteColor field in Sitecore. To add the field, create a new template, named something like "Extended Caching", and add a field section to it, named Caching. Add a checkbox field to the new section, named VaryByFavoriteColor and set the field's title text to "Vary By Favorite Color" (capital "B" in "By" for consistency with Sitecore). Finally, add your new template to the Base Templates of the /sitecore/templates/System/Layout/Sections/Caching template. This is one of the few times that it is appropriate to modify a native Sitecore template.

Once you have completed the above, you should be able to set global caching settings on the rendering.