Level: 300
 

Simple information site in Sitecore – Part 7: Spots - Content oriented

Boxes

This is the seventh part of the article series in 11 parts, describing how to build a simple information site in Sitecore.


In this article we’ll go through how you can build a content spot framework for your website. This article has been split into two parts. One describing a content oriented implementation and one describing a presentation oriented implementation. In this part we will describe the content oriented, where the spots are managed through the content editor.

Written by: Jens Mikkelsen
Wed, Dec 29 2010

Articles in this series

 

Part 1: The requirements
Part 2: Installing Sitecore and setting up a Visual Studio solution
Part 3: Architecture
Part 4: The basic layouts
Part 5: Identity and documents
Part 6: Navigation
Part 7: The homepage - content oriented spots

Part 8: The homepage - presentation oriented spots
Part 9: News
Part 10: Search
Part 11: Deploying the solution

 

Requirements for the homepage

A frontpage on a site rarely holds content itself, but pulls out teasers and content from other pages. This is what we are going to implement. This means that we are going to have several small individual presentations, which the page consists of. These small individual presentations we are going to refer to as content spots; some people refer to them as widgets or web parts.


There are going to be several different types of content spots and these should, as with everything else, be grouped by function and not by type. This means that the individual content spots should be placed in whatever component they are implementing functionality for. For instance the news spot should be placed in the news component.


However there are some generic content spots, which isn’t associated with one component. This is the case for the image spot and the HTML spot, which is described in the first part of this series. These are generic and should therefore be implemented in the spot component.


As you might have noticed the functionality of the frontpage revolves around content spots. As this functionality is general, there is no reason to constrain it to the homepage. Therefore we are not going to create a homepage component, but a spots component. In that way it can be used on different page types, which has nothing to do with the homepage.


Several ways to implement 

The functionality can be implemented in many different ways, and they have different advantages, so it is up to you to decide what benefits you are going for. In this article we’ll go through the first example of implementing it, while we will implement the other in the next article in this series:

  1. In the first implementation we are not going to utilize the Page Designer, but assign spots to a page using normal Sitecore content fields. This implementation may lack the usability of the page designer, but wins in maintainability and enables editors to audit sites without handing over responsibility of the presentations from the developer to the editor.
    This implementation will be focused around content. The idea is that the editors don’t need to focus on how content is presented. Instead they can focus completely on content.
  2. In the second implementation we are going to utilize the Sitecore Page Designer, which is often the way Sitecore suggests. In this implementation you are going to give control over the presentations to the editors and let them assign different sublayouts directly to the item. This has its disadvantages as well. First of all until Sitecore 6.4 this implementation will result in layouts are going to be copied from standard values to the content item. You can read about that on my and Thomas Eldbloms blog, which states that it is a bad idea to assign layouts to items.

The content focused implementation

In the content focused implementation we will focus our solution on enabling the editors to create global spots, which can be reused throughout the site. The editor will start by creating a spot in a global folder and then assign them on the frontpage or any other page using the spot framework – this is done through a multiselect field.


The content spot functionality can be divided into two parts, each responsible for each there area:

  1. The content spots and the presentation they need.
  2. A spot presenter, which can present a list of spots, which it knows nothing about.

By dividing the functionality like this, it is possible to separate the solution by function and not by type as discussed in this post. In that way a spot presenting a list of news, can be developed in the news component and then the spot presenter can render it, without knowing the news component. This is done by defining how a spot is presented in the template representing the content spot, which will be described later in this article.

 

When functionality is generic and not relevant for any specific component, it must be grouped with a component based on type. Therefore the more generic spots will be defined in the spot component itself. This is relevant for the HTML spot and the image spot, which is described in the first article. These spots are not related to any component by its function, but are generic content spots and are therefore placed in the spot component.

 

The content spots

To create these spots, we start out by defining the templates. The HTML spot consists of a title, text, a link and link text which will be shown in the bottom of the spot. The spot will look a lot like one of the spots on the homepage of Learn Sitecore except it doesn’t contain an image.

 

