This post has been migrated from www.experimentsincode.com, we apologise if some of the images or content is missing

This post as been migrated, original date 26 Feb 2010 Sitecore have release the Online Marketing Suit. One of the nice aspects of OMS is that ability to test different page content to see which content users respond best to, this is called Multivariate testing. I quickly show how this is setup. Firstly we create a the different items that contain the content variations. So in the picture below you can see that I have three different home nodes. When the user visits the site they are taken to /sitecore/content/home but they may see content from /sitecore/content/home2 and /sitecore/content/home3. This content is injected by the multivariate test. Now I have my content the next step is to create the multivariate test. This is setup using the Marketing Centre application. For this example I have setup an incremental test strategy that simply picks the next multivariate test item to display to the user:
    public class IncrementalMultiVariateTestStrategy : IMultiVariateTestStrategy
    {
        const string _cookieName ="aegeagaegaeWeafea2";

        #region IMultiVariateTestStrategy Members

        public Item GetTestVariableItem(Item item, Item multiVariateTest)
        {

            if (!multiVariateTest.HasChildren) return null;
            int index = Cookie == -1? 0 : Cookie;

            if (index >= multiVariateTest.Children.Count) index = 0;

            Cookie = index + 1;
            return multiVariateTest.Children[index];
        }

        #endregion

        private int Cookie
        {
            get
            {
                int i = -1;

                if(HttpContext.Current.Request.Cookies[_cookieName]!= null)
                    int.TryParse(HttpContext.Current.Request.Cookies[_cookieName].Value, out i);

                return i;
            }
            set
            {
                HttpContext.Current.Response.Cookies.Add(new HttpCookie(_cookieName, value.ToString()));
            }
        }
    }
The image below shows the setup in the Marketing Centre with each test variable pointing at the relevant node. Now I just need to setup the Sample Rendering to use the test on the homepage: So publishing the site and doing a couple of refreshes we can see that the content of the sample rendering actually changes. So are multivariate test works!! Ok so it works for XSLTs but what about a sublayout? Si I have created a simple sublayout with the following code behind:
public partial class layouts_MVTest : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        output.Text = "Sublayout: " + Sitecore.Context.Item["Title"];
    }
}
I have also updated the home item to include the sublayout and set the sublayout to use the multivariate test: Ok so saving this and publishing it we now get this output: Notice how the XSLT content changes but the sublayout content does not change. So why does this happen? This is caused by how the Sublayouts and XSLTs resolve the current item. I suspect that most Sitecore developers (this is true of where I work and for myself) are used to getting the current item via Sitecore.Context.Item within a sublayout. However if you look at the code that the XSLT uses to render itself (Sitecore.Web.UI.WebControls.XslFile there is a GetItem method inherited from the Sitecore.Web.UI.WebControl class. Within this method the actual item passed to the XSLT is resolved based on the WebControl.DataSource property. The Multivariate Test actually changes the DataSource property to point at the new content item. So how do we get this value in the our Sublayout? Well we have actually look at the parent control of our user control:
Sitecore.Web.UI.WebControls.Sublayout parent = (Sitecore.Web.UI.WebControls.Sublayout)this.Parent;
string sourceItem = parent.DataSource;
This then gives us the ID of the item injected by the multivariate tests. So what does this mean in terms of development? Well if you want to use multivariate tests on a site that you already developed you will have to replace any reference to Sitecore.Context.Item with a custom solution that looks at the parents DataSource property:
    public Item Source
    {
        get
        {
            Sitecore.Web.UI.WebControls.Sublayout parent = (Sitecore.Web.UI.WebControls.Sublayout)this.Parent;
            Guid sourceItem = new Guid(parent.DataSource);
            return Sitecore.Context.Database.GetItem( new Sitecore.Data.ID(sourceItem)) ?? Sitecore.Context.Item;        }

    }
What about sub-items, for example you have the following code in your XSLT:
      <ul>
      <xsl:for-each select="./item">
        <li>
          <sc:text field="Title"></sc:text>
        </li>
      </xsl:for-each>
    </ul>
Well this actually just breaks as shown in this images below and only works when the original item is requested. The solution is to proxy the subitems below the new nodes: I have summarised the problems you will have to think about when using mutlivariate tests on your site:
  • Sitecore.Context.Item - any code that uses this reference will not pick up multivariate test content. This code will need to be changed.
  • Sub items don't exist - sub items may not exist beneath the alternative content items. You will need to recreate to proxy these items.
  • Other items will not see the alternative content. E.g. if you have a rendering in another item that relies on content in an item that is using multivariate test this item will only see the original item and not the alternative content.
The multivariate tests are a powerful addition to the Sitecore platform but if you plan to use them on your site you need to think how they will be used before you start coding. Their usage will determine how you design both your renderings and sublayouts. For simplicity it is best to only use multivariate tests on renderings and sublayouts that only have a dependency on the current item.