This is a two part post on taking on a strategy to make like easier for content editors by making it easy for them use page editor. In Part 1 of this topic, we saw how some help instructions for content editors laid out in various sections of the page can help make their lives easier. The idea is, of course, to make it as easy as possible to edit content and have content updating be a smooth process. Our clients so far are very happy with this approach, so we thought we would share. In this post we’ll get into the code that helps us do this.
- Part 1 – Easier Page Editor Adoption for Content Editors – How it works for the Content Editors
- Part 2 – Easier Page Editor Adoption for Content Editors – The Code Guts.
Note: This was done in an older project that was done with webforms, so you’ll need to update this for use in MVC projects. People far smarter than me will have probably figured out much cooler ways to do this, and I’m all ears – leave me a note/comment!
The Templates and Items Setup
As outlined in the Part of this post, there are three main steps where we need to show instructions. They are:
1. When a sublayout/module is placed on a page without a datasource via standard values.
2. Once the item is created, instruct how to add associated content (i.e. setting the datasource)
3. Once the associated content is set, how to enter module specific content.
So the very thing we do is create a template to assist in having content for this:


Notice the the three different fields correspond to the three steps where we need to show the content:
- Field No DataSource Help is for step #1
- Field No Data Help is for step #2
- Field Page Editor Instructions is for step #3
Note that these fields will show only when in page editor mode, as detected by the code in the control.
Once the template is setup, then we then need to create the items. We create an item for each of the sublayouts that we have and fill in the appropriate content. We name each help item same as the name of the sublayout, so it can be grabbed from code dynamically.