Example spot

 

To start off with lets create the HTML spot first. As mentioned we need to enable the editor to specify a title, text and a link including the link text. So we need to create a template which allows this. Create it in a component folder called Spot:

 

HTML spot template

 

Now we need to create the presentation using the same procedure as in the other articles. In this case we are going to use XSLT, but if you are using sublayouts the concepts are the same. Create the XSLT in a Spot folder (both in Sitecore and in the filestructure). Add the XSLT to a Spot component Visual Studio project (as shown in the earlier articles).

 

Spot component

 

Now we need to develop the functionality. First start out with rendering the title and the text. This can be done using the Sitecore XSLT controls sc:text and sc:html. After that we need to render out the link. This can be done by using the Sitecore XSLT controls sc:text and sc:link, which should give you something like this:

 

< xsl:template match = "*" mode="main">

  < div class = "Spot">

    < div class = "HTMLSpot">

      < div class = "SpotTitle">

        < sc:text field = "Spot_Title"/>

      </ div >

      < div class = "SpotText">

        < sc:html field = "Spot_Text"/>

      </ div >

      < div class = "SpotLink">

        < sc:link field = "Spot_Link">

          < sc:text field = "Spot_LinkText"/>

        </ sc:link >

      </ div >

    </ div >

  </ div >

</ xsl:template >

 

The text and HTML controls simply outputs the text or HTML specified in the referenced field. The link controls takes in a link field and then generated a link to the linked item using the text in between the tags.


Right now you might be wondering why we don’t specify an item where the fields are actual present as this presentation is going to be rendered on the frontpage, but rest assure we will return to this. For the moment you can pretend that the presentation is used directly on the item containing the content.

 

Now that we are done with the HTML spot, we can do the same for the Image spot, which should hold an image field and a link, which the user will be directed to when clicking the image. So go ahead and create a template for the image spot:

 

Image spot template

 

Now go ahead and create the presentation part as well. In this case we stick to the XSLT. I create it in the spot component and include it in Visual Studio, so that I can develop on it. The rendering itself is fairly simple and it just renders the image using the Sitecore XSLT control sc:image and sc:link which we used in the HTML spot. This should make your code look something like this:

 

  < div class = "Spot">

    < div class = "ImageSpot">

      < sc:link field = "Spot_Link">

        < sc:image field = "Spot_Image"/>

      </ sc:link >

    </ div >

  </ div >

 

Creating the user interface for the editor

Now we need to enable the content authors to create spots. As this is a simple information site and as I presume that there is going to be a limited amount of spots, we convinced the client just to have a simple and one leveled structure, where they can create spots globally. Therefore we need to create a folder, where content authors can create the content spots. This means we need to create a spot folder template, so that we can specify the insert options, so that the editors can create new spots easily and intuitive. The spot folder doesn’t actually belong in the spot component, as this is more of an organizing template structuring content together like the GlobalNavigationFolder, which you can read about in this earlier part of the series. So go ahead and create the spot folder template in the PageTypes component, specify an icon and then create standard values by selecting the template, clicking options and then Standard values:

 

Standard values

 

Now an item under the spot folder is created called standard values. Standard values are sort of fallback value for a field. In that way you can add a field value to the standard value and all items based on the spot folder template will by default be using the values specified on the standard values. This makes it a really good option for defining initial field values, which is used if the specific field isn’t edited on the specific item. In that way an item will return the value from the standard values item, if the field isn’t edited. Read more about standard values in Sitecore here.


Now add the Image spot and the HTML spot to the insert options field on the standard values:

Spotfolder insert option

 

If you now add an item to the content structure based on the spot folder template, you will see that the editor easy can create spots. Create a few example spots:

 

Spot folder

 

The spots created in the global spot folder can be regarded as a repository, wherefrom the editor can select a subset of spots, which will be shown on the specific page. This means we should somehow enable the content editors of selecting spots. This can be done by creating one or more multiselect fields with the datasource set so that it will be possible to select only spots. In the frontpage we want to be able to present two columns of spots, which means we have to create a template with two multilists – one for each column. This template should be created in the spots component:

 

Spot column selector

 

Now that we have created the template, we need to set the datasource on each field, so that the editor will only be able to select items that are spots. This can be done in several ways.


We could decide to hardcode the path to the spot folder, but this would give some issues, if we decided to create a copy of the site, for a white label instance or similar.


Another option would have to create a query that looks for the ascendants of the current node, looking for a website root template and then find the spot folder below. However this this would create a dependency from the spot component to the pagetypes component. If we look at the design of the solution, this would create a circular reference between the components, which should be avoided.


Therefore we should find a way to create a datasource, that finds the spots, but doesn’t create any dependencies on other components. The problem is that the Sitecore Query syntax currently doesn’t support any functionality to query on inherited templates. This means we cannot let the root or folder inherit from a base template and then query on this. This makes it quite hard to set the datasource. What we normally do in Pentia is making our own custom multilist field, which can find the root based on inherited templates. But this is beyond this article and we are therefore going to take a shortcut. We are going to base the query on names.

setting datasource sitecore

 

Notice that the query is: ancestor::*[@@name='Home']/*[@@name='Spots']/*
Sitecore Query works very similar to XPath but have a little different syntax. You can read more about Sitecore Query here: http://sdn.sitecore.net/Reference/Using%20Sitecore%20Query.aspx


Our query looks through the ancestors of the current item and then finds a node named Home and then a node named Spots. This isn’t all that nice and you should definitely ensure that your editors can’t rename the home and spots node, but the solution will be sufficient for this small example.

 

Creating the spot presenter

Now that we have enabled the editor to select the spots, which should be presented and created the presentations and templates for the spots, we need to create a presentation that takes the selected spots, and renders their presentation in two columns on the frontpage. So go ahead and create a sublayout called TwoColumnSpots:

 

Two column spots

 

This sublayout will be responsible for creating the grid for the content region on the frontpage, but will not contain the functionality to render the spots itself. The functionality will be put into a more generic usercontrol, which can be used in other presentations as well. For instance if we want three columns, we might as well reuse the presentation to render the spots. This makes the TwoColumnSpot sublayout rather simple:

 

< div class="TwoColumn">

  < div class="LeftColumn">

    <!-- put generic spotrender here -->

  </ div >

  < div class="RightColumn">

    <!-- put generic spotrender here -->

  </ div >

</ div >

 

Now we need to build some sort of control to render the spots. We can create a generic usercontrol to do this, which takes the name of the field, where the editor has selected the spots, as a parameter. There is no reason for this control to be a Sitecore sublayout, as we want to use it in a sublayout grid, so go ahead and create a new class in Visual Studio called SpotPresenter and make it inherit from a UserControl:

 

Spot presenter usercontrol

 

To be able to set which field the spotrenderer should select spots from, we need to create a property where we can set the field name:

 

public string SpotFieldName { get; set; }

 

We want the control to render the spots, when it is loaded, so we want to override the Render method:

 

protected override void Render(HtmlTextWriter writer)

{

  base.Render(writer);

  //Call a method which will render the spots

  RenderSpots(writer);

}

 

 

 

 

 

private void RenderSpots(HtmlTextWriter writer)

{

  throw new NotImplementedException();

}

 

The RenderSpots method needs to find the current item and then locate the field, where the spots are selected:

 

//Get the current item from Sitecore

Item currentItem = Sitecore.Context.Item;

if (currentItem == null)

  throw new InvalidOperationException("Context item doesn't exist. Is the presentation run outside of a Sitecore context?");

 

 

//Get the spotField to render

MultilistField spotField = currentItem.Fields[SpotFieldName];

if (spotField == null)

  throw new InvalidOperationException("Cannot find any spotfield with the name " + SpotFieldName ?? "null");

 

We then need to get the items, which are selected in the field, which can be done using LINQ. Then we need to iterate over these and render the presentation of the spot:

 

//Use LINQ to select the target Items

IEnumerable <Item> spotItems = spotField.TargetIDs.Select(id => Sitecore.Context.Database.GetItem(id));

 

Now we have all the spots that need to be rendered. However we haven’t defined how a content spot, should be rendered. That is, we don’t know which presentation we should render the content with. So we need to define a way for the content in Sitecore to point at a presentation. This can be done in several ways, but we might as well do it in similar way to how Sitecore defines how content should be presented – through the normal layout field. So go to the standard values of our two spots and set which presentation should be used:

 

Sitecore presentation on spots

 

You will see that there is selected the Sample Layout. This is due to the fact, that Sitecore doesn’t allow renderings and sublayouts to be added to the layout field without the presence of a layout. Seeing as the content shouldn’t be presented itself, I have selected the sample layout, but any layout would do and if you want to goldplate the solution create an empty layout, which throws a 404 page not found, as this will make users unable to browse to the spot and get something presented.


Do the same for the HTML spot.


Now we have defined how a spot is presented. This means we can now render the spots, by iterating over them a call a method responsible for extracting the presentations and render them to the page:
 

//Iterate over each spot and call a method to render it

foreach (Item spotItem in spotItems)

  RenderSpot(spotItem, writer);

 

The RenderSpot method will then look like this:

 

private void RenderSpot(Item spotItem, HtmlTextWriter writer)

{

  //Get the current Device

  DeviceItem device = Sitecore.Context.Device;

  if (device == null)

    throw new InvalidOperationException("Cannot find the context device. Is the presentation run outside of a Sitecore context?");

 

 

  //Get the selected renderings on the spot item

  RenderingReference[] renderings = spotItem.Visualization.GetRenderings(device, false);

 

 

  foreach (RenderingReference reference in renderings)

  {

    Control control = reference.GetControl();

    //Set the datasource for the presentation

    ((Sitecore.Web.UI.WebControl)control).DataSource = spotItem.Paths.FullPath;

    //use the Sitecore API to render out the contents of the presentation

    control.RenderControl(writer);

  }

}

 

Here we get the presentations set on the spot for the current device and then we set the datasource to the spot item and then call the Sitecore API method RenderControl, which renders the contents of the presentation. Notice that we actively set the datasource and that is why the spot presentations doesn't use the context item as its datasource.


Now all we need to do is add the control to the TwoColumnSpot sublayout:

 

<% @ Control Language="C#" AutoEventWireup="true" CodeBehind="TwoColumnSpot.ascx.cs" Inherits="Spot.TwoColumnSpot" %>

<% @ Register TagPrefix="spot" Namespace="Spot" Assembly="Spot" %>

< div class="TwoColumn">

  < div class="LeftColumn">

    < spot : SpotPresenter SpotFieldName="Spot_LeftSideSpots" runat="server" ID="LeftColumnSpots" />

  </ div >

  < div class="RightColumn">

    < spot : SpotPresenter SpotFieldName="Spot_RightSideSpots" runat="server" ID="RightColumnSpots" />

  </ div >

</ div >


Here we have registered the tagprefix Spot and added the controls, where we specify the property SpotFieldName. Now add this presentation to the FrontPage template:

 

Spots on frontpage

 

Select some spots in the spot fields on the frontpage, publish, compile and then hit the frontend. With a little styling you should now see something like this, where I have selected the HTML spot in the left column and the image spot in the right column:

 

Frontend spots

 

Now you are done. In the next part we will look at how the same functionality can be achieved using the unified page editor in Sitecore 6.4. Also we will discuss advantages and disadvantages for the two kinds of implementations.
 

 

 

 

 

 

Please rate this article


9 rates / 2,11 avg.

  • About the author:

    Jens Mikkelsen

    Jens Mikkelsen is a partner at Inmento Solutions a Sitecore consulting firm. He works as a Sitecore specialist and consulting helping clients architect and build quality Sitecore solutions using the newest modules and tools. 

    Further he has been deeply envolved in various complex solutions and has built up a strong knowledge of Sitecore architecture and best practices. He has especially focused on and is specialized in debugging and analyzing Sitecore solutions.

     

    Jens is very interested in the technical mechanisms in the new marketing products such as Sitecore DMS and Sitecore ECM.

    My Sitecore Freelance CV

17 responses to "Simple information site in Sitecore – Part 7: Spots - Content oriented"

Hello Jens

Great article, but I'm wondering about OMS functionality like MV test, personalization etc., when adding spots via data on the items?

OMS functionality works by (correct me if I'm wrong) adding renderings to an item and setting (for example) personalization on that rendering. By adding spots in the data section of an item, you are mixing presentation and data, since it is predetermined where the spots are placed and how they are rendered. You can of course set the rendering on the specific spot, but that would apply to all spots and not the particular spot in mind.

The above solution worked great in Sitecore versions before OMS, but since OMS started dictating (even more) practices for separation of data and presentation, it is also even more important to think about the user, rather than excellent implementations as I think the above solution really is!

With the newest Sitecore 6.4, it is becoming easier for editors to change to layout of a page and place "spots" and the likes on pages with advanced OMS functionality like personalization, MV test etc. I think these options are a must for editors, do you agree?

Side note: Thanks for a great site! :)
Posted: Thursday, January 06, 2011 8:56 AM
Hi Claus,

Thanks for your comment. You are right about OMS and Page Designer not being supported in this way of implementation, which is why I am writing two articles with two different implementation strategies. This one is the content focused while the next will focus on presentation.

Regarding the OMS you only restrict users from using the presentation and conditional rendering part, which in my opinion is a very little part of all the benefits of OMS. OMS and personalization could very well be implemented at content level instead. If you want to read more about my approach to OMS, check out this blog entry I wrote a while back. It doesn't go into detail, but it should give you an idea on a more general level: http://mcore.wordpress.com/2010/04/22/will-sitecore-oms-end-strictly-hierarchical-sites/

Regarding the Page Designer before Sitecore 6.4, there are some really big set backs, which is why I wrote about this type of implementation as well. In Sitecore 6.4 it has been improved a lot, but there are still some drawbacks, which I will describe in the next article.

Finally about mixing presentation and content; I would say that this part is even more strict. The idea is that the editor will never worry about presentation only content. Which will be the best way to go for some implementations.
The presentation and content is very much separated and content is kept even though you change the presentation. There are absolutely no content bound to the presentations, which there might be, if you decide to implement the presentation oriented implementation (which I will write about in the next article)

I hope that makes sense and it is very nice to hear your point of view.

Cheers
Jens
Posted: Monday, January 10, 2011 8:22 PM
Thanks for the article. We started using a similar approach in our projects. Developers & content editors have been very positive but I'm also very curious how the "sitecore/presentation way" is working in 6.4. Bring on the next article! :)

Posted: Tuesday, January 25, 2011 11:36 AM
Hi Jens,

Kudos for all the articles! Sitecore is become a real pinnacle in this matter as covering the basics is one, but taking OMS, Page Editor Mode, developers, content editors, designers, and multi sites into account is a whole different story. I am really looking forward to your next article. This one is very valuable, but will be obsolete soon enough I guess, assuming that OMS 2 and Sitecore 7 will bring a whole lot more to the table in this direction of presenations.
Posted: Saturday, February 19, 2011 1:58 AM
Hi Jens,

First, I like to thanks for all these articles, they helped a lot to understand better sitecore.

I am a beginner of sitecore, but I am missing something in the article, which template has to inherited _twoColumnSpots template? Is it normalPage template? If doesn't have to inherit how the editos choose the spots? Please if you can explain me better this part.

Thanks a lot and once again congratulations, these articles are really great.



Posted: Tuesday, March 08, 2011 8:42 PM
Kit
Would you have the source code available for this lesson...i am relative newbie to .net C3 and sitecore and am having a difficulty getting my SpotPresenter.cs code to validate.

Thanks...great series...hope to see more about it.
Posted: Monday, March 28, 2011 8:25 PM
Hi Guys and Girls,

The next episode in the series is now available. I hope you enjoy it!

@Kit - I have uploaded the code in the next article and it also include the SpotPresenter.cs, so you can get it from there.

@Karol - the Frontpage template has to inherit from the _twoColumSpots template.
Posted: Tuesday, March 29, 2011 11:55 PM
Kit
Hey Jens,

So i have this SpotPresenter implemented and all seems to be correct. i have added the _TwoColumSpot template to my Home template and i am able to select spots to go in the various columns. All is good.

However, when i publish and preview the page, while the sublayout "TwoColumnSpot" that houses the two columns renders fine, and in SiteCore Debug see it calling the two spots i have created (HTMLSpot and ImageSpot, both sublayouts), nothing is rendered at all. Its like the GetControl call is failing or not returning what it supposed to.

Any thoughts on what it could be? Again please excuse my newbieness :)

Kit
Posted: Wednesday, April 06, 2011 6:34 PM
Hi Kit,

First of all I would hardcode some content in the spot presentations, to see if it is rendered. This should indicate whether there is a problem with the spot presentations or the spotpresenter.

If no content is presented it might be that the spot presentation isn't added to the spot template standard values.

Let me know if it works.

Cheers
Jens Mikkelsen
Posted: Wednesday, April 06, 2011 9:11 PM
Kit
OK i have some hardcode content in the HTMLSpot Sublayout and the IMAGESpot Sublayout.

The TwoColumnSpot Sublayout is rendering fine, but nothing is showing for the two spot presentations. I ran through Debug on SpotPresenter.cs and when it get to the RenderSpot function this has a value
((Sitecore.Web.UI.WebControl)control).DataSource
but it is red.
control.RenderControl(writer) executes but nothing displays and then the page is done...

no spots...
Posted: Thursday, April 07, 2011 6:39 PM
Adding a comment so I can get notified when the Page Editor article is ready. An ETA on that would be great too. Nice series so far Jens.

~james
Posted: Monday, August 22, 2011 7:14 AM
scratch that I see it is already up.
Posted: Monday, August 22, 2011 7:28 AM
Haha. Enjoy!
Posted: Monday, August 22, 2011 9:13 AM
Okay, I am having the same issue as Kit last year. Exactly the same. I downloaded the source from the next article but everything I did looks the same. If it makes a difference, I am using sublayouts and not renderings.
Posted: Sunday, March 18, 2012 11:09 PM
For anyone else trying to do this with sublayouts instead of renderings, this code seems to work with both. Although I have not tested it too hard yet.

Replace:
Control control = reference.GetControl();
//Set the datasource for the presentation
((Sitecore.Web.UI.WebControl)control).DataSource = spotItem.Paths.FullPath;
//use the Sitecore API to render out the contents of the presentation
control.RenderControl(writer);


With:
//Set the datasource for the presentation
reference.Settings.DataSource = spotItem.Paths.FullPath;

//Get the Control that renders this spot
Control control = reference.RenderingItem.GetControl(reference.Settings);

//Add this control to the collection
this.Controls.Add(control);

//use the Sitecore API to render out the contents of the presentation
control.RenderControl(writer);

Posted: Monday, March 19, 2012 4:22 PM
This is the same solution that I presented at Dreamcore North America in 2010. See additional ways to implement the concept at http://www.awareweb.com/AwareBlog/InversionControl2.aspx.
Posted: Wednesday, July 18, 2012 8:20 PM
Thanks for the tutorial series, I'm new to sitecore and they are really helping. I'm using sitecore 6.6 and the datasource query for the spots did not work for me. A little trial and error and I discovered that this worked:
ancestor::*[@@name='Home']/*[@@name='Spots']

i.e. I needed to strip /* from the end of the query.
Posted: Thursday, November 22, 2012 12:21 PM

Leave a reply


Notify me of follow-up comments via email.
 
 
#nbsp;