Now that you have now implemented Sitecore as your CX & CMS platform & are looking to implement best practices in your deployment. In this blog, we will discuss how you can add custom warnings which help standardize your workflow across users.
Here at Altudo, we work with clients across industry verticals to plan, strategize & implement Sitecore. We come across a myriad of use cases which we help visualize & implement.
Between one such routine project discussions - one of our clients expressed a need for an easier way to add versions to items on the website. While the editor is working on an item (though he can ‘lock and edit’ it) - what if for some reason he wants to preserve the older version and create a new one? We know that Sitecore provides the "Add Version" option in the menu under the "Version" tab, but the client wanted something more accessible in this case.
Knowing that Sitecore allows custom warnings to be managed in the content editor window, I proposed a solution to add a warning message with the button to enable the user to "Version Up, Lock and Edit" the item.
Now, it’s important to understand how Sitecore usually works around item edits.
• If an item is created, it will be stored as Version 1.
• An item can be updated from one workflow state to another during the workflow cycle.
• The version number remains the same during this move (in this case, 1).
• The item version is increased once the entire workflow cycle is completed and the item is published.
• This increase occurs when the content editor selects to “Lock and Edit” an item which is in the publish workflow state.
Ebook
Upgrade to Sitecore 9.1 Using this Handy Guide
What we tried to do differently here was to allow the user to add a new version of an item to the content editor warning via a new button. This was necessary so that he could easily create a new version of the item and preserve the old one in the previous version.
It was easy enough because Sitecore managed the Content Editor warnings in the web.config file as a separate pipeline, so I just had to add a custom pipeline processor to the getContentEditorWarnings pipeline.
I started creating a custom pipeline processor, the task was to create a custom message that suggested that the user could also create a new version of the item and edit it in the content editor, while allowing the user to click on the "Version Up, Lock and Edit" button for the item.
I have created a "ContentEditorVersionUpAndEditWarning" custom class. In this case, the logic initially exits the method if the user is an administrator or if the user has no permissions to edit the item.
Item obj = args.Item;
if (obj == null)
return;
if (Context.IsAdministrator)
{
if (!obj.Locking.IsLocked() || string.Compare(obj.Locking.GetOwner(),
Context.User.Name, StringComparison.InvariantCultureIgnoreCase) == 0)
return;
}
else if (obj.Locking.IsLocked())
{
if (obj.Locking.HasLock())
return;
}
Since all validations are met, the logic creates a new warning object for the content editor and initializes its fields "Title" and "AddOption" with the text value of the message and the command reference.
GetContentEditorWarningsArgs.ContentEditorWarning
contentEditorWarning = args.Add();
contentEditorWarning.Title = Translate.Text("You can version up,
lock and edit this item as well.");
contentEditorWarning.AddOption(Translate.Text("Version Up, Lock and Edit"),
"customitemedit:versionup");
The class's final code looks like this.
namespace Sitecore.Customizations
{
public class ContentEditorVersionUpAndEditWarning
{
public void Process(GetContentEditorWarningsArgs args)
{
Item obj = args.Item;
if (obj == null)
return;
if (Context.IsAdministrator)
{
if (!obj.Locking.IsLocked() || string.Compare(obj.Locking.GetOwner(),
Context.User.Name, StringComparison.InvariantCultureIgnoreCase) == 0)
return;
}
else if (obj.Locking.IsLocked())
{
if (obj.Locking.HasLock())
return;
}
else
{
if (!Sitecore.Configuration.Settings.RequireLockBeforeEditing
|| !Sitecore.Data.Managers.TemplateManager.IsFieldPartOfTemplate(FieldIDs.Lock, obj))
return;
GetContentEditorWarningsArgs.ContentEditorWarning
contentEditorWarning = args.Add();
contentEditorWarning.Title = Translate.Text("You can version up,
lock and edit this item as well.");
contentEditorWarning.AddOption(Translate.Text("Version Up, Lock and Edit"),
"customitemedit:versionup");
}
}
}
}
Now we create the command that will be called when you click on the warning message button.
The need here is that the item should be "checked out" and made available to the user in the edit mode when the button in the warning message is clicked.
Simply create "VersionUpLockEdit" a new custom command class. Create this class by inheriting the class "ContentEditor. Edit" to create an edit command in the content editor interface.
Add a method "Execute," which will be called when the command is invoked.
public override void Execute(Sitecore.Shell.Framework.Commands.CommandContext context)
{
...
...
}
If the command is invoked by a valid item, the execute method validates if not the program execution exits the method. If the item is already in a "checked out" state, the method also validates if it is then the logic checks in the item.
if (context.Items.Length != 1)
return;
if (Sitecore.Shell.Framework.Commands.ContentEditor.Edit.CanCheckIn(context.Items[0]))
Context.ClientPage.SendMessage((object)this, "item:checkin");
....
If the item is valid for locking and editing version up, the logic creates a collection of arguments for name - value and invokes the "Run" method.
Item obj = context.Items[0];
NameValueCollection parameters = new NameValueCollection();
parameters["id"] = obj.ID.ToString();
parameters["language"] = obj.Language.ToString();
parameters["version"] = obj.Version.ToString();
Context.ClientPage.Start((object)this, "Run", parameters);
The final “Execute” method looks like this,
public override void Execute(Sitecore.Shell.Framework.Commands.CommandContext context)
{
Assert.ArgumentNotNull((object)context, "context");
if (context.Items.Length != 1)
return;
if (Sitecore.Shell.Framework.Commands.ContentEditor.Edit.CanCheckIn(context.Items[0]))
Context.ClientPage.SendMessage((object)this, "item:checkin");
else
{
// If Unlocking the item then
Item obj = context.Items[0];
NameValueCollection parameters = new NameValueCollection();
parameters["id"] = obj.ID.ToString();
parameters["language"] = obj.Language.ToString();
parameters["version"] = obj.Version.ToString();
Context.ClientPage.Start((object)this, "Run", parameters);
}
}
The item is validated in the Run method for its state, whether it is already in a lock state or if the user has permissions to edit the item. Among other things, the logic also validates the actual existence of the item.
Assert.ArgumentNotNull((object)args, "args");
Item obj1 = Context.ContentDatabase.Items[args.Parameters["id"],
Language.Parse(args.Parameters["language"]),
Sitecore.Data.Version.Parse(args.Parameters["version"])];
if (!Context.IsAdministrator && (!obj1.Access.CanWrite() ||
!obj1.Locking.CanLock() && !obj1.Locking.HasLock()))
return;
if (obj1 == null)
{
SheerResponse.Alert("Item not found.", new string[0]);
}
The logic first creates a new version of the item once it has been validated and once a new version has been added, it calls the command "item: versionadded."
// Add item version
Sitecore.Data.Version[] versionNumbers = obj1.Versions.GetVersionNumbers(false);
Log.Audit((object)this, "Add version: {0}", new string[1] { AuditFormatter.FormatItem(obj1) });
Item obj2 = obj1.Versions.AddVersion();
if (versionNumbers == null || versionNumbers.Length <= 0)
return;
Context.ClientPage.SendMessage((object)this,
"item:versionadded(id=" + obj2.ID.ToString() + ",version=" + obj2.Version.ToString() +
",language=" + obj2.Language.ToString() + ")");
Once the new version version version version process has been completed, the logic validates whether the user is an administrator, if not, it calls the "item: startediting" command to unlock the edit item. The command passes the item id and version details as arguments.
// Check out the item
if (Context.User.IsAdministrator)
obj2.Locking.Lock();
else
obj2 = Context.Workflow.StartEditing(obj2);
Context.ClientPage.SendMessage((object)this,
"item:startediting(id=" + obj2.ID.ToString() + ",version=" + obj2.Version.ToString() +
",language=" + obj2.Language.ToString() + ")");
The “Run” method looks like this,
protected void Run(ClientPipelineArgs args)
{
Assert.ArgumentNotNull((object)args, "args");
Item obj1 = Context.ContentDatabase.Items[args.Parameters["id"],
Language.Parse(args.Parameters["language"]),
Sitecore.Data.Version.Parse(args.Parameters["version"])];
if (!Context.IsAdministrator && (!obj1.Access.CanWrite() ||
!obj1.Locking.CanLock() && !obj1.Locking.HasLock()))
return;
if (obj1 == null)
{
SheerResponse.Alert("Item not found.", new string[0]);
}
else
{
if (!SheerResponse.CheckModified())
return;
// Add item version
Sitecore.Data.Version[] versionNumbers = obj1.Versions.GetVersionNumbers(false);
Log.Audit((object)this, "Add version: {0}", new string[1] { AuditFormatter.FormatItem(obj1) });
Item obj2 = obj1.Versions.AddVersion();
if (versionNumbers == null || versionNumbers.Length <= 0)
return;
Context.ClientPage.SendMessage((object)this,
"item:versionadded(id=" + obj2.ID.ToString() + ",version=" + obj2.Version.ToString() +
",language=" + obj2.Language.ToString() + ")");
// Check out the item
if (Context.User.IsAdministrator)
obj2.Locking.Lock();
else
obj2 = Context.Workflow.StartEditing(obj2);
Context.ClientPage.SendMessage((object)this,
"item:startediting(id=" + obj2.ID.ToString() + ",version=" + obj2.Version.ToString() +
",language=" + obj2.Language.ToString() + ")");
}
}
Finally, we must create a patch configuration file with the custom pipeline processor and the custom command. In the \App Config\Include folder, we save the file "ContentEditorVersionUpAndEditWarning.config." This patch of configuration files is automatically included in the runtime configuration settings.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:x="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<getContentEditorWarnings>
<processor patch:after="*[type='Sitecore.Pipelines.GetContentEditorWarnings.IsLocked, Sitecore.Kernel']" mode="on"
type="Sitecore.Customizations.ContentEditorVersionUpAndEditWarning, Sitecore.Customizations" />
<processor />
</getContentEditorWarnings>
</pipelines>
<commands>
<command name="customitemedit:versionup" type="Sitecore.Customizations.VersionUpLockEdit, Sitecore.Customizations" />
</commands>
</sitecore>
</configuration>
Here you have it! Your message / command custom warning is ready to use.
You can also create custom warnings in the content editor window using this example. The utility can range from the latest updates to the edited item or the details of the workflow status of an item, or may inform the user of the last updated fields; the use is endless. So, I will leave that to you and your best needs.
Looking for more Tips, Tricks & How-Tos on how to leverage your Sitecore instance?
Do write to us: marketing@altudo.co
We at Altudo are a Sitecore Platinum Implementation Partner & deliver a Sitecore project almost every 2 weeks and with a run rate of more than 15 every year. Read more about our capabilities, here.