Multilist fields with source queries in Parameter Templates

I’ve talked previously about how you can improve your content editors’ understanding of where things live inside your Sitecore content tree by making use of relative queries to specify where the editing UI finds things. You can do it when you set the source property for some types of field (like Multilists for example) and you can do it for Data Sources.

Logically, you’d assume that if a relative query works for a Multilist field in a normal template, it should work in a Parameter Template too? Well, if you set up something like this:

Schema

Then you’ll find your query returns no items when it is used to display the properties of your component:

Empty

What’s going on here then? Should it not be showing the items “A” and “B” here, because they’re the children of the current content item…

A colleague of mine hit this issue on a project recently, tried a solution and suggested I write it up. (So hat tip to Joe Dearsley for the inspiration for this post) He pointed out the key issue to me: That if your query is part of a Parameter Template, then when it runs the context item is not the content item that this dynamic binding is part of – it’s the Parameter Template’s Standard Values item instead. Hence you don’t get back the results you expected from your query.

But never fear, it’s not difficult to fix, if you find yourself with this issue.

When Sitecore is processing the Source property of your fields, it runs a pipeline to sort out any queries or processing necessary before acting on the data. This deals with the process of transforming your “query:./*” into a set of items to be displayed. So we can amend the pipeline and insert a bit of code to resolve this situation for us.

Poking around with Reflector, you can discover that the getLookupSourceItems pipeline contains two steps by default. And one of them already deals with translating a query into the correct set of items. All that’s wrong is that in this case it’s using the wrong context item. So lets insert a new pipeline processor to resolve this. The config is as follows:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>

      <getLookupSourceItems>
        <processor patch:before="*[@type='Sitecore.Pipelines.GetLookupSourceItems.ProcessQuerySource, Sitecore.Kernel']"
            type="Testing.ParameterTemplateSourceQueries, Testing" />
      </getLookupSourceItems>
      
    </pipelines>
  </sitecore>
</configuration>

The code for a quick fix is also pretty simple:

public class ParameterTemplateSourceQueries
{
    private ID BaseParameterTemplate = new ID("{8CA06D6A-B353-44E8-BC31-B528C7306971}");

    public void Process(GetLookupSourceItemsArgs args)
    {
        if (!args.Source.StartsWith("query:"))
        {
            return;
        }

        if (!args.Item.Template.BaseTemplates.Where(bt => bt.ID == BaseParameterTemplate).Any())
        {
            return;
        }

        string url = WebUtil.GetQueryString();
        if (string.IsNullOrWhiteSpace(url))
        {
            return;
        }

        FieldEditorParameters parameters = FieldEditorOptions.Parse(new UrlString(url)).Parameters;

        var currentItemId = parameters["contentitem"];
        if (string.IsNullOrEmpty(currentItemId))
        {
            return;
        }

        Sitecore.Data.ItemUri contentItemUri = new Sitecore.Data.ItemUri(currentItemId);
        Item contextItem = Sitecore.Data.Database.GetItem(contentItemUri);

        args.Item = contextItem;
    }
}

The arguments passed in describe the field being processed. If the Source property doesn’t start with the phrase “query:” then we don’t need to process the data, and can let the pipeline continue. (In the real world, this code should probably also handle fast queries too though)

Next we need to check if we’re being called for the right reasons. We only want this code to run if the current context item is based on the “Standard Rendering Parameters” template. So we check the base templates of the item to ensure that at least one of them matches this. If not, we can stop.

Now we can assume that the user is looking at the “Control Properties” dialog, and we can grab the querystring data for the web request that displayed the dialog. This should contain some useful data we need. So if it’s empty, again we can stop processing.

The querystring can then be parsed into a FieldEditorParameters object. Amongst other things, this can give us the full Sitecore ID of the context content item. So we grab that and check it’s not empty for some reason, and if not, parse it and load it.

And that item is the thing we want to be our real context item – so we assign it to the pipeline arguments’ Item property, and let the pipeline carry on and deal with the query expansion.

So with that in place, if we repeat our previous test we see:

Now it works...

Which is the correct answer. Bingo.

Advertisements

3 thoughts on “Multilist fields with source queries in Parameter Templates

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s