The Guts of the Control
Now that the template and the items are created, we can create the control that will display it all. The control would be a generic usercontrol, and not a sublayout. In the markup section, we need to add an area for each of the sections.
<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %> <asp:PlaceHolder runat="server" ID="mainHelperPlaceholder"> <asp:PlaceHolder runat="server" ID="noDataSourcePlaceholder"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scNoDataSourceHelpText" DisableWebEditing="True"/> </div> </asp:PlaceHolder> <asp:PlaceHolder runat="server" ID="noDataPlaceholder"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scNoDataHelpText" DisableWebEditing="True"/> </div> </asp:PlaceHolder> <asp:PlaceHolder runat="server" ID="noDataPlaceholderWithEditFrame"> <sc:EditFrame ID="noDataEditFrame" runat="server"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scNoDataHelpTextWithEditFrame" DisableWebEditing="True"/> </div> </sc:EditFrame> </asp:PlaceHolder> <asp:PlaceHolder runat="server" ID="editFramePlaceholder"> <sc:EditFrame ID="pageEditEditFrame" runat="server"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scEditFrameHelpText" DisableWebEditing="True"/> </div> </sc:EditFrame> </asp:PlaceHolder> <asp:PlaceHolder ID="pageEditModePlaceholder" runat="server"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scPageEditHelpText" DisableWebEditing="True"/> </div> </asp:PlaceHolder> </asp:PlaceHolder>
How the placeholders are controlled
The code behind for this markup has a bunch of properties, which are set when placing the control inside a sublayout. These settings are set based on what is needed in that sublayout. These settings eventually control what placeholders show, or don’t show.
// Indicate whether datasource should be checked (i.e. does this sublayout require a datasource) public bool CheckDataSource { get; set; } // Indicate whether the sublayout acutally has a datasource set or not public bool HasDataSource { get; set; } // Indicate whether the control should check if the Item has any child items (based on whether its needed or not) public bool CheckNoItems { get; set; } // Indicate whether the item has any children public bool HasItems { get; set; } // Indicate whether to show page editor instructions public bool ShowPageEditInstructions { get; set; } // Pass in whether user is in page edit mode public bool IsPageEditMode { get; set; } // Indicate whether we should use edit frame for new items public bool UseEditFrameForNewItems { get; set; } // Pass in what set of edit frame toolbar buttons to show public string EditFrameButtons { get; set; } // Pass in the title to show for the edit frame toolbar public string EditFrameTitle { get; set; } // Pass in the path where child items will get created from the edit frame toolbar public Item EditFrameDataSource { get; set; }
The placeholder mainHelperPlaceholder controls the display of anything in control, and is toggled based on whether user is in page editor mode or not:
<asp:PlaceHolder runat="server" ID="mainHelperPlaceholder">
The placeholder noDataSourcePlaceholder controls the display of the instructions of when the sublayout is on the page, but not datasource has been set
<asp:PlaceHolder runat="server" ID="noDataSourcePlaceholder"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scNoDataSourceHelpText" DisableWebEditing="True"/> </div> </asp:PlaceHolder>
The placeholders noDataPlaceholder and noDataPlaceholderWithEditFrame controls the display of instructions when there IS a datasource, but it requires additional items (possibly as child items) which don’t exist. The placeholder noDataPlaceholderWithEditFrame has an extra edit frame as well, with a custom set of buttons that allow the user to enter the child items directly from the page editor.
<asp:PlaceHolder runat="server" ID="noDataPlaceholder"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scNoDataHelpText" DisableWebEditing="True"/> </div> </asp:PlaceHolder> <asp:PlaceHolder runat="server" ID="noDataPlaceholderWithEditFrame"> <sc:EditFrame ID="noDataEditFrame" runat="server"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scNoDataHelpTextWithEditFrame" DisableWebEditing="True"/> </div> </sc:EditFrame> </asp:PlaceHolder>
The placeholder editFramePlaceholder is used to the page editor instructions when there is a need to show page editor instructions for adding child items to a specific path.
<asp:PlaceHolder runat="server" ID="editFramePlaceholder"> <sc:EditFrame ID="pageEditEditFrame" runat="server"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scEditFrameHelpText" DisableWebEditing="True"/> </div> </sc:EditFrame> </asp:PlaceHolder>
The placeholder pageEditModePlaceholder is shown based on if ShowPageEditInstructions is set to true from the sublayout, for generic instructions after all the required items have been added.
<asp:PlaceHolder ID="pageEditModePlaceholder" runat="server"> <div class="sublayoutHelp"> <sc:Text runat="server" ID="scPageEditHelpText" DisableWebEditing="True"/> </div> </asp:PlaceHolder>
The Code Behind
Now that we defined what each placeholder is supposed to do (i.e. what content each will show) here is the code that has the business logic control it all.
public partial class SublayoutHelp : UserControl { public Database ContextDatabase { get; set; } public string HelpItemName { get; set; } public bool CheckDataSource { get; set; } public bool HasDataSource { get; set; } public bool CheckNoItems { get; set; } public bool HasItems { get; set; } public bool ShowPageEditInstructions { get; set; } public bool IsPageEditMode { get; set; } public bool UseEditFrameForNewItems { get; set; } public string EditFrameButtons { get; set; } public string EditFrameTitle { get; set; } public Item EditFrameDataSource { get; set; } protected void Page_Load(object sender, EventArgs e) { // hardcoded for this example: do this only when the server is CMS HSEnums.ServerRole serverRole = HSEnums.ServerRole.CMS; HelpItemName = "/sitecore/content/Globals/Meta/Help/" + Parent.ToString().Split('_')[1]; bool noDataSourceIsVisible = false; bool noDataIsVisible = false; bool noDataWithEditFrameIsVisible = false; bool editFrameIsVisible = false; bool pageEditHelpIsVisible = false; mainHelperPlaceholder.Visible = false; if (serverRole == HSEnums.ServerRole.CMS) { // Set all the placeholders to initial state, which is visible = false SetVisibility(noDataSourceIsVisible, noDataIsVisible, noDataWithEditFrameIsVisible, editFrameIsVisible, pageEditHelpIsVisible); if (ContextDatabase == null) return; Item sublayoutHelp = ContextDatabase.GetItem(HelpItemName); if (sublayoutHelp == null) return; // If the module/sublayout needs to have a datasource and is indicated to check the datasource, // and does not have a datasource set, then show the noDataSource help instructions. if (CheckDataSource && !HasDataSource) { noDataSourceIsVisible = true; } // If the module needs other items, i.e. child items, and is indicated to check this // and does not have the noDataSource placeholder is not shown already (because earlier condition weren't met) // then show the noData instructions if (CheckNoItems && !HasItems && !noDataSourceIsVisible) { noDataIsVisible = !UseEditFrameForNewItems; noDataWithEditFrameIsVisible = UseEditFrameForNewItems; } // If sublayout set the PageEdit isntructions to show, and user is in page edit more, and noData and noDataSource placeholders // aren't already show, then show the generic page editor instructions placeholder if (ShowPageEditInstructions && IsPageEditMode && !noDataSourceIsVisible && !noDataIsVisible && !noDataWithEditFrameIsVisible) { editFrameIsVisible = UseEditFrameForNewItems; pageEditHelpIsVisible = !UseEditFrameForNewItems; } // Now set the fields and item source for all the help text if (noDataSourceIsVisible) { scNoDataSourceHelpText.Item = sublayoutHelp; scNoDataSourceHelpText.Field = FieldsProvider.SublayoutHelpTemplate.NoDataSourceHelp; } if (noDataIsVisible) { scNoDataHelpText.Item = sublayoutHelp; scNoDataHelpText.Field = FieldsProvider.SublayoutHelpTemplate.NoDataHelp; } // If the edit frame that is shown but there is data available, then set the edit frame toolbar source and title. if (noDataWithEditFrameIsVisible) { if (EditFrameDataSource != null) { noDataEditFrame.Buttons = EditFrameButtons; noDataEditFrame.Title = EditFrameTitle; noDataEditFrame.DataSource = EditFrameDataSource.Paths.FullPath; scNoDataHelpTextWithEditFrame.Item = sublayoutHelp; scNoDataHelpTextWithEditFrame.Field = FieldsProvider.SublayoutHelpTemplate.NoDataHelp; } else { noDataWithEditFrameIsVisible = false; } } // If the edit frame that is shown for no data items available is shown, then set the edit frame toolbar source and title. if (editFrameIsVisible) { if (EditFrameDataSource != null) { pageEditEditFrame.Buttons = EditFrameButtons; pageEditEditFrame.Title = EditFrameTitle; pageEditEditFrame.DataSource = EditFrameDataSource.Paths.FullPath; scEditFrameHelpText.Item = sublayoutHelp; scEditFrameHelpText.Field = FieldsProvider.SublayoutHelpTemplate.PageEditorInstructions; } else { editFrameIsVisible = false; } } // If the generic page edit isntructions are supposed to show, then set the item and field for the text if (pageEditHelpIsVisible) { scPageEditHelpText.Item = sublayoutHelp; scPageEditHelpText.Field = FieldsProvider.SublayoutHelpTemplate.PageEditorInstructions; } // Finally, set the visibility after all the logic has been computed. SetVisibility(noDataSourceIsVisible, noDataIsVisible, noDataWithEditFrameIsVisible, editFrameIsVisible, pageEditHelpIsVisible); } } private void SetVisibility(bool noDataSourceIsVisible, bool noDataIsVisible, bool noDataWithEditFrameIsVisible, bool editFrameIsVisible, bool pageEditHelpIsVisible) { mainHelperPlaceholder.Visible = true; noDataSourcePlaceholder.Visible = noDataSourceIsVisible; noDataPlaceholder.Visible = noDataIsVisible; noDataPlaceholderWithEditFrame.Visible = noDataWithEditFrameIsVisible; editFramePlaceholder.Visible = editFrameIsVisible; pageEditModePlaceholder.Visible = pageEditHelpIsVisible; } }
Conclusion
I hope this post (and its predecessor) helped to give an idea of what is possible with the tools that Sitecore provides, in terms of helping the content editor. This by no means is the only approach you can take to achieve this goal, and there are possibly many other ways we can make it easy for user and editors alike. As I mentioned before, if somebody has done similar things in cooler ways, please leave me a note/comment. I’m always curious to know!
Acknowledgements
The two last posts would not be possible without Francesco, who helped to architect and implement this strategy. You can find him here, and on twitter at @gallarotti.