How to create a custom wizard in Sitecore

Posted by

We are going to create a custom Sitecore Wizard that can be opened in the right-click context menu. You can use a custom Sitecore wizard for many things:

  1. Run a custom maintenance script.
  2. Export data.
  3. Simplify item creation.

In this post, we are going to create a custom wizard to simplify item creation.

Here is a screenshot of the finished wizard:

Image

For simplicity’s sake, we are going to create items of an “Article” template, of which has two fields “ArticleTitle” and “ArticleDate”.

Sitecore Article item preview

The wizard will validate the user input and concatenate the two fields to make the item name (e.g. “2014-04-28-my first post”), and  obviously auto-populate the corresponding fields on the item itself.

Note: All the code is at the bottom of the post – I couldn’t figure out how to make wordpress play nice with inline code (I can’t wait to launch my own site).

Step 1: Code & Configuration

(note: all code is included below)

  • Add a new folder to your solution: /sitecore/custom wizards/ArticleWizard
  • Add a new XML file in this folder: “NewArticleWizard.xml“. This XML will define the UI for our custom wizard.
  • Add a new class to this folder: “NewArticleWizardForm.cs“. This is a “code-beside” file, that we use to write code against our custom wizard UI (event handlers, business logic)
  • And finally create the file: “NewArticleOpenWizardCommand.cs“. This class is a custom sitecore command that helps launch the actual wizard in the content editor.
  • Add “NewArticleWizard.config” patch file to the /App_Config/Include Folder

Step 2: Sitecore Configuration

Now Let’s add the ability to launch the wizard to the right click context menu.

Custom Sitecore context Menu

  • As an administrator, open up Sitecore desktop, select the Core database, and launch the content editor.
  • Expand folder: /Sitecore/content/Applications/Content Editor/Context Menus/Default
  • In the default folder, Insert a New Item:
    • Template: /System/Menus/Menu item
    • ItemName: NewArticleWizard
  • Set the following fields:
    • Display Name: New Article Wizard …
    • Icon: Business/32×32/note_new.png
    • Message: item:articlewizard(id=$Target)
    • Note how the item:articlewizard part of the message field matches the command name in NewArticleWizard.config.
  • Save
  • Switch back to the master database, and your menu item should already be there!

Code Notes:

All code is in my web project, assembly name = “TdsCodeGen.Web”

NewArticleWizard.xml

  • This defines the UI for the wizard, and consists of 3 pages: intro, form input, confirmation

"Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense">
  
    "SitecoreWizardDemo.UI.Wizards.NewArticleWizard.NewArticleWizardForm,TdsCodeGen.Web">

      "FirstPage" Icon="Applications/48x48/magic-wand.png">
        "scWizardWelcomeTitle">
          "NewBlogArticleWizard"/>
        
        "This wizard will create a new article."/>
      

      "WizardPageOne" Header="Page 1" Text="Enter the title and date of the article" Icon="Applications/48x48/magic-wand.png">

        
          "FieldsAction" Columns="2" Width="100%" CellPadding="2">
            
            "Article Title:" GridPanel.NoWrap="true" Width="90%" />
            "ArticleTitle" Width="100%" Change="OnArticleTitleChanged" GridPanel.Width="100%"/>
            
            "Article Date:" GridPanel.NoWrap="true" Width="100%" />
            "ArticleDate" Width="30%" Change="OnArticleDateChanged" GridPanel.Width="100%"/>
          

        
      


      "LastPage" Icon="People/48x48/user1.png">
        
          "The wizard has completed - the new article item has been created."/>
        
      

    
  

NewArticleWizardForm.cs

  • This is the code-beside file that has event handlers & business logic for NewArticleWizard.xml
using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.SecurityModel;
using System;

namespace SitecoreWizardDemo.UI.Wizards.NewArticleWizard
{
    public class NewArticleWizardForm : Sitecore.Web.UI.Pages.WizardForm
    {
        // Sitecore auto mapps these properties to their corresponding elements in the xml file.

        // 
        protected Sitecore.Web.UI.HtmlControls.Edit ArticleTitle;

        // 
        protected Sitecore.Web.UI.HtmlControls.DatePicker ArticleDate;

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (!Context.ClientPage.IsEvent)
            {
            }
        }

        #region infrastructure

        ///

        /// Create the new article item in sitecore
        ///

 

        private Item CreateNewArticle()
        {
            const string articleTemplateId = "{57074230-A2B4-4D8F-AC10-6F9F41845E46}";
            const string articlesParentFolderId = "{7878953E-A6E9-4E57-AA8A-B459B7A2D608}";

            using (new SecurityDisabler())
            {
                Database masterDb = Sitecore.Configuration.Factory.GetDatabase("master");
                Item articleFolderItem = masterDb.GetItem(new ID(articlesParentFolderId));
                TemplateItem articleTemplate = masterDb.GetTemplate(new ID(articleTemplateId));

                string articleName = BuildArticleItemName(this.ArticleTitle.Value, DateUtil.IsoDateToDateTime(this.ArticleDate.Value));

                // Create the new item in Sitecore.
                Item newArticleItem = articleFolderItem.Add(articleName, articleTemplate);

                // Update our item's properties with the values from the wizard.
                newArticleItem.Editing.BeginEdit();

                try
                {
                    newArticleItem.Fields["ArticleTitle"].Value = this.ArticleTitle.Value;
                    newArticleItem.Fields["ArticleDate"].Value = this.ArticleDate.Value;
                }
                finally
                {
                    newArticleItem.Editing.EndEdit();
                }

                return newArticleItem;
            }
        }

