Wednesday 31 July 2019

How to Create Custom Standard Values Tokens



Out of the box, Sitecore comes with the following expand standard values tokens:

$name – Name of the item
$date – Current server date
$time – Current server time
$now – Current server date time
$id – Item ID
$parentid – Item’s Parent ID
$parentname – Item’s Parent Name

Sometimes the already existing tokens are not enough. There are cases in which the Content Editors won`t be able to access the value that needs to be populated (ex. – web service call) or it will be hard for them to do it (ex. – the value of the item varies on many other items). In the current example, the $next token will be implemented. It will automatically replace the token with the current siblings' count plus one  – this token is usually used in cases where there is a requirement for the auto-incrementing sort order of items.

Implementing a custom token is fairly simple and can be achieved in 2 easy steps.

Step 1 – Creating a custom ExpandInitialFieldValueProcessor

Create a custom ExpandInitialFieldValueProcessor with the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Sitecore.Pipelines.ExpandInitialFieldValue;

namespace SitecoreMaster82.Models.CustomToken
{
    public class TokenNextProcessor : ExpandInitialFieldValueProcessor
    {
        public override void Process(ExpandInitialFieldValueArgs args)
        {
            if (args.SourceField.Value.Contains("$next"))
            {
                if (args.TargetItem != null && args.TargetItem.Parent != null && args.TargetItem.Children != null)
                {
                    args.Result = args.Result.Replace("$next", args.TargetItem.Parent.Children.Count.ToString());
                }
                else
                {
                    args.Result = args.Result.Replace("$next", "0");
                }
            }
        }
    }
}

The code is pretty straightforward. It checks if the value of the field contains the $next token. If it does it checks if the parent is not null and the parent has children. If the parent is not null and there are children the value is set to the children`s count (the processor is executed after the child is added to the index will be 1 based), otherwise it sets the value to 0.

Step 2 – Creating the custom configuration

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <expandInitialFieldValue>
        <processor type="SitecoreMaster82.Models.CustomToken.TokenNextProcessor , SitecoreMaster82"
       patch:after="processor[@type='type=Sitecore.Pipelines.ExpandInitialFieldValue.ReplaceVariables, Sitecore.Kernel']" />
      </expandInitialFieldValue>
    </pipelines>
  </sitecore>
</configuration>

And here is an example of how it works.









Wednesday 3 July 2019

Navigate to Content Tree, Items Search by ID and Path




Navigate to the Item, Search by Path and Item ID



Lack of a fast way to paste a Sitecore item path into the UI and have the Content Editor change selection to that item. I suggested using the search box or the Navigate button, but apparently, they weren’t right. The person wanted to paste a link and have the content tree change without any other clicking about.



The problem can be solved with a simple Command:


using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Web.UI.Sheer;

namespace SitecoreMaster.Models
{
    public class NavigateCommand: Command
    {
        public override void Execute(CommandContext context)
        {
            ClientPipelineArgs args = new ClientPipelineArgs();
            args.CustomData.Add("db", context.Items[0].Database.Name);

            Context.ClientPage.Start(this, "Run", args);
        }

        protected void Run(ClientPipelineArgs args)
        {
            if (!args.IsPostBack)
            {
                SheerResponse.Input("Enter a path or id: ", string.Empty);
                args.WaitForPostBack();
            }
            else
            {
                if (args.HasResult)
                {
                    string dbName = (string)args.CustomData["db"];
                    Database db = Sitecore.Configuration.Factory.GetDatabase(dbName);
                    Item itm = db.GetItem(args.Result);

                    if (itm != null)
                    {
                        Context.ClientPage.SendMessage(this, string.Format("item:load(id={0})", itm.ID.ToString()));
                    }
                    else
                    {
                        SheerResponse.ShowError("Item not found", string.Format("The item '{0}' was not found.", args.Result));
                    }
                }
            }
        }
    }

}


When the command is triggered by clicking a button, the code records the database that the context item was found in. (That’s whatever item was selected in the content tree when the user clicked the button triggering our command) The “context” database for commands is always Core, so we need this information because the user might actually be looking at Master or Web when they click the button. This is then passed into the Run() method.


The first time Run() is triggered no postback has occurred, so we need to ask the user to enter the path or ID of the item to select, and we need to wait for that data. The SheerResponse.Input() method shows a simple dialog with a text entry field. If you were feeling fancy you could create a custom dialog using Sheer here, but this basic dialog will do for our needs.


The second time Run() is triggered the postback from the input dialog should have occurred. If it has, and if the postback has provided us with some data, then we can try and make the Content Tree change focus. To do that we want to load the item to verify it exists. That means extracting the database name from the arguments passed in, fetching a reference to the database and then trying to load the item.




If we get an item back from the database, we can use the SendMessage() method to trigger the “load an item” behaviour. This will cause the Content Editor to load the item specified, refresh the content tree so it has focus, and refresh the editor pane to show the appropriate data. And if we get no item back we can show an error using the ShowError()method



