Monday, August 25, 2008

Organizing Branch Templates

Earlier this year, I wrote about organizing Master Hierarchies in the Sitecore content tree. I described a limitation in Sitecore 5.3 that has changed for the better in Sitecore 6. This post discusses a new Sitecore feature -- Branch Templates -- and how it has replaced and improved upon Sitecore 5.3 Masters.

The theme of Sitecore 6 was "Simplicity." In pursuit of simplicity, we made major user interface changes for content authors. Our new Page Editor and Page Designer modes dramatically improve ease of use for editors from both a content authoring and page layout perspective. In addition, we focused on simplifying the experience for developers. Many new features were added, including the Quick Action Bar, built-in validation (at both the item and field level), efficient management of locked items and much more.

The introduction of Branch Templates was a way to simplify the creation of new blueprints for complete sites, microsites or branches of the content tree. If this sounds familiar, it is because this functionality already existed in Sitecore 5.3 using Masters. Masters and Master Hierarchies were designed to create item instances of Sitecore Templates (now referred to as "Data Templates" in Sitecore 6). Masters could be configured on an individual item or on a Template's Standard Values to allow one-click item creation for non-technical business users.

Conceptually, Masters and Templates (along with their Standard Values) were so close, that we decided to merge them into a single concept in Sitecore 6. Templates became similar (and preferred to) Masters starting in Sitecore 5.3. Sitecore 5.3 introduced the idea of Template Standard Values that maintain a dynamic connection with all of the content instances (i.e. items based on the template). This was a big leap from Sitecore 5.2, where these values could only be placed on Masters. In Sitecore 5.3, we only recommend using two features of masters: 1) using Masters to create new content items and 2) using the $name token (which would be replaced with the name of the item being created).

In merging Masters and Templates, we decreased the learning curve for developers while adding some essential features. In particular, Sitecore introduced the ability to organize templates and to create Branch Templates with siblings.

Back in January, I wrote the following about the organization of Masters in Sitecore 5.3:

There are some system-related limitations to organizing masters (under /sitecore/masters). Specifically, developers cannot organize masters into subfolders...The reason for this is that Sitecore uses the structure of the masters themselves to determine master hierarchies.

In Sitecore 5.3, Masters were all stored under a flat structure under /sitecore/masters and there was no easy workaround if you wanted to organize your Masters. In multi-site solutions (or simply solutions with many masters), this was a non-ideal organizational structure.

In Sitecore 6, this problem is solved using Branch Templates. You can find Branch Templates under /sitecore/templates/branches or in the Template Manager under templates/branches. In the screenshot below, you can immediately see that Branch Templates can be organized hierarchically.

Branche Template

Under the NiCam folder, you can see six branch templates: Flash, Lenses, Other Accessories, P & S, poll and SLR. The Branch Template item is a container for the template structure itself. For example, when a user creates a "Canon 200" using the "SLR" Branch Template, the following tree structure is created:

  • Cannon 200
    • Resources
    • Reviews

We can also create sibling Branches. Consider the following scenario:

image

If a user creates a "Canon 200" using the "Lenses" Branch Template, the following tree structure is created:

  • Cannon 200
  • Support
    • Resources

The idea is that you instantiate a branch using the container template (in this example, "Lenses") and Sitecore uses the children of that container to instantiate new items.

Branch Templates make life easier for developers when compared to Masters and give much more flexibility in your design of this section of the content tree. To learn more about Branch Templates, see the Data Definition Reference in the Sitecore CMS 6 References.

Tuesday, July 29, 2008

Administering Security, revisited

Back in January, I wrote about security administration in Sitecore and its effect on the design of the content tree. I advocated for the use of security inheritance to simplify security administration, such that many child or descendant items could inherit their security permissions from a single parent. Administering security on the parent item dramatically saves time over placing security settings on each of the descendants.

I also discussed the following use case:

...you may encounter requirements that a parent item and its children have different security permissions.

This is a common requirement for a product or news landing page. Someone in marketing might have editing rights to the landing page; someone in product management might have editing rights to the products themselves. One solution I recommended looked as follows:

I. Home
  a. Product Landing
    i. Products [folder]
      1. Product A
      2. Product B

This organization allows separate settings to be placed on Product Landing and the Products folder. All of the products in the branch can inherit their permissions from the Products folder. Separate permissions can be placed on the Product Landing page.

Sitecore 6 introduces a new solution to this security administration scenario. It's an exciting feature that -- while introducing some complexity -- ultimately simplifies administrative tasks. (Note: We also have new documentation on security topics on the Sitecore Developer Network. This is worth the read, as it discusses many of the new security features introduced in Sitecore 6.)

When you open the Security Editor in Sitecore 6 and select a user or role, you can click on the "Assign" button in the Editor ribbon. This brings up the Security Settings dialogue, which allows you to set separate settings for the item vs. its descendants. This directly addresses the use case above where the marketing role controls the landing page, but not the product descriptions.

Let's take a closer look at the UI. In the top pane, users and roles are listed for whom you are setting permissions. You can assign security settings for any number of users and roles at once -- a significant user interface enhancement over the Sitecore 5 approach.

In the next pane, the standard permissions (rwcrda) are listed on the left. Permissions for either the item or its descendants are listed on the right. Note that this feature has been implemented for both item-level security and item-level inheritance.

SecuritySettings

What does this mean for the design of your content tree? It means that a simplified, intuitive content tree structure can be created and easily administered. The final design for the tree can remove the Products folder without introducing administrative headaches:

I. Home
  a. Products
    i. Product A
    ii. Product B

Tuesday, March 25, 2008

Team Development

A full discussion of team development exceeds the scope of this blog; however, a brief mention of the relationship between team development and content tree design is worth mention. Typically, developers work in one of two ways: using a shared development database or a local database. In the former scenario, all changes are saved to a common system; in the latter scenario, data is changed locally and moved (using the Packager) to an integration server.

A simple rule of thumb in either scenario is to reduce the incidence of developers writing to the same item or subitems in the content tree. In the former scenario (a single development database), this can create unintended consequences due to the fact that most developers work as Administrator users. This means that common features such as item locking do not apply to them. Developers can easily overwrite each others' changes if they are working on the same part of the content tree simultaneously.

In the latter scenario (isolated development), challenges emerge when moving data to an integration server. Choosing the correct installation options in the Package Installer is often confusing and developers can end up overwriting each others’ changes.

In any case, communication and coordination between developers is essential to ensure that the data in the content tree is accurate.

Monday, March 24, 2008

Packaging Nodes

While it is typically not a first consideration to design your content structure to facilitate the creation of packages, it is worth noting that the content tree can be organized to make the difficult process of generating packages easier. Here, the simplest of recommendations applies: Organize project assets into logical folders whenever possible. For example, when managing multiple sites in a single instance of Sitecore, organize templates into site-specific folders. This makes it easy to use the "Add with Subitems" command in the Package Designer when adding items statically.

Monday, March 17, 2008

Sorting Content Items

By default, Sitecore sorts content items based on their sortorder attribute. Sortorder describes how a single content item should be sorted relative to its siblings. (If the sortorder attribute is not set, Sitecore uses the SubItems Sorting value of the parent item. See here for more information: http://sdn5.sitecore.net/Scrapbook/Understanding%20the%20Sort%20Order.aspx.) To set the sort order of an item, business users can click on the sort commands in the ribbon. The sort commands provide commonly required options:



Clicking on one of these commands updates the sortorder attribute of the selected content item:


Clicking on the sorting options allows business users to sort the subitems of the current item based on a number of criteria:



Rendering logic will implicitly recognize this sort order, such that the following rendering will respect the sortorder field:

    <xsl:for-each select="$home/item[@key='vehicles']/item">
      <sc:link>
        <sc:image field="menu image" />
        <sc:text field="menu title" />
        </sc:link>
    </xsl:for-each>

Sitecore allows developers to implement their own sorting algorithms (http://sdn5.sitecore.net/Scrapbook/Understanding%20the%20Sort%20Order.aspx). Algorithms can be specified under /sitecore/system/settings/subitems sorting. For example, to sort items by a date field, developers can use the following approach:

public class ItemComparer : IComparer
{
private string _fieldName;

public ItemComparer()
{
}

public ItemComparer(string fieldName)
{
_fieldName = fieldName;
}

public int Compare(object x, object y)
{
Item item1 = x as Item;
Item item2 = y as Item;

if (_fieldName == null)
{
_fieldName = "date";
}

Sitecore.Data.Fields.DateField date1 = (Sitecore.Data.Fields.DateField)item1.Fields[_fieldName];
Sitecore.Data.Fields.DateField date2 = (Sitecore.Data.Fields.DateField)item2.Fields[_fieldName];
return System.DateTime.Compare(date1.DateTime,
date2.DateTime);
}
}

This class can be used in your code-behind as follows:

// get an array of the Items:

Item[] i = Sitecore.Context.Database.SelectItems("");

// sort it using your comparer:

Array.Sort(i, new ItemComparer());

// use the sorted array:

foreach (Sitecore.Data.Items.Item thisItem in i) {
// do something with each item
}

Tuesday, March 11, 2008

Content Search

In some projects, developers must address requirements that involve simple searches. For example, imagine a firm that provides trainings at store locations around the local area. Each training has a predictable set of attributes such as Title, Start Date and Instructor. End users can select from a list of classes and view all of the locations where the training is being offered. Effectively, the system performs two searches: the first query returns a list of all classes; the second query returns a list of locations where a specific class is being taught. The system may provide further flexibility, wherein choosing a location lists all of the instructors teaching the class. In this case a third query will be required.



Note that here we are referring to a search of content nodes, not a website search that would typically be addressed by a site search engine. The following analysis will assume that developers are either using XPath or Sitecore Query to perform query operations.

The performance of this feature and the strategy for its implementation may be dramatically different depending on the design of the content tree. The following may be the initial design for the project, based on the logical structure of business units:

I. Home
  a. Locations
    i. Store A
      1. Classes
        a. Class A
        b. Class B
      2. About Us
    ii. Store B
      1. Classes
        a. Class A
        b. Class B
      2. About Us

This intuitive structure may easily map on to the business hierarchy, facilitate the development of navigation elements and simplify the implementation of content markers.

To query the above content structure, however, requires the use of descendants queries that may slow site performance. A Sitecore Query of /sitecore/content/home/locations//*[@@templatename=’class’] would return a result set including all classes; however, the system would have to traverse almost the entire content tree to access the desired results. Similarly, a Sitecore Query of locations that teach the selected class would require an additional descendants search along with further analysis of content items to determine available locations.

The larger the number of locations, the slower the queries will perform. The SDN provides guidance on optimizing the performance of various query scenarios (http://sdn5.sitecore.net/Reference/Using%20Sitecore%20Query.aspx); however, in this case, a reorganization of the content tree may be in order. Consider the following alternative:

I. Global
  a. Classes
    i. Class A
      1. Instance A
      2. Instance B
    ii. Class B
II. Home
  a. Locations
    i. Store A
      1. About Us

Here, the classes are organized under /sitecore/content/Global/Classes. Each class has any number of instances, which include attributes for Start Date, Instructor and Location. With this organizational approach, the queries are simplified and provide significance performance advantages. A query of /sitecore/ content/Global/Classes/* will return a list of classes without requiring a descendants query. Retrieving a list of locations for a particular class, again, avoids descendants queries. The query /sitecore/content/Global/Classes/Class A/* will return all class Instances for a particular Class. This list of Classes will need to be analyzed to generate a list of locations.

Optimizing the content tree for search performance is a broad topic and exceeds the scope of this document. However, developers should keep this consideration in mind when designing the content tree. Other approaches – such as leveraging the Links Database, creating search metadata or using search engine APIs – should also be considered fully when optimizing search-driven features.

Wednesday, March 5, 2008

Navigation Elements

The design of your content tree can dramatically impact the ease of implementing navigation elements such as hierarchical navigation or breadcrumbs.

When the content tree mirrors the information architecture of your web site, generating hierarchical navigation is extremely simple. An XSL code snippet could be as straightforward as the following:

  <xsl:for-each select="$home/item[@template='section']">
    <div>
      <sc:link>
        <sc:text field="menu title" />
      </sc:link>
    </div>
  </xsl:for-each>

In this simple example, the XSLT loops through the children of the home item and outputs a link to each child that is based on the Section template. The simplicity of this rendering is dependent upon the mirroring of the content tree and the information architecture of the site. When possible, this is a very desirable way to design the content hierarchy due to the development productivities that can be realized.

Depending upon what should appear in the site navigation, however, this exact mirroring may not be possible. Business users may want to control the items listed in the navigation based on editorial decisions rather than a static information architecture. Consider a requirement for the following items to appear in the navigation: Specials, CEO Blog, Products and About Us. These items, however, may be scattered throughout the content tree:

I. Home
  a. Products
    i. Specials
    ii. Product A
  b. About Us
    i. CEO Blog

There is no simple logic to determine which items will appear in the navigation and – even if there were – this logic may change over time. To address this, developers may wish to allow business users to configure the navigation themselves. One way to accomplish this requires that the navigation is described in metadata items, possibly in the /sitecore/content/global folder.

I. Content
  a. Global
    i. Navigation
      1. Nav 1
      2. Nav 2
      3. Nav 3
      4. Nav 4

Each of the Nav elements in the above example is based on a template with a Navigation Item field. This field may be a tree list control that allows business users to select an arbitrary item from the content tree. Business users may sort the children of /content/global/navigation in the order they should appear in the navigation. A simple rendering would be:

  <xsl:for-each select="/*/item[@key='content']/item[@key='global']/item[@key='navigation']/item">
    <div>
      <xsl:variable name="sourceItem" select="sc:item(sc:fld('navigation item', .), .)" />
      <sc:link select="$sourceItem">
        <sc:text field="menu title" select="$sourceItem" />
      </sc:link>
    </div>
  </xsl:for-each>

A perhaps simpler approach (though more complex in XSL) would be to implement a single Navigation item:
I. Content
  a. Global
    i. Navigation

The Navigation item would have a field called “Menu Items” of type treelist whose source is the /sitecore/content/home item. Business users can choose which items they want to appear in the navigation and sort them based on editorial decisions.

Yet another way to tackle this problem would be to create a base template for your site with a “Show in Navigation” field. Your rendering logic could perform a descendants query starting with the home item to check for the value of the field. While the solution is simple, this query could create extreme overhead problems as descendants queries can be very expensive.

Rendering breadcrumbs poses similar challenges to those described with hierarchical navigation. When the page navigation mirrors the content tree, rendering breadcrumbs is trivial from a coding perspective:

  <xsl:for-each select="ancestor::item">
    <xsl:if test="position() > 2">
      <sc:link>
        <sc:text field="menu title" />
      </sc:link> >
    </xsl:if>
  </xsl:for-each>
  <sc:text field="menu title" />

If the user has navigated to the /sitecore/content/Home/Products item, the above rendering will output: Home > Products.

When the content tree does not mirror the information architecture of the website, breadcrumbs become more complicated. Imagine the following content hierarchy:

I. Home
  a. News
    i. 2007
      1. January
      2. February
        a. 01
          i. News Story 1
          ii. News Story 2

In the example above, News Stories are structured by the year, month and date they are entered. However, business requirements may dictate that the breadcrumb exclude the year, month and date items and display all News Stories as children of the News section. For example, the breadcrumb for News Story 1 should be: Home > News > News Story 1. To implement this, a simple filtering of content items by template may be sufficient:

  <xsl:for-each select="ancestor::item">
    <xsl:if test="position() > 2 and @template != 'folder'">
      <sc:link>
        <sc:text field="menu title" />
      </sc:link> >
    </xsl:if>
  </xsl:for-each>
  <sc:text field="menu title" />

The more your content tree deviates from your site’s information architecture, the more complex your rendering logic will need to be and the more reliant your renderings will be on metadata. This should not imply that your content tree needs to be determined by ease-of-coding considerations. However, where developer productivities can be achieved by simplifying content organization, this should be considered.