During a routine project discussion, the client expressed a need for an easier way to add versions to items on the website. While the editor works on an item (although he gets to “Lock and Edit” it), what if he wants to preserve the older version for some reason and move on to create a new one. We know that Sitecore provides the “Add Version” option under the “Version” tab in the menu, but in this case the client wanted something more accessible.
Knowing that Sitecore allows managing custom warnings in the content editor window; I proposed a solution that we add a warning message along with the button to allow the user to “Version Up, Lock and Edit” the item.

Now, it is important to understand how Sitecore normally works around item edits.
- When an item is created, it gets stored as Version 1.
- While in the workflow cycle, an item can be updated moving from one workflow state to another.
- During this move, the version number remains the same (in this case, 1).
- Once the entire workflow cycle is complete and the item is published, the item version gets incremented.
- This increment happens when the content editor selects to “Lock and Edit” an item which is in the publish workflow state.
What we were attempting to do different here was to allow the user to add a new version of an item via a new button in the content editor warning. This was required so that he had easy access to creating a new version of the item and preserving the old one in the previous version.
Going about it was simple enough as Sitecore managed the Content Editor warnings as a separate pipeline in the web.config file, so all I had to do was to add a custom pipeline processor in the getContentEditorWarnings pipeline.
I started with creating a custom pipeline processor, the task was to create a custom message that suggested that the user can also create a new version of the item and edit it in the content editor, while allowing the user to click a button that lets them “Version Up, Lock and Edit” the item.
I created a custom class “ContentEditorVersionUpAndEditWarning”. Here, initially the logic exits the method in case of the user being an administrator or if the user does not have edit permissions to 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;
}
As all validations are met, the logic creates a new content editor warning object and initializes its “Title” and “AddOption” fields with the message text value and the command reference respectively.
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 final code for the class 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 move on to create the command that will be called when the warning message button is clicked.
The need here is that when the button in the warning message is clicked, the item should be “checked out” and made available in the edit mode to the user.
Simply create a new custom command class, “VersionUpLockEdit”. Create this class by inheriting the “ContentEditor.Edit” class, this will allow you to create an edit command in the content editor interface.
Add an “Execute” method, this is the method that will be called when the command is invoked.
public override void Execute(Sitecore.Shell.Framework.Commands.CommandContext context)
{
...
...
}
The execute method validates if the command is invoked by a valid item, if not then the program execution exits the method. The method also validates if the item is already in a “checked out” state, 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 version up lock and edit process then the logic creates a name-value collection of arguments 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);
}
}
In the Run method, the item is validated for its state, whether it is already in lock state or if the user has permissions to edit the item. Among other things the logic also validates if the item actually exists.
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]);
}
Once validated, the logic first creates a new version of the item and once a new version has been added, it calls the “item:versionadded” command.
// 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 process is complete, the logic validates if the user is an administrator, if not it proceeds to unlock the item for editing by calling the “item:startediting” command. 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 finished “Run” method looks something 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() + ")");
}
}
Lastly, we need to create a patch config file, where we will include the custom pipeline processor and the custom command. For this, we save the file, “ContentEditorVersionUpAndEditWarning.config”, in the \App Config\Include folder. This config file patch is automatically included in the configuration settings at runtime.
<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>
There you have it folks! Your custom warning message/command is ready to use.

Using this example, you can further create custom warnings in the content editor window. The utility can range from latest updates on the item being edited or workflow status details on an item, or perhaps inform the user which fields were last updated; the usage is endless. So, I will leave that to you and your best needs.