        ///

        /// Builds an article item name.
        ///

 

        private static string BuildArticleItemName(string articleTitle, DateTime articleDate)
        {
            // Remove duplicate spaces from article title.
            while (articleTitle.Contains("  "))
            {
                articleTitle = articleTitle.Replace("  ", " ");
            }

            articleTitle = articleTitle.Trim();

            return string.Format("{0:yyyy-MM-dd}-{1}", articleDate, articleTitle);
        }

        ///

        /// Determines if the article name is valid.
        ///

 

        private bool IsArticleNameValid
        {
            get
            {
                return this.ArticleTitle != null && !string.IsNullOrWhiteSpace(this.ArticleTitle.Value);
            }
        }

        ///

        /// Determines if the article date is valid.
        ///

 

        private bool IsArticleDateValid
        {
            get
            {
                if (this.ArticleDate != null && this.ArticleDate.Value != null)
                {
                    DateTime dt = Sitecore.DateUtil.IsoDateToDateTime(this.ArticleDate.Value, DateTime.MinValue);

                    if (dt.Date != DateTime.MinValue)
                    {
                        return true;
                    }
                }

                return false;
            }
        }

        #endregion

        #region UI custom event handlers

        ///

        /// Event handler that gets called when the 'ArticleTitle' input control loses focus (i.e. on blur).
        ///

 

        protected void OnArticleTitleChanged()
        {
            base.NextButton.Disabled = !(this.IsArticleNameValid && this.IsArticleDateValid);
        }

        ///

        /// Event handler that gets called when the 'ArticleDate' input control loses focus (i.e. on blur).
        ///

 

        protected void OnArticleDateChanged()
        {
            base.NextButton.Disabled = !(this.IsArticleNameValid && this.IsArticleDateValid);
        }

        #endregion

        #region Wizard event handlers

        ///

        /// Method that runs when the wirzard page/step changes.
        ///

 

        protected override bool ActivePageChanging(string page, ref string nextPage)
        {
            if (nextPage == "LastPage")
            {
                if (this.IsArticleDateValid && this.IsArticleNameValid)
                {
                    // disable back button since we are about to go to final page.
                    base.BackButton.Disabled = true;

                    // create the article
                    Item newArticleItem = CreateNewArticle();

                    return base.ActivePageChanging(page, ref nextPage);
                }
            }

            return base.ActivePageChanging(page, ref page);
        }

        ///

        /// "event handler" that runs after the wizard page/step changes.
        ///

 

        protected override void ActivePageChanged(string page, string oldPage)
        {
            base.ActivePageChanged(page, oldPage);

            if (page == "WizardPageOne")
            {
                // set default statue values for our input fields.
                this.ArticleTitle.Value = string.Empty;
                this.ArticleDate.Value = Sitecore.DateUtil.ToIsoDate(DateTime.Now);

                this.NextButton.Disabled = true;
            }
            else if (page == "LastPage")
            {
                // only allow the user to close the wizard on the last page.
                this.NextButton.Disabled = true;
                this.BackButton.Disabled = true;
            }
        }

        

        #endregion
    }
}

NewArticleOpenWizardCommand.cs

  • This code actually opens the wizard in the content editor.
  • Note the LOC:
    string controlUrl = Sitecore.UIUtil.GetUri(“control:NewArticleWizard“);
    Important: Ensure that “control:NewArticleWizard” matches the XML node name in the XAML file (step 1).
using Sitecore.Shell.Framework.Commands;
using Sitecore;

namespace SitecoreWizardDemo.UI.Wizards.NewArticleWizard
{
    public class NewArticleOpenWizardCommand : Command
    {
        public override void Execute(CommandContext context)
        {
            // get the uri of our wizard by finding the control using Sitecore's UIUtil
            string controlUrl = Sitecore.UIUtil.GetUri("control:NewArticleWizard");

            // broadcast the need to show the wizard to the sitecore shell
            Context.ClientPage.ClientResponse.Broadcast(Context.ClientPage.ClientResponse.ShowModalDialog(controlUrl), "Shell");
        }

        public override CommandState QueryState(CommandContext context)
        {
            return base.QueryState(context);
        }

        protected void Run(Sitecore.Web.UI.Sheer.ClientPipelineArgs args)
        {
        }
    }
}

NewArticleWizard.config

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <commands>
      <command name="item:articlewizard" type="SitecoreWizardDemo.UI.Wizards.NewArticleWizard.NewArticleOpenWizardCommand, TdsCodeGen.Web" />
    commands>
    <controlSources>
      <source mode="on" namespace="SitecoreWizardDemo.UI.Wizards.NewArticleWizard" folder="/sitecore/custom wizards/ArticleWizard" deep="true" />
    controlSources>
  sitecore>
configuration>

Conclusion

Thats it! The wizard should launch. If it doesn’t, verify that your class names match the config files. To make this post useful in a practical sense, you could easily add code to automatically organize posts into folders, such as /year/month/day/article – but I will leave that as an exercise to the reader.

Thank you for reading my first post! There will be many more to come. Cheers!

References

http://usoniandream.blogspot.com/2007/02/tutorial-create-your-own-sitecore.html

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