Search code examples
sitecoresitecore8rule-enginesitecore-mvc

Sitecore - Dynamic actions on the Rules engine field type


We have a rules field type on a template and we want set to the action of the the rules engine to change the data source to one of the children of the item that the rules field is on.

I have tried to create a custom macro but cannot get an id to the item we are amending from inside.

The "Text:" field of the /sitecore/templates/System/Rules/Action template only accepts a hard-coded root path:

set data source to [DataSource,Tree,root=/sitecore/content/data/item1/item1a/&setRootAsSearchRoot=true,Item] 

We would like to be able to set it to something dynamic such as:

set data source to [DataSource,Tree,root=query:./*&setRootAsSearchRoot=true,Item]

Is there any way to get the item the rules field is on from inside the macro? Or do I need to something extreme like extending the rules field type?


Solution

  • Can you do this? Yes, but unfortunately it is going to be really dirty and will likely take some extra time to develop and test.

    The Problem

    The first thing to note whenever you decide to create a custom Macro is that when your Macro runs you won't have an Item Context and your Site Context is going to be shell. In other words:

    • Sitecore.Context.Site : shell
    • Sitecore.Context.Item : null

    This means that you won't have any way to determine what your Context Item actually is, or even the Site that it belongs to.

    Making matters worse, note that your Context Database is going to be core. In other words:

    • Sitecore.Context.Database : core

    This means that you are going to need a custom processor that will resolve the Context Database, Site and Item and then store the Item in Session for you to use.

    Solution Concept

    You will need to do two things in order to get this to work:

    1. Create a custom processor that will resolve and store the "context" item for you
    2. Create a custom Tree macro that supports an alternative root parameter that accepts a Sitecore Query

    Content Editor Solution

    If you want to make this work in the Content Editor, you will have to tap into a pipeline that runs when the item fields are displayed. I did some research into this and I think you will have the easiest time adding to the <getContentEditorFields> pipeline.

    The idea, here, is that when the Content Author navigates to an item in the Content Editor, this pipeline will run to get all the fields to be displayed. While this pipeline is running, your processor is grabs the item and stores it in Session for you to use in your macro.

    Note that I have not tested this, but the concept should work. The greatest flaw with this solution, however, is that it will not work in the Experience Editor.

    Experience Editor Solution

    Based on the description in the OP, I don't think this solution will work for you, but I have included it just in case.

    If you know that your Content Authors are only ever going to be using this rule for personalization or something like that from the Experience Editor, you can tap into the Content Authoring flow of the Experience Editor to resolve your context.

    The idea, here, is that when the Content Author navigates to that page in the Experience Editor, the typical Sitecore Pipelines are run and you can use them, specifically the <httpRequestProcessed> pipeline, to resolve and store the context item, from the sc_itemid query string parameter.

    Note that I have not tested the above, and that I have adapted this solution from its original source. The logic is sound, but the greatest flaw is that this will not work from the Content Editor.

    Conclusion

    The reality is that this is a ton of work to perform to save your content authors from having to traverse down to the Context Item in the tree. I understand that it would be better for their experience, and that it can help to enforce certain restrictions, e.g. the selected item must be a child/descendant, but the cost is pretty high.

    If you really do need something like this implemented, my recommendation would be to instead incorporate a child/descendant-check into your condition/action. If the selected item is not a child/descendant then you would abort the rule, log an error and display an error popup to the user. It's not the same UX, but it won't require a dirty hack and a ton of hours to do.