To enable the user to trigger our command we need to wire it up using the same old techniques we’ve used for commands in the past. First, you have to map the class above to a command string by adding an entry to the Commands.config file with a patch



<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <commands>
      <command name="ContentTreenavigate:navigate" type="SitecoreMaster.Models.NavigateCommand,SitecoreMaster" />
    </commands>
  </sitecore>
</configuration>

(Obviously, you need your namespace and dll name in the type attribute above…


Then you need to create a button in the UI to trigger this command. For example, to add it to the “Go to” chunk of the Developer ribbon tab, you can add a new item at /sitecore/content/Applications/Content Editor/Ribbons/Chunks/Goto in the Core database. Using the /sitecore/templates/System/Ribbon/Small Button template add something like:





Choose a suitable icon, fill in the click event with the command name defined above, and give it whatever name you fancy.


So to test it, switch back to Master and click your new button:

If you enter the path "/sitecore/content/Website/Command Template Item/2019/6/New NewsItem"  and click ok, the content tree will change:







If you enter the Item ID "{8E080626-DDC3-4EF4-A1D1-F0BE4A200254}" and click ok, the content tree will change:







Conclusion
Finally, I would like to conclude this post, I hope I have been able to help you and justify the topic.



Tuesday 2 July 2019

Example of Sitecore Command Template With User Interface





Command Template: allow insert of items according to logic rather than predefined structures.


The command template defines a class and method to be called during an insert operation. Unlike data templates and branch templates, which consist of predefined structures, command templates reference Sitecore UI commands to invoke wizards or other logic used to create new items.


Step 1: Writing our Command
Create our Command Class in your solution and inherit Command Class. Command Class is available in Sitecore.Shell.Framework.Commands namespace in Sitecore.Kernel.dll

using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Globalization;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Web.UI.Sheer;
using System;
using System.Collections.Specialized;

namespace SitecoreMaster82.Models.CommandTemplate
{
    public class CustomCommandTemplate : Command
    {
        public override void Execute(CommandContext context)
        {
            if (context.Items.Length == 1)
            {
                Item item = context.Items[0];
                NameValueCollection parameters = new NameValueCollection();
                parameters["id"] = item.ID.ToString();
                parameters["language"] = item.Language.ToString();
                parameters["database"] = item.Database.Name;
                Context.ClientPage.Start(this, "Run", parameters);
            }
        }

        protected void Run(ClientPipelineArgs args)
        {
            if (!args.IsPostBack)
            {
                //Means we are in the initial step, we want to ask for the name of the news
                Context.ClientPage.ClientResponse.Input("Enter the name of the news item:", Translate.Text("New NewsItem"), Sitecore.Configuration.Settings.ItemNameValidation, "'$Input' is not a valid name.", 100);
                args.WaitForPostBack();
            }
            else
            {
                //Now we got a postback, which means we got a response
                if (!String.IsNullOrEmpty(args.Result) && args.Result != "undefined")
{
                    Database db = Sitecore.Configuration.Factory.GetDatabase(args.Parameters["database"]);
                    Item parent = db.GetItem(args.Parameters["id"], Language.Parse(args.Parameters["language"]));
                    //Create the folder structure if it doesn't exist
                    string year = DateTime.Now.Year.ToString();
                    string month = DateTime.Now.Month.ToString();
                    TemplateItem folderTemplate = db.Templates[TemplateIDs.Folder];
                    Item yearFolder = parent.Children[year];
                    if (yearFolder == null)
                        yearFolder = parent.Add(year, folderTemplate);
                    Item monthFolder = yearFolder.Children[month];
                    if (monthFolder == null)
                        monthFolder = yearFolder.Add(month, folderTemplate);
                    //Create the news Item
                    TemplateItem template = Context.ContentDatabase.Templates[new ID("{5401DFB9-D884-418A-8EB2-1CCC3931F6EE}")]; //This GUID is of data templates based on you want to create item /sitecore/templates/User Defined/News 
                    Item item = monthFolder.Add(args.Result, template);
                    //Load the Item in the content editor
                    Context.ClientPage.SendMessage(this, "item:load(id=" + item.ID.ToString() + ")");
                }
            }
        }
    }
}

Step 2: Add Command in your Commands.config file
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <commands>
      <command name="CommandTemplate:TestCommandTemplate" type="SitecoreMaster82.Models.CommandTemplate.CustomCommandTemplate,SitecoreMaster82" />
    </commands>
  </sitecore>
</configuration>
Step 3: Add Command Template Item
  • Right Click on Branches and select Command Template
  • Give our Command Template a proper Name




    • Now add command Name to our Command Template
    • Keep in mind that Command_Name would be the same name used in a command.config file
    • That’s it our Command Template is ready to use, we just need to add it in Insert Options and its done. Whenever we will add new Items using this Command Template it will automatically create our Item with proper folder structure. 


Conclusion
Finally, I would like to conclude this post, I hope I have been able to help you and justify the topic.


Sitecore Publishing Service 7.0 Installation Guide

  About the Publishing Service module The Publishing Service module is an optional replacement for the existing Sitecore publishing methods....