More in this section
Blogs RSS feed

Avoiding uneditable content in your Sitefinity Templates

by User Not Found

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.

Embedding static content in a Sitefinity 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.


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


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.";
                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.

Sitefinity Shared Content

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. 

1 comment

Leave a comment
  1. Hardy Erlinger Sep 28, 2011
    Thank you, Gabe. The way I usually solve this challenge is by leveraging the resources infrastructure.

    In a nutshell:

    1. Create a resources class as decribed in the documentation at

    2. Add any required keys and messages. In your case this would be something like "EncyclepediaTitle" and "ThankYouMessage" with suitable default values.

    3. In your control template reference the resources like this:
    <asp:Literal Text="<%$ Resources:MyCustomResourceClass, ThankYouMessage%>" runat="server" /> 

    The advantage of this approach is that once users know about the section "Admin" -> "Interface Labels and Messages", they can look for the strings themselves and edit them as they whish. All they need to look for is the exact string that's displayed in the widget (case-sensitive).

    The disadvantage is that you will have to deploy a dll with the resources and (although I suspect this to be a bug) that once you uploaded your dll, any changes you make to it afterwards will not be reflected in "Interface Labels and Messages" anymore, i.e. if you add additional resources to the assembly after initial deployment and copy the dll to the server, these resources sometimes don't appear for editing in the "Interface Labels and Messages" UI. Not sure what the solution for this is unfortunately ...

    Anyway, this approach has served me well so far but I'll look into yours, too. Thanks for the article.



    Leave a comment