7

I'm trying to add Parameters to a rendering based on the placeholder it's been inserted into. I've been trying to handle this using rules (after reading through this blog post):

  • I created a new condition (that the Placeholder name matched a given Key) based on the above blog post.
  • Created a new Rule under /sitecore/system/Settings/Rules/Conditional Renderings/Global Rules which uses the new condition
  • Set the Action for the Rule to be to change the rendering parameters

Unfortunately, I couldn't get the new rule to work. I debugged the project and put a breakpoint in the Execute method of my ConditionalRenderingsRuleContext class. Unfortunately, it never gets hit.

I've since seen this post on the Sitecore developers site which states

MVC does not support global conditional rendering rules

Does anyone have any suggestions on how to achieve this?

  • What are your parameters used for? I presume it is not something which you can just do using CSS (like left or right align)? – jammykam Oct 27 '16 at 16:35
  • @jammykam - The parameters are going to be used to set the size of images being displayed. Some placeholders are wider (ie full width, 50%, 25%, etc) so need images to be rendered at different widths. I'd like to output images resized by Sitecore at the correct dimensions rather than serve a huge image that the browser scales down. – MarkRadford Oct 28 '16 at 10:17
4

You're quite right about why it's not working - MVC renderings don't execute the global conditional rendering rules.

This is not something I've had to do, but here's a suggestion. Someone might be able to suggest a better method, but here are a couple of suggestions:

Setting parameters during rendering

You could look at amending the mvc.renderPlaceholder pipeline to achieve what you want. The processor Sitecore.Mvc.Pipelines.Response.RenderPlaceholder.PerformRendering is what retrieves the renderings for a placeholder and calls the mvc.renderRendering for each. It doesn't pass any placeholder information into this pipeline, so you would need to act here.

This is the method:

protected virtual void Render(string placeholderName, TextWriter writer, RenderPlaceholderArgs args)
{
    foreach (Rendering rendering in this.GetRenderings(placeholderName, args))
        PipelineService.Get().RunPipeline<RenderRenderingArgs>("mvc.renderRendering", new RenderRenderingArgs(rendering, writer));
}

You could extend this processor and override this method with one that executes rules for the rendering. It could then update the rendering item that gets passed into the pipeline.

It's worth considering that Sitecore perhaps didn't implement the rules here due to performance issues, so rather than reintroduce global conditional rendering rules across all MVC renderings, you might want to make this a tailored processor that only acts differently for particular renderings. This amended processor could potentially just inject the placeholder name into the rendering parameters, and then the rendering itself could decide how to act upon this.

Setting parameters upon saving

As an alternative method, though one that depends on the nature of your solution, would it be appropriate to perhaps tackle this problem at the source rather at rendering time?

For example, when the item is saved you could have an event that is triggered that looks through the placeholders + renderings and injects parameters into the renderings as required, which then get saved into the item. This way the rendering process doesn't need to be changed at all.

  • 1
    To back this up, you can also refer to the post from John West on the matter: community.sitecore.net/technical_blogs/b/sitecorejohn_blog/…. More specifically, the implementation part that refers to implementing a processor similar to the Personalize processor (/App_Config/Include/Sitecore.MvcExperienceEditor.config) with logic to evaluate conditions as the EvaluateConditions processor in the insertRenderings pipeline.Moreover, you should also note the reasons to why Sitecore "removed" this feature in MVC. – Søren Engel Oct 27 '16 at 15:48
  • Thanks for your answer @Kasaku. Very helpful. I think you're right about setting the parameters on saving instead - that sounds like a much better idea. I'll look into trying that instead and update here if / when I managed it. – MarkRadford Oct 28 '16 at 10:22
3

Just to add onto @Kasaku's response, if you are looking to create a processor for the <renderPlaceholder> pipeline that will run rules then you will either want to create a new processor to run your rules or extend and replace the OOTB Sitecore.Mvc.Pipelines.Response.RenderPlaceholder processor. From a performance standpoint, your best bet would be to extend the OOTB processor (rather than make all the same database calls a second time).

Your processor could look something like the following:

public class PerformEnhancedRendering : Sitecore.Mvc.Pipelines.Response.RenderPlaceholder.PerformRendering 
{
    protected override void Render(string placeholderName, TextWriter writer, RenderPlaceholderArgs args)
    {
        var shouldRunRules = ... // do logic to check if you should run rules, here

        if (shouldRunRules)
        {
            var ruleFolderId = ... // I recommend that you set this in configuration and then parse it
            var ruleFolderItem = Sitecore.Context.Database.GetItem(ruleFolderId);
            if (ruleFolderItem == null) 
            {
                // null-case logic here
            }

            var rules = RuleFactory.GetRules<RenderPlaceholderRuleContext>(ruleFolderItem, "Rule");
            shouldRunRules = rules != null && rules.Count > 0;
        }

        foreach (Rendering rendering in this.GetRenderings(placeholderName, args))
        {
            if (shouldRunRules)
            {                
                var ruleContext = new RenderPlaceholderRuleContext()
                {
                    Rendering = rendering,
                    PlaceholderName = args.PlaceholderName
                };

                rules.Run(ruleContext);
            }

            PipelineService.Get().RunPipeline<RenderRenderingArgs>("mvc.renderRendering", new RenderRenderingArgs(rendering, writer));
        }
    }
}

and you would need a RenderPlaceholderRuleContext class that extends the OOTB RuleContext class and adds support for the Rendering and PlaceholderName properties, so that you can pass them into your rule conditions and actions.

The ruleFolderId is the id of the Rule Folder item in Sitecore, under which you would have a rule context folder containing all of the rule items that you want to run.

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.