Extending Sitecore Rocks – Creating a ContentTreeCommand and Server Component

Sitecore Rocks is completely extensible, much like Sitecore itself.  In this example I’ll be extending it to support cloning with a Sitecore Rocks Server Component and a Sitecore Explorer Command Plug-in.

The Server Component

•Server Components sit in the bin folder of the websites.
•The Hard Rocks Webservice is used for processing custom plugins.
•All assemblies must begin with Sitecore.Rocks.Server
•The class’s namespace must begin with Sitecore.Rocks.Server.Requests
•The class must have an Execute method that returns a string
•The Execute method may contain any number of string parameters

1. Create a new Sitecore Rocks Server Component Project named  Sitecore.Rocks.Server.Cloning

2. Rename the HandleRequest class to Clone in the Requests folder

3. Change the Namespace to Sitecore.Rocks.Server.Requests.Cloning

4. Use the following commented code

using System.IO;
using System.Xml;
using Sitecore.Data;
using Sitecore.Data.Items;
using System;
using Sitecore.Configuration;
namespace Sitecore.Rocks.Server.Requests.Cloning
    public class Clone
        public string Execute(string databaseName, string sourceItemId, string targetItemId, string databaseUri)
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
                //clone the item
                Database database = Factory.GetDatabase(databaseName);
                Item item = database.SelectSingleItem(sourceItemId);
                Item destination = database.SelectSingleItem(targetItemId);
                Item item2 = item.CloneTo(destination);
                //write out the database uri
                //write out the new item id
            catch (Exception ex)
                //write out an error if we have one and Rocks will throw the error
                xmlTextWriter.WriteString("***ERROR*** " + ex.Message);
            return stringWriter.ToString();

5. Compile and place the assembly in the bin of your website.

Creating the Rocks Plug-in

When Rocks loads it scans the C:\Users\{user}\AppData\Local\Sitecore\Sitecore.Rocks\Plugins folder for assemblies and loads types that are marked with certain attributes[Command],[Pipeline],[FieldControl] etc…

In the code below will be doing the following :
  • Modify the constructor to set the name, group and sort order.
  • Modify the CanExecute Method to make sure only one item is selected.
  • Modify the Execute Method to Show a Dialog that allows the user to select where to place the clone and then call the Server Method.
  • Add an ExecuteCompleted  method to handle the return call from the server and refresh the screen.
  • Add a method to handle the XML Parsing.
1. Create a new Sitecore Rocks Plug-in Project and name it Sitecore.Rocks.Plugins.Cloning
2. Rename the Command to Clone
3. Replace the code with the following commented code
namespace Sitecore.Rocks.Symposium.Commands
    using Sitecore.VisualStudio.Commands;
    using Sitecore.VisualStudio.ContentTrees;
    using System.Linq;
    using Sitecore.VisualStudio.Data;
    using Sitecore.VisualStudio.UI.SelectItem;
    using Sitecore.VisualStudio.Extensions.IItemSelectionContextExtensions;
    using Sitecore.VisualStudio.Data.DataServices;
    using System.Xml;
    using System;
    using System.Windows;

    public class Clone : CommandBase
        public Clone()
            this.Text = "Clone";
            this.Group = "Edit";
            this.SortingValue = 2300;
        public override bool CanExecute(object parameter)
            //this method enables or disables the menu option
            var context = parameter as ContentTreeContext;
            if (context == null || context.SelectedItems == null || context.SelectedItems.Count() != 1)
                return false;
            return true;

        public override void Execute(object parameter)
            //this method executes when the button is pushed
            var context = parameter as ContentTreeContext;
            if (context == null || context.SelectedItems == null || context.SelectedItems.Count() != 1)

            //get the selected item
            IItem selectedItem = context.SelectedItems.FirstOrDefault() as IItem;

            if (selectedItem != null)
                // get the root "sitecore/content" item for our select item dialog.
                var contentItemId = IdManager.GetItemId("/sitecore/content");
                var contentItemUri = new ItemUri(selectedItem.ItemUri.DatabaseUri, contentItemId);

                //Show a popup to select a target
                SelectItemDialog dialog = new SelectItemDialog();
                dialog.Initialize("Select Target Item", contentItemUri);

                if (dialog.ShowDialog() == true)
                    //item is selected to clone to , send the command to the server
                    var targetItem = dialog.SelectedItem;
                    if (targetItem != null)
                        context.GetSite().DataService.ExecuteAsync("Sitecore.Rocks.Server.Requests.Cloning.Clone,Sitecore.Rocks.Server.Cloning", //The class to exectue on the server
                            completed, // the completed event
                            selectedItem.ItemUri.DatabaseName.Name,  //the database name for sitecore
                            selectedItem.ItemUri.ItemId.ToString(), //the source items id
                            targetItem.ItemId.ToString(), // the target items id
                            selectedItem.ItemUri.DatabaseUri.ToString() // the database uri to return to server


        ExecuteCompleted completed = delegate(string response, ExecuteResult result)
            //this method is fired after the item is created on the server
            if (!DataService.HandleExecute(response, result))
            //get the active content tree
            ContentTree activeContentTree = Sitecore.VisualStudio.UI.ActiveContext.ActiveContentTree;
            if (activeContentTree != null)
                // get the return values from the xml that was returned
                string database = GetResultValue(response, "//database");
                string item = GetResultValue(response, "//item");

                //get the databaseUri in the rocks format
                DatabaseUri dbUri;
                DatabaseUri.TryParse(database, out dbUri);
                //get the itemUri in rocks format
                ItemId itemId = new ItemId(new Guid(item));
                ItemUri itemUri = new ItemUri(dbUri, itemId);
                if (itemUri != null)
                    //send the user to our newly created content

        //parse xmlvalue
        public static string GetResultValue(string xml, string xPath)
            XmlDocument xmlDocument = new XmlDocument();
            XmlNode xmlNode = xmlDocument.SelectSingleNode("//result" + xPath);
            return xmlNode.InnerText;

4. Compile the Project.
5. Open up a new instance of visual studio and you should see your new ‘clone’ command when you browse to an item.

About Kevin Buckley
.Net web developer with a lot of experience in CMS. Currently working at Sitecore as Solutions Engineer.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: