I’ve been looking at the new Visual Studio 2010 beta and it looks like it’s going to make all sorts of improvements over VS2008.

One of the features I really like is the web.config transformations; this is exactly what I’ve been looking for in Sitecore installs. When you’re deploying Sitecore to a production server there is always a raft of settings that need changing, you can manually keep track of them or use features like configSource attributes but there always seems to be problems. In VS2010 however you can keep a set of transformation web.configs for your various deployments:

image

Part of the MSBuild deployment process is that it creates a new web.config with the changes you’ve specified in the transformation files. The files themselves contain the settings that need changing and details on how to match them within the original web.config:


<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings configSource="App_Config\ConnectionStrings.Debug.config" xdt:Transform="Replace" />
  <sitecore database="SqlServer">
    <sc.variable name="dataFolder" value="E:\WebApplications\vs2010test\data" xdt:Transform="Replace" xdt:Locator="Match(name)"  />
    <sites>
      <site name="vs2010test_english" xdt:Transform="Replace" xdt:Locator="Match(name)" language="en" hostName="english.vs2010test.local" ...
      <site name="vs2010test_japanese" xdt:Transform="Replace" xdt:Locator="Match(name)" language="ja-JP" hostName="japanese.vs2010test.local" ...
      <site name="vs2010test_german" xdt:Transform="Replace" xdt:Locator="Match(name)" language="de-DE" hostName="german.vs2010test.local" ...
    </sites>
    <settings>
      <setting name="IndexFolder" xdt:Transform="Replace" xdt:Locator="Match(name)" value="E:\WebApplications\vs2010test\data\indexes" />
    </settings>
  </sitecore >
  <system.web>
    <customErrors mode="RemoteOnly" xdt:Transform="Replace"/>
  </system.web>
</configuration>

The important attribute is xdt:Transform=”Replace” which replaces the setting in the original web.config with the new one. This works fine when there is just a single node of that type such as <connectionStrings/>.

For nodes with multiple instances such as <site/> you can distinguish them using xdt:Locator=”Match(name)” which tells the transformer to match the element to the original using the name attribute.

Once all the changes are made you should end up with a new web.config that is configured for your deployment target machine. There is the added bonus that all of these transform files are stored in source control alongside the original web.config.

I’ve also been looking at the Team Development for Sitecore product from Hedgehog software (deserves own blog post), combined with this and I think my deployment issues will be solved. Hopefully :)

Fields that inherit the value of their parent items is something I’ve heard asked for before in the past but I’ve always just recommended coding it into the presentation. As an alternative however I’ve created a custom renderField pipeline step that handles it for you.

By including “InheritParent” in the name of your field it will look for values in parent items when none exists in the current item. Installing it is just a matter of including the code in your project and referencing it in the <renderField> just after GetFieldValue:

<renderField>
  <processor type=”Sitecore.Pipelines.RenderField.GetFieldValue, Sitecore.Kernel” />
  <processor type=”Namespace.FieldValueInherit, Assembly” />

using System;

using Sitecore.Data.Fields;

using Sitecore.Data.Items;

using Sitecore.Pipelines.RenderField;

namespace Namespace

{

/// <summary>

/// Sitecore renderField pipeline for inheriting parent field values recursively.

/// </summary>

public class FieldValueInherit

{

/// <summary>

/// Processes the field value inheritance pipeline.

/// </summary>

/// <param name="args">The pipeline arguments.</param>

public void Process(RenderFieldArgs args)

{

//Dont run while in page edit mode.

if (Sitecore.Context.PageMode.IsPageEditor ||

Sitecore.Context.PageMode.IsPageEditorClassic ||

Sitecore.Context.PageMode.IsPageEditorDesigning ||

Sitecore.Context.PageMode.IsPageEditorEditing ||

Sitecore.Context.PageMode.IsPageEditorNavigating)

{

return;

}

//Check field exists.

Field field = args.GetField();

if (field == null)

{

return;

}

//Check field is tagged to inherit parent values.

if (!field.Name.Contains("InheritParent"))

{

return;

}

//If field contains standard values then check parent items for fields that have been set.

if (field.ContainsStandardValue || !field.HasValue)

{

Item item = args.Item;

if (item == null)

{

return;

}

Item[] ancestors = item.Axes.GetAncestors();

Array.Reverse(ancestors);

foreach (Item ancestor in ancestors)

{

if (ancestor.Fields[field.ID] != null && ancestor.Fields[field.ID].HasValue)

{

args.Result.FirstPart = ancestor.Fields[field.ID].Value;

return;

}

}

}

}

}

}

Bit of a mini-post, I saw a writeup on how to create new template types for Visual Studio so I went ahead and created one for the Sitecore XSLT Rendering files. Save the below file to your Visual Studio templates folder (Tools->Options->Projects & Solutions) and you’re done. When you next go to add an xslt file you can pick the Sitecore XSLT Rendering (which I got from the latest 6.2 release) listed under my templates.

InsertRendering

If you wish to modify it you can just make changes to the xsl.xslt file in the zip file.

The File

Had a real head scratcher of a problem with Sitecore running in integrated mode. The site in question is rather odd in that everything including the home node is secured; any anonymous visitor is redirected to the login page. They also need various URL tricks to be done which necessitated integrated mode. Putting all that together was straight forward, just a matter of denying extranet/Anonymous access to the root home node and specifying a login page followed by implementing the integrated mode fix as described here.

Oddly though the moment I viewed the site while logged out it stopped sending me to the login page and instead threw up a “Layout not Found” page. Odder still the item it said it was trying to display wasn’t the home item or even the login item but instead was the root /sitecore item. I knew something strange was happening with the ItemResolver in the httpBeginRequest pipeline so I added a custom processor and debugged it to have a look at the HttpRequestArgs.

Here is what I saw when I switched back to classic mode:

{Sitecore.Pipelines.HttpRequest.HttpRequestArgs}
    base {Sitecore.Pipelines.PipelineArgs}: {Sitecore.Pipelines.HttpRequest.HttpRequestArgs}
    Context: {System.Web.HttpContext}
    LocalPath: “/default”
    PermissionDenied: true
    RequestType: Begin
    StartPath: “/sitecore/content/home”
    Url: {Sitecore.Web.RequestUrl}

As you can see it has attempted to retrieve the home item and been denied permission. It also attempts to retrieve the /default item but this also fails as it doesn’t exist. By the end of the request the context item is still null and permission has been denied so sitecore redirects to the login page.

On the other hand here is what happens when it’s in integrated mode:

{Sitecore.Pipelines.HttpRequest.HttpRequestArgs}
    base {Sitecore.Pipelines.PipelineArgs}: {Sitecore.Pipelines.HttpRequest.HttpRequestArgs}
    Context: {System.Web.HttpContext}
    LocalPath: “/”
    PermissionDenied: true
    RequestType: Begin
    StartPath: “/sitecore/content/home”
    Url: {Sitecore.Web.RequestUrl}

In this case the ItemResolver has been denied access to the home item but then went on to retrieve the / root item and set this as the context (which of course has no layout). The difference is down to the fact that IIS is now no longer telling ASP.Net to look for a /default file in integrated mode. So the context is now set and Sitecore attempts to render it as per normal except the context item in question is the /sitecore item.

Thankfully the solution is simple; if I deny access to /sitecore and /sitecore/content then the problem is resolved. In this case the ItemResolver finishes with permission denied and a null context which means the visitor is redirected to the login page once again.

I could have skipped this whole process however if I’d not fallen for that old trap of confusing what is true for one thing been true for another. On a classic asp.net website only files beneath the site root can be accessed as webpages and although similar in Sitecore it is by no means the same thing. In Sitecore *any* item can become the context item if access is allowed, I guess I can write this off as a reminder :)

Richard Dias has already covered this topic before on his blog but I felt that the issue could do with even a few more examples of how to get custom datatypes working in sitecore.

I’ve created a firstname/secondname textfield combo which stores the data as attributes on an xml element. This is how sitecore stores data internally for situations like these, a good example been the image field. Do try switching on raw mode and having a look at how sitecore stores the various data types.

Installing the datatype is as defined in steps 10 and 11 of the SDN article, firstly you add the following to <controlSources> in web.config (don’t forget to change the namespace and assembly details):
<source mode=”on” namespace=”Project.Namespace” assembly=”Project.Assembly” prefix=”ExampleCustomDatatype”/>

And then you create a “template field type” item representing your field in “/system/field types” on the core database. The “template field type” template has 3 fields, the first 2 been the assembly and class of the control and the third requires the prefix defined in the web.config, followed by :, followed by the class name. In this case it would be ExampleCustomDatatype:ExampleCustomDatatype.

Finally below is the code that I’m using in this example:

using System;
using System.Web.UI;
using Sitecore.Shell.Applications.ContentEditor;
using Sitecore.Web.UI.HtmlControls;

namespace Project.Namespace
{
    public class ExampleCustomDatatype : Input
    {
        private XmlValue XmlValueStore
        {
            get
            {
                XmlValue viewStateProperty = base.GetViewStateProperty("XmlValueStore", null) as XmlValue;
                if (viewStateProperty == null)
                {
                    viewStateProperty = new XmlValue(string.Empty, "ExampleCustomDatatype");
                    this.XmlValueStore = viewStateProperty;
                }
                return viewStateProperty;
            }
            set
            {
                base.SetViewStateProperty("XmlValueStore", value, null);
            }
        }

        public override string Value
        {
            get
            {
                return XmlValueStore.ToString();
            }
            set
            {
                XmlValueStore = new XmlValue(value, "ExampleCustomDatatype");
            }
        }

        private string FirstName
        {
            get
            {
                return XmlValueStore.GetAttribute("firstname");
            }
            set
            {
                XmlValueStore.SetAttribute("firstname", value);
            }
        }

        private string SecondName
        {
            get
            {
                return XmlValueStore.GetAttribute("secondname");
            }
            set
            {
                XmlValueStore.SetAttribute("secondname", value);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            if (!Sitecore.Context.ClientPage.IsEvent)
            {
                Text firstNameField = new Text {ID = GetID("firstName"), Value = FirstName};
                this.Controls.Add(firstNameField);

                this.Controls.Add(new LiteralControl(Sitecore.Resources.Images.GetSpacer(0x18, 16)));

                Text secondNameField = new Text {ID = GetID("secondName"), Value = SecondName};
                this.Controls.Add(secondNameField);
            }
            else
            {
                Text firstNameField = FindControl(GetID("firstName")) as Text;
                Text secondNameField = FindControl(GetID("secondName")) as Text;
                if (firstNameField != null)
                {
                    if (FirstName != firstNameField.Value)
                    {
                        this.TrackModified = true;
                        this.SetModified();
                    }
                    FirstName = firstNameField.Value;
                }
                if (secondNameField != null)
                {
                    if (SecondName != secondNameField.Value)
                    {
                        this.TrackModified = true;
                        this.SetModified();
                    }
                    SecondName = secondNameField.Value;
                }
            }
            base.OnLoad(e);
        }
    }
}

Once all is said and done you can add the new field type to a template and try editing in an item. You should see two plain text fields and when you enter say “Steve” into the first and “Green” into the second you will see the following in raw mode:

<ExampleCustomDatatype firstname=”Steve” secondname=”Green” />

Finally you can pull the content out in just the same way you would with any other field that stores data as attributes in an xml element:

<xsl:value-of select=”sc:fld(‘fieldname’,.,’firstname’)”/>

<xsl:value-of select=”sc:fld(‘fieldname’,.,’secondname’)”/>

Workmate of mine Adam Rambridge sent around an excellent survey on monday asking what best practices we recommend for sitecore projects. Instead of writing up a blog post this week I’ve taken the easy route and just copy/pasted the results ;)

Question Answer
Your name Steve Green

Information architecture

How best to structure templates? Typically I would break the templates down into 3 folders, field sections, page types and meta data.Field sections are reusable collections of fields such as title/text, meta tags, navigation that are inherited by page types.Page type templates are for items that are under the home node, ideally they are the only templates to have presentation values.Meta data templates are for items outside the web context which are typically stored in the global folder. These cover things such as reusable rich text blocks, control labels and configuration, dropdown menu sources and other content that doesn’t ‘belong’ to the content items.
How should the content structure be organised? I’d recommend prefacing your template names with a short signifier, so ABC_ or Comp_, this is so the client can later develop other websites and easily distinguish between the templates meant for one over the other.All content under the home item should represent a page and have valid presentation. All other content should be stored within the global folder which is a sibling item to the root home node.
Is this good practice that we should use on all projects? 90% of the best practices we typically use can be applied as-is without modification. I would prefer to see at least some attempt made to consistency.
Are there disadvantages to this scheme? None, you should only be doing it if it makes sense, if it doesn’t then you’re not doing anyone any favours.
Are there better ways? Indubitably, I hope to find them out ;)
How should you decide when to store items in a global folder rather than under the home node? Only content that “belongs” to the item should be present. The approach to organising sitecore content should be functionally similar to database normalization. It should be in global folders if the content in question isn’t “owned” by the context item, this covers both things like sidemenu RTE blocks, control labels or if there is a many-to-one relationship of some sort.
Text that goes with a control or sublayout We did try name/value pairs for a while but frankly these suck. I’ve now switched to a set of custom configuration templates, one per rendering or sublayout. They have 2 sections, one for labels and one for configuration. The configuration node is set at the top of the renderings as a variable and as a private property on the sublayouts. I’ve been planning on automating this at some point however.Something which I don’t do but it worth considering is using the parameters templates which were introduced in 6.1. I’m not sure how usable this is for the content editors however, letting them go into the presentation interface is dangerous at the best of times.

Naming

Naming fields and field sections Field names should be programmatically sound with friendly names added later.
Naming templates, layouts, renderings etc. ProjectAcronym_TemplateName typically. Folders used as much as possible (note, not supported in workflows).
Name prefixes See above.
What other advice would you give on naming items? Clear, concise and SEO friendly. In the case of sublayouts and renderings make sure the item name matches the file name.

Project structure

What is the ideal structure for a Sitecore project? Start with the standard 4, Website, Business, Data and Tests. You’ll almost always end up creating them so why not do it from the start. Otherwise you tend to bloat up the website project with helper classes only to have to refactor later.
What are the worst mistakes that should be avoided? Omnidirectional project references, untilize dependency injection where possible.

Sitecore ORMs

What do you think about Sitecore ORMs? Tears, wailing, gnashing of teeth. Contentious issue but personally I think the issues it’s trying to solve are not as big as the problems it causes.
What problems does it solve? Very very good question. It’s can be cool that’s for sure. Templates as object, intelisense on your fields, that’s lovely. Then you run into the hell of lazy loading, caching and often a gradual and inexplicable delta between the database and the in memory objects.
Does it cause any problems of its own? See above.
Would you use shared source Domain Objects instead? Why? Never tried it to be honest.

Sublayouts and renderings

How do you decide whether to use one over the other? It’s not very scientific but I use the rule of thumb that if it’s not easy it’s time to switch to a sublayout. XSLT should make your life easier, not harder.
Are there dangers of too much reliance on XSLT? There can be issues with refactoring, due to its reliance on referencing items by paths and fields by names. I’ve got some grand ideas to help resolve that however via xslt helpers.
Are there dangers of too much reliance on sublayouts? Sitecore is designed with xslt in mind, if you use sublayouts where a simple xslt rendering could have done you’ve missed a trick.
Is one easier to maintain that the other? Loaded question. Ask someone who needs to rename every reference to an item by path and you’ll get one answer. Ask somone who needs to pull out a faulty ORM and you’ll get another. I think like most things you need a healthy balance really.

Testing

Can Sitecore projects benefit from unit testing? Strictly speaking no, Sitecore itself is impossible to properly unit test. Integration and stress testing however is vital.
WatiN? A recursive Watin test for the whole site to check for standard errors (missing presentation, failed xslt etc) should be standard on all sitecore sites.
What holds us back from doing more testing? Time, and occasional false perception of there not been enough time.

What else?

What factors cause sitecore projects to go well? When the site is been developed as a sitecore site, see next question for more.
What factors cause sitecore projects to go badly? When a site is been developed as something else. Sitecore projects typically fail when someone is trying to code something else into the system. Sitecore can be an application framework, but you’d be better off with MVC. Sitecore can be made to act like any other CMS or legacy system, but you’d be better off not doing it that way. Sitecore always *CAN*, but you probably shouldn’t.
What other questions should this survey have asked? I’m sure we can think up enough for a sequal at some point. This survey though was exhaustive and excellent, cheers ;)

 

 

Love to see what other peoples answers would be, if you do end up posting your answers online make sure you post a link to in the comments :)

layoutnotfound

Layout not found, never a good look. Despite all efforts to not link to items lacking presentation the only sure-fire way to prevent this is to simply not have any; everything under the home node should have *some* kind of presentation applied. In every case where someone has said “don’t worry, there is no way they could reach that item” they always have linked to it or found that users actively change the urls to it (happens more than you’d expect).

The biggest offender for zero presentation is the common garden variety /sitecore/templates/Common/Folder. It’s not uncommon to see deeply nested sets of folders in order to create more content rich urls, it is after all part of the SEO holy trinity of url, title and header. My replacement for this is what I call the bump folder, not the best of names but it has stuck. It’s straightforward to implement and dead easy for content editors to use, the bump folder simply 301 redirects the user to either the parent item or the item selected in a droplink.

First step is to create a new template in your solution and add the following field:

bumpfoldertemplate

This is a single droplink field called Target and I’ve ticked shared as it’s language invariant (or at least likely to be, just untick if it’s going to change based on language). The interesting bit to note here is the source, you can not only supply paths but also sitecore queries. In this case the query used is “query:./*[@@tid!=../@@tid]” which means “Select all child items which are not bump folders”. The reason I avoid linking up to bump folders is to avoid 301 daisy chaining or even worse 301 loops (where the folder linked to has no target set and 301 redirects to the parent item). I’m also using a drop list instead of a general link so as to avoid the folders turning into aliases and creating the website equivalent of spaghetti code.

The only thing to add now is a layout item (and aspx file) and assign it to the presentation for the bump folder. In the codebehind for the layout add the following:


protected void Page_PreInit(object sender, EventArgs e) { 
  LookupField target = Sitecore.Context.Item.Fields["target"]; 
  if(target.TargetItem != null
    Response.Redirect(target.TargetItem.GetFriendlyUrl()); 
  Response.Redirect(Sitecore.Context.Item.Parent.GetFriendlyUrl());
}

Done, I know it’s not exactly ground breaking stuff but it’s little things like this that can really make a big difference to a Sitecore project.

Update: 27th September 2009

Doh, forgot to add that I’m using a set of extension methods alongside my solution, GetFriendlyUrl() in this case is actually an extension method.

public static string GetFriendlyUrl(this Item item)
{
    return LinkManager.GetItemUrl(item);
}

Also as pointed out by Thomas Eldblom these bump folders shouldn’t preclude the development of “fit for purpose” container items. They’re simply for content editors to organise their content into more useful hierarchies. Thomas also has some good pointers on how to manage your errors in general, see the comments for more details.

Adding little “traffic light” labels to the top of your renderings and sub-layouts can really help both the customer and other developers see how the site is progressing. Just a small span at the top of the file containing its name and a css class for its status will do the trick:

<span class="devlabel red">homepage_flashbanner.ascx</span>

The problem you run into is that the style tags often interfere with the layout of the page or just don’t show up correctly at all:

before

It can be worse than this, often you’ll find that simply adding these spans will throw the whole page into a shambles.

The solution is to turn to the as always awesome jQuery. Start by adding the following script to the bottom of your main layout file:

<script type="text/javascript">
jQuery(document).ready(function() {
   jQuery(".devlabel").each(function(n) {
      var label = jQuery(this);
      var target = label.next();
      var pos = target.offset();
      var left = pos.left + "px";
      var top = -12 + pos.top + "px";
      label.css({
         zIndex: 5000,
         left: left,
         top: top
      });
   });
 });
</script>

Make sure the CSS class for the label is set to absolute positioning as so:

.devlabel
{
	font-size:8px;
	position:absolute;
}
.red
{
	color:red;
}
.orange
{
	color:orange;
}
.green
{
	color:green;
}

What that jQuery will do is search for any labels with the ‘devlabel’ class and position them directly above the very next element. It should end up looking more like this:

after

Then of course as your project progresses you can change the color of the traffic lights, red for not started, orange for in progress and green for finished (and tested!). Quite satisfying to watch them slowly turn green one by one :)

progress

I’ve been adding these ‘traffic lights’ to my projects for quite a while now, the only issue really is having to remove them at the end of the project (for SEO purposes they’re a big no no). This has given me inspiration for possibly writing a pipeline handler to automate the process, instead of using the traffic light colors it could instead output the name and Sitecore UI icons of the various renderings and sub-layouts. Once I have the details sorted I’ll be sure to post an update.

When you’ve got larger Sitercore installs where there is a team of graphic artists dedicated to maintaining the media library you can get cases of content editors linking to images that haven’t been published yet.

Off the back of those kind of situations I wrote a custom validator to test if the item is published on any of the target databases. It could easily be repurposed for any of the link fields and the warning could be raised to an error if needed.

using System.Collections.Generic;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Data.Validators;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.SecurityModel;
using Sitecore.Shell.Applications.ContentEditor;
namespace example
{
    public class UnpublishedMediaValidator : StandardValidator
    {
        protected override ValidatorResult Evaluate()
        {
            ItemUri itemUri = base.ItemUri;
            if (itemUri != null)
            {
                Field field = base.GetField();
                if (field == null)
                    return ValidatorResult.Valid;
                string str = field.Value;
                if (string.IsNullOrEmpty(str))
                    return ValidatorResult.Valid;
                if (string.Compare(str, "<image />") == 0)
                    return ValidatorResult.Valid;
                string itemId = new XmlValue(str, "image").GetAttribute("mediaid");
                if (string.IsNullOrEmpty(itemId))
                    return ValidatorResult.Valid;
                Database currentDatabase = Factory.GetDatabase(itemUri.DatabaseName);
                Assert.IsNotNull(currentDatabase, itemUri.DatabaseName);
                Item localItem = currentDatabase.GetItem(itemId);
                if (localItem == null)
                    return ValidatorResult.Valid;
                foreach(Database targetDatabase in GetTargets(localItem))
                {
                    Item targetItem = targetDatabase.GetItem(localItem.ID);
                    if(targetItem == null)
                    {
                        base.Text = Translate.Text("The field \"{0}\" links to an unpublished item.", new object[] { field.DisplayName });
                        return base.GetFailedResult(ValidatorResult.Warning);
                    }
                }
            }
            return ValidatorResult.Valid;
        }
        private List<Database> GetTargets(Item item)
        {
            using (new SecurityDisabler())
            {
                Item item2 = item.Database.Items["/sitecore/system/publishing targets"];
                if (item2 != null)
                {
                    List<Database> list = new List<Database>();
                    foreach (Item item3 in item2.Children)
                    {
                        string name = item3["Target database"];
                        if (name.Length > 0)
                        {
                            Database database = Factory.GetDatabase(name, false);
                            if (database != null)
                            {
                                list.Add(database);
                            }
                            else
                            {
                                Log.Warn("Unknown database in PublishAction: " + name, this);
                            }
                        }
                    }
                    return list;
                }
            }
            return new List<Database>();
        }
        protected override ValidatorResult GetMaxValidatorResult()
        {
            return base.GetFailedResult(ValidatorResult.Warning);
        }
        public override string Name
        {
            get
            {
                return "Unpublished Items.";
            }
        }
    }
}

Implementing it is fairly straight forward, just compile the code, create a new Validation Rule item in /sitecore/system/Settings/Validation Rules/Field Rules/ (namespace.class,assembly) and add to the Validator Bar rule on the Image Field Type in /sitecore/system/Settings/Validation Rules/Field Types/Image

As I said it would be easy to repurpose this for any link type, useful in conjunction with more complex workflows.

This is something I see come up a lot when developing Sitecore websites, how best to reference your items, by path or by guid. Almost every method in the Sitecore API will accept both path and guid as will xslt (paths often been XPATH statements in that case). Both have their pros and cons and both are more suited for particular situations that the other.

The biggest benefit of paths is their human readability, even a non-technical person can find an item based on its path. If however you’ve spent a whole project referencing items by path and you need to change the site item hierarchy you’ll run afoul of a potential refactoring nightmare, doubly so if those paths are created dynamically. Guids on the other hand are the exact opposite, they’re essentially immune to 90% of those refactoring issues but they’re otherwise uttering incomprehensible (i.e. 5EBC6046-5012-4C78-BAC9-5852A8E26918)

So the long and short of it is that it would be nice to use guids everywhere for more robust code but you’ll need to hope everyone remembers to put a friendly comment in explaining what the guid is for. The middle ground solution I’ve found which really nails the issue for everything but xslt (more on that later) is a static settings class like below:

using Sitecore.Data;
namespace Example.Business
{
    public static class SiteSettings
    {
        public static class TemplateIds
        {
            public static TemplateID Client { get { return new TemplateID( new ID("5EBC6046-5012-4C78-BAC9-5852A8E26918"));} }
            public static TemplateID Branch { get { return new TemplateID( new ID("{35E75C72-4985-4E09-88C3-0EAC6CD1E64F}"));} }
            public static TemplateID Fees { get { return new TemplateID(new ID("{334CA6C3-B6CB-4A86-80C4-1BD1892408BB}")); } }
            public static TemplateID Service { get { return new TemplateID(new ID("{2FB9F53A-CCE2-4873-A376-BE1984FE0DDB}"));} }
            public static TemplateID Section { get { return new TemplateID(new ID("9F9AE8B7-159D-468E-9732-68BB7E9D53A4")); } }
            public static TemplateID Article { get { return new TemplateID(new ID("CCDAE7B5-656C-4E64-90D1-7A6BDC66C697")); } }
            public static TemplateID Author { get { return new TemplateID(new ID("D3B7113E-639E-494C-8F4D-65A4CADCE11A")); } }
        }
        public static class ItemIds
        {
            public static ID ArticleRoot{ get { return new ID("7438EA73-B93A-476E-B6A0-9FE4C382AE66"); } }
            public static ID Branches { get { return new ID("BAD98E0E-C1B5-4598-AC13-21B06218B30C"); } }
            public static ID SiteRoot { get { return new ID("D3978CE5-BBC7-4201-9D53-46B53E039365"); } }
        }
        public static class WorkflowIds
        {
            public static ID NewSection { get { return new ID("1FE1D278-6463-47AD-9813-E82C82F87753"); } }
            public static ID NewComponent { get { return new ID("777348EE-A748-47EC-B771-9BC0F5A0C636"); } }
        }
        public static class WorkflowStateIds
        {
            public static ID LoginDetailsSent { get { return new ID("DE94B240-198D-40BE-8621-236EF74DB395"); } }
            public static ID Approved { get { return new ID("3521F34D-F15D-404D-9EAB-DF124F89EE56"); } }
        }
    }
}

Straight forward and simple, the only downside is that it cant be used for your xslt renderings but more on that later…

« Previous PageNext Page »

Follow

Get every new post delivered to your Inbox.