Archive

Archive for May, 2012

Running Sitecore Field Editor from a command

21/05/2012 15 comments

When working with Sitecores page editor sometimes you need to edit Hidden fields for examples page metadata ie. “Page Title, Metakeywords, Metadescription”.  You could probably use the editframe control and if in pageedit render out the metadatacontroll through a placeholder. But a more elegant way could be by adding a button in editor Ribbon see screenshot below, and executing  the page editor with a limited set of fields, and is this post we would create a general command tha does exactly that.

To make the command as general as possible in would be tied to a settings item of the type
“/sitecore/templates/System/WebEdit/Field Editor Button”

Which contains fields for displaying

  • Header
  • Editor Icon
  • List with fields that should be shown in the editor separated with “|”

And even better you can use this where you are using the sc:editframe.

Now you can add a button of you liking, you could make a chunk here:

/sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Editor/Metadata

Under the chunk add a button
/sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Editor/Metadata/Edit

The click event
“command:executefieldeditor(path=/sitecore/content/Applications/WebEdit/Edit Frame Buttons/Metadata/EditMetadata)”

executes the command “command:executefieldeditor” specified in the commands.config file.

Mine looks like this

  <command name="command:executefieldeditor" type="PT.Framework.ExecuteFieldEditorCommand.ExecuteFiledEditor,PT.Framework.ExecuteFieldEditorCommand"/>

Now to the code, by deriving from the “FieldEditorCommand” i get the execution of the page editor for free all i have to do is specifying the correct parameters in the virtual method “GetOptions”  , note that the “PageEditFieldEditorOptions” is located in the Sitecore.Client.dll.

<
public class ExecuteFiledEditor : FieldEditorCommand
{
  protected override PageEditFieldEditorOptions GetOptions(ClientPipelineArgs args, NameValueCollection form)
  {
    EnsureContext(args);
    return new PageEditFieldEditorOptions(form, BuildListWithFieldsToShow()) { Title = SettingsItem[HEADER], Icon = SettingsItem[ICON] };
  }

  private void EnsureContext(ClientPipelineArgs args)
  {
    CurrentItem = Database.GetItem(ItemUri.Parse(args.Parameters[URIPARAMETER]));
    Assert.IsNotNull(CurrentItem, CURRENTITEMISNULL);
    SettingsItem = Client.CoreDatabase.GetItem(args.Parameters[PATHPARAMETER]);
    Assert.IsNotNull(SettingsItem, SETTINGSITEMISNULL);
  }
 private List<FieldDescriptor> BuildListWithFieldsToShow()
  {
    List<FieldDescriptor> fieldList = new List<FieldDescriptor>();
    ListString fieldString = new ListString(SettingsItem[FIELDNAME]);
    foreach (string field in new ListString(fieldString))
     if (CurrentItem.Fields[field] != null)
      fieldList.Add(new FieldDescriptor(CurrentItem, field));

   return fieldList;
  }

 private const string FIELDNAME = "Fields";
 private const string HEADER = "Header";
 private const string ICON = "Icon";

 private const string URIPARAMETER = "uri";
 private const string PATHPARAMETER = "path";
 private const string CURRENTITEMISNULL = "Current item is null";
 private const string SETTINGSITEMISNULL = "Settings item is null";

private Item CurrentItem { get; set; }
 private Item SettingsItem { get; set; }

}

And the final result:

Categories: C#, Sitecore 6 Tags: ,

Queries in Datasource location on Sitecore Layouts

15/05/2012 10 comments

The datasource location specified on layouts is limited to Sitecore paths.

But working with multisite solutions it is sometimes necessary to have some items stored locally under Site.

This could be done fairly easy hooking in to the Sitecore pipeline “getRenderingDatasource”, found in the web.config under
“/configuration/sitecore/pipelines/getRenderingDatasource”

Below I’ve inserted my own

“PT.Framework.Pipelines.GetDatasourceLocation,PT.Framework.Pipelines”

