Avoiding uneditable content in your Sitefinity Templates

September 27, 2011 Digital Experience

Recently I was creating a custom widget template for the Sitefinity Blog Widget.  As part of my design, I needed to add some text to this template.  Because I was already modifying the template I simply typed this content directly into my template.

Thou shalt not manage content outside the CMS

Later I recognized my mistake.  As a content editor, it’s extremely frustrating to be modifying a web page only to realize there is some bit of content that is uneditable because it’s embedded directly inside code. 

It’s easy to slip into this habit though.  In the beginning it’s easier to type the content directly into the template.  However, as this becomes more prevalent the web site becomes unwieldy & unsustainable.    Trivial content edits require the involvement of developers (who may or may not remember where this content is located).

In a nutshell, embedding content directly into code defeats the purpose of having a CMS.

First a big disclaimer

The solution I’m going to share below is my personal solution to this challenge. 

I put this code through an internal review and several people on the team suggested this was a messy solution to this challenge.  Nor do I entirely disagree with them.

They suggested I use Sitefinity’s built-in <sf:ContentBlock> widget instead of a custom User Control.  However, after experimenting with this, it doesn’t appear that <sf:ContentBlock> currently works inside a template while utilizing Shared Content. 

Alternately, they suggested I create separate page for the the List and Details view of my Blog Posts.  (As opposed to having a single page handle both views).  This would allow me to use Sitefinity’s Page Editor (instead of widget templates) to add this content.  This works fine, but this technique becomes reflected in the page URL’s.  Perhaps I’m too picky, but my URL’s were more important to me than the editing experience.

I debated whether I should publish this blog post.  However, even though it is messy, this code let me overcome a challenge and accomplish my personal goals.  Long-term, the team is investigating more elegant solutions to this use case.  In the meantime it felt like sharing is better than silence.

My personal solution

Now that I have my giant disclaimer out of the way, here is how I addressed this:

1.  First, I created a very simple ASP.NET User Control that allows me to select from Shared Content based on a Title.

~/Extensions/Widgets/SharedContent.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SharedContent.ascx.cs" Inherits="SitefinityWebApp.Extensions.Widgets.SharedContent" %> <asp:Literal ID="ContentLiteral" runat="server" />

~/Extensions/Widgets/SharedContent.ascx.cs

using System;
using System.Linq;
using Telerik.Sitefinity;

namespace SitefinityWebApp.Extensions.Widgets
{
    public partial class SharedContent : System.Web.UI.UserControl
    {
        public string ContentTitle { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            var content = App.WorkWith().ContentItems().Where(x => x.Title == ContentTitle).Get().First();

            if (content == null)
            {
                ContentLiteral.Text = "The specified shared content cannot be found.";
            }
            else
            {
                ContentLiteral.Text = content.Content;
            }
        }
    }
}

2.  Next, I modified the Blog List widget template to replace the embedded content with dynamic content.

<%@ Control Language="C#" %> <%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.ContentUI" Assembly="Telerik.Sitefinity" %> <%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" Assembly="Telerik.Sitefinity" %> <%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.PublicControls.BrowseAndEdit" Assembly="Telerik.Sitefinity" %> <%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %> <%@ Register Src="~/Extensions/Widgets/SharedContent.ascx" TagName="SharedContent" TagPrefix="sf" %> <%@ Import Namespace="Telerik.Sitefinity" %> <telerik:RadListView ID="Repeater" ItemPlaceholderID="ItemsContainer" runat="server" EnableEmbeddedSkins="false" EnableEmbeddedBaseStylesheet="false"> <LayoutTemplate> <sf:ContentBrowseAndEditToolbar ID="MainBrowseAndEditToolbar" runat="server" Mode="Add"> </sf:ContentBrowseAndEditToolbar> <h1> <!-- Retrieve the "Encyclopedia Title" message from a Shared Content Block --> <sf:SharedContent ContentTitle="Encyclopedia Title" runat="server" /> <!-- The content block should contain plain text (no HTML) because of how it is used here --> </h1> <ul class="sfpostListTitleOnly"> <asp:PlaceHolder ID="ItemsContainer" runat="server" /> </ul> </LayoutTemplate> <ItemTemplate> <li class="sfpostListItem"> <sf:DetailsViewHyperLink ID="DetailsViewHyperLink1" TextDataField="Title" ToolTipDataField="Description" runat="server" /> </li> </ItemTemplate> </telerik:RadListView> <sf:Pager ID="pager" runat="server"> </sf:Pager> <div class="message"> <!-- Retrieve the "Thank You" message from a Shared Content Block --> <sf:SharedContent ContentTitle="Thank You Message" runat="server" /> </div>

3.  The last step was to create the Shared Content Blocks referenced by my template.

Final thoughts

My solution above solves the challenge of surfacing content through the CMS.  This makes the content manageable by content editors.  This is good.

However, this scenario also requires training & communication between developers, designers and content editors.  It won’t be intuitive, by looking at the page, that this content is stored in a Shared Content Block with a title of “Thank You Message”.  It’s also not intuitive that this content sits inside a <DIV> that is styled through a specific widget template & theme. 

Beyond documentation and communication I don’t have a magic fix for this.  I suspect in-line editing is our best long-term solution for cutting through this challenge.  (If you can see it, you can edit it.)  In-line editing is something Sitefinity already supports, although my customization above does not support in-line editing.

Either way, at least the content isn’t sitting inside a file that only developers can modify.  This is certainly a step in the right direction. 

I welcome feedback, alternatives or criticism. 

The Progress Team