1

Lets say we have 4 renderings on the Page and each rendering has a data source attached to it which has a Keyword field that is being used for SEO purpose.

Is it possible to get all the attached rendering datasource keywords on the page and display together in the Page Metadata?. I think I need to find the current page and iterate through all the renderings attached and then find a keyword text.

But will this have any performance issues or is there any better way to do it?

Any help or suggestions would be appreciated.

Thanks in advance

  • Something I learned using SXA is you can create a computed field which aggregates all the content you want. This way the text on data source items is treated like content of the page. – Michael West Nov 8 '18 at 1:42
  • @MichaelWest Is it possible in Sitecore 8.2 . Do you have any example link that would be helpful? Thanks – Owais Ahmed Nov 8 '18 at 1:54
  • Yes this should be positive since SXA has compatible versions with 8.2. Perhaps you can explore the module first to see how it works. – Michael West Nov 8 '18 at 11:16
3

This is going to be a horrible linky answer (Sorry moderators its too much code to put in an answer). But Sitecore's habitat example site that does this for assets. In the foundation.assets project, it gets styling and JavaScript from renderings and page content to assemble later on the page. Specifically it is this processor in the mvc.getPageRendering pipeline. It gets the values from a field the rendering and stuffs it into a singleton for later use in the page life cycle. You can just take it one step further and get the field from the datasource of the rendering.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
    <sitecore>
        <pipelines>
            <mvc.getPageRendering>
                <processor patch:before="*[@type='Sitecore.Mvc.Pipelines.Response.GetPageRendering.GetLayoutRendering, Sitecore.Mvc']" type="Sitecore.Foundation.Assets.Pipelines.GetPageRendering.AddRenderingAssets, Sitecore.Foundation.Assets"/>
            </mvc.getPageRendering>
        </pipelines>
    </sitecore>
</configuration>

The moment it reads the field and adds it to the singleton is the line AssetRepository.Current.AddInlineStyling(cssInline, true);

public class AddRenderingAssets : GetPageRenderingProcessor
{
    public override void Process(GetPageRenderingArgs args)
    {
        this.AddAssets(args.PageContext.PageDefinition.Renderings);
    }

    private void AddAssets(IEnumerable<Rendering> renderings)
    {
        foreach (var rendering in renderings)
        {
            var renderingItem = this.GetRenderingItem(rendering);
            if (renderingItem == null)
            {
                return;
            }

            AddAssetsFromItem(renderingItem);
        }
    }

    protected static void AddAssetsFromItem(Item renderingItem)
    {
        if (!renderingItem.IsDerived(Templates.RenderingAssets.ID))
            return;
        AddScriptAssetsFromRendering(renderingItem);
        AddInlineScriptFromRendering(renderingItem);
        AddStylingAssetsFromRendering(renderingItem);
        AddInlineStylingFromAssets(renderingItem);
    }

    private static void AddInlineStylingFromAssets(Item renderingItem)
    {
        var cssInline = renderingItem[Templates.RenderingAssets.Fields.InlineStyling];
        if (string.IsNullOrEmpty(cssInline))
        {
            return;
        }
        var asset = AssetRepository.Current.AddInlineStyling(cssInline, true);
        asset.AddOnceToken = renderingItem.ID.ToString();
    }

}

https://github.com/Sitecore/Habitat/blob/master/src/Foundation/Assets/code/Pipelines/GetPageRendering/AddPageAssets.cs#L24

The singleton is here. It is marked as [ThreadStatic] so that it is regenerated for each thread request. https://github.com/Sitecore/Habitat/blob/master/src/Foundation/Assets/code/Repositories/AssetRepository.cs

public class AssetRepository
{
    private static readonly AssetRequirementCache _cache = new AssetRequirementCache(StringUtil.ParseSizeString("10MB"));

    [ThreadStatic]
    private static AssetRepository _current;

    private readonly List<Asset> _items = new List<Asset>();
    private readonly List<ID> _seenRenderings = new List<ID>();

    public static AssetRepository Current => _current ?? (_current = new AssetRepository());

    internal IEnumerable<Asset> Items => this._items;

    internal void Clear()
    {
        this._items.Clear();
    }

    public Asset Add(Asset asset, bool preventAddToCache = false)
    {
        if (asset == null)
        {
            throw new ArgumentNullException(nameof(asset));
        }

        ........

    }
}

Then in the cshtml file, the contents are read from the singleton and placed on the page. @RenderAssetsService.Current.RenderScript(ScriptLocation.Head)

https://github.com/Sitecore/Habitat/blob/master/src/Project/Habitat/code/Views/Website/Layouts/Default.cshtml#L25

Similar to your request, you can gather all the fields from you datasources for your renderings, add them to a singleton and rendering them on the page.

  • Once you have the datasource item, you can go anywhere you want. But I would look into caching the metadata values. The more renderings you have on a page, the more calls to Sitecore it is going to be making. – Chris Auer Nov 8 '18 at 4:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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