<getRenderingDatasource>
 <processor type="Sitecore.Pipelines.GetRenderingDatasource.GetDatasourceLocation, Sitecore.Kernel" />
 <processor type="PT.Framework.Pipelines.GetDatasourceLocation,PT.Framework.Pipelines" />
 <processor type="Sitecore.Pipelines.GetRenderingDatasource.SetFallbackDatasourceLocations, Sitecore.Kernel" />
 <processor type="Sitecore.Pipelines.GetRenderingDatasource.GetDatasourceTemplate, Sitecore.Kernel" />
 <processor type="Sitecore.Pipelines.GetRenderingDatasource.GetTemplatesForSelection, Sitecore.Kernel" />
 <processor type="Sitecore.Pipelines.GetRenderingDatasource.CheckDialogState, Sitecore.Kernel" />
 <processor type="Sitecore.Pipelines.GetRenderingDatasource.GetDialogUrl, Sitecore.Kernel" />
 </getRenderingDatasource>

The code for this step is really simple:

</pre>
public void Process(GetRenderingDatasourceArgs args)
 {
 Assert.IsNotNull(args, "args");
 DatasourceLocation = args.RenderingItem["Datasource Location"];
 if(QueryInDataSourceLocation())
 ProcessQuery(args);
 }

private void ProcessQuery(GetRenderingDatasourceArgs args)
 {
 ContextItemPath = args.ContextItemPath;
 ContentDataBase = args.ContentDatabase;
 Item datasourceLocation = ResolveDatasourceRootFromQuery();
 if (datasourceLocation != null)
 args.DatasourceRoots.Add(datasourceLocation);
 }

private bool QueryInDataSourceLocation()
 {
 return DatasourceLocation.StartsWith(_query);
 }

private Item ResolveDatasourceRootFromQuery()
 {
 string query = DatasourceLocation.Replace(_query, ContextItemPath);
 return ContentDataBase.SelectSingleItem(query);
 }

private string DatasourceLocation { get; set; }
 private string ContextItemPath { get; set; }
 private Database ContentDataBase { get; set; }
 private const string _query = "query:.";
<pre>

Now you can write queries like “./ancestor-or-self::*[@@templatekey=’site’]/Spots”

Update – Multiple datasource locations

Since one might want to have multiple Datasource Roots i made a change to the code so you can separate queries with the “|” delimiter. Note the normal sitecore path is still working and handled by the
“Sitecore.Pipelines.GetRenderingDatasource.GetDatasourceLocation”.

Now you can write

query:./ancestor-or-self::*[@@templatekey=’main section’]/QueryGlobal|/sitecore/content/GlobalSpots|query:./ancestor-or-self::*[@@templatekey=’site’]/Spots


public class GetDatasourceLocation
 {
 public void Process(GetRenderingDatasourceArgs args)
 {
 Assert.IsNotNull(args, "args");
 DatasourceLocation = args.RenderingItem["Datasource Location"];
 ContextItemPath = args.ContextItemPath;
 ContentDataBase = args.ContentDatabase;
 DatasourceRoots = args.DatasourceRoots;
 if(QueryInDataSourceLocation())
 ProcessQuerys(args);
 }

private void ProcessQuerys(GetRenderingDatasourceArgs args)
 {

ListString possibleQueries = new ListString(DatasourceLocation);
 foreach (string possibleQuery in possibleQueries)
 {
 if (possibleQuery.StartsWith(_query))
 ProcessQuery(possibleQuery);
 }

 }
 private bool QueryInDataSourceLocation()
 {
 return DatasourceLocation.Contains(_query);
 }

private void ProcessQuery(string query)
 {

 Item datasourceLocation = ResolveDatasourceRootFromQuery(query);
 if (datasourceLocation != null)
 DatasourceRoots.Add(datasourceLocation);
 }

private Item ResolveDatasourceRootFromQuery(string query)
 {
 string queryPath = query.Replace(_query, ContextItemPath);
 return ContentDataBase.SelectSingleItem(queryPath);
 }

private string DatasourceLocation { get; set; }
 private string ContextItemPath { get; set; }
 private Database ContentDataBase { get; set; }
 private List<Item> DatasourceRoots { get; set; }
 private const string _query = "query:.";

}

Categories: C#, Sitecore 6 Tags: ,