A little over a year ago I did a post on Dynamic Key Placeholders, since then I have noticed
there was some information lacking, such as what versions of Sitecore it works
with, and how to get Placeholder Settings to work.
From my testing this should work in every version of Sitecore from
6.5 to 8.0, and likely will continue working in previous and future versions as
well.
The Old Way
By default when
using dynamic key placeholders you can create placeholder settings for each
index of the key. Such as if the
original key was Placeholder, you
would need to create settings for Placeholder1,
Placeholder2, etc… This can lead to a
lot of work, and a cluttered collection of placeholder settings.
A New Way to Do It
An easier way would
be to create an override of the GetAllowedRenderings processor to allow for an
experience more like the original when creating placeholder settings.
A Quick Modification to the Original
In the original
source for the dynamic key placeholders we need to make a simple modification. In the part of the code that we set the key I have added the # symbol in there to allow us to
split it apart far easier to create an override for Placeholder Settings. You can use any symbol you want, but keep I
will continue with this one for the rest of the post.
// Count represents
how many of the same container have already been added to the page
if (renderings.Any())
{
_dynamicKey = _key + "#" + renderings.Count();
}
Our New Processor
The big changes though are in the addition of overriding the
GetAllowedRenderings processor. The change
is not too complex as we are basically mirroring what Sitecore is already
doing, but with the exception of overriding the placeholder key.
To override the key
we want to split the key first into the segments by the / character and then
for each segment we use the split on the # to remove our index from the dynamic
key giving us the original key.
After that we want
to try to get the placeholder item using our cleaned up key. Of course if there is a device specified we
should get the item in the context of that device.
If the Item exists
we should get the list of renderings it supports.
public class GetAllowedRenderings : Sitecore.Pipelines.GetPlaceholderRenderings.GetAllowedRenderings
{
/// <summary>
/// This is a method
based on the original Sitecore method to allow for dynamic placeholder keys
/// </summary>
/// <param name="args">The Placeholder
Rendering Args (Device, Key, Database, etc...)</param>
public new void Process(GetPlaceholderRenderingsArgs args)
{
Assert.IsNotNull((object)args, "args");
//Remove the dynamic
indexing from the key
var key = string.Join("/", args.PlaceholderKey.Split('/').Select(i => i.Split('#')[0]));
//Get the
placeholder item, if there is a Device selected get it using that Device
Context
Item placeholderItem = null;
if (ID.IsNullOrEmpty(args.DeviceId))
{
placeholderItem = Client.Page.GetPlaceholderItem(key, args.ContentDatabase, args.LayoutDefinition);
}
else
{
using (new DeviceSwitcher(args.DeviceId, args.ContentDatabase))
{
placeholderItem = Client.Page.GetPlaceholderItem(key, args.ContentDatabase, args.LayoutDefinition);
}
}
//If there was a
placeholder item (Placeholder Settings) set the allowed renderings
if (placeholderItem != null)
{
args.HasPlaceholderSettings
= true;
bool
allowedControlsSpecified;
args.PlaceholderRenderings
= this.GetRenderings(placeholderItem,
out
allowedControlsSpecified);
if
(allowedControlsSpecified)
args.Options.ShowTree = false;
}
}
}
Our Configuration Change
Finally we have the configuration file to enable
this override, this is simply done by replacing the processor in the
getPlaceholderRenderings pipeline.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<getPlaceholderRenderings>
<processor patch:instead="*[@type='Sitecore.Pipelines.GetPlaceholderRenderings.GetAllowedRenderings,
Sitecore.Kernel']" type="[Your Method], [Your Assembly] />
</getPlaceholderRenderings>
</pipelines>
</sitecore>
</configuration>
Update (4/10/2015):
Thank you Jamie
Stump for pointing this out.