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 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:
Then you'll find your query returns no items when it is used to display the properties of your component:
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:
Which is the correct answer. Bingo.
↑ Back to top