Disable HTML Caching in Sitecore

Published by on
Tags:

I need a quick way to disable HTML caching on a Sitecore server. I didn't want to mess around with the sites setting because I wanted something a little more generic.

You might be tempted to set Caching Enabled to false.

    <!--  CACHING ENABLED
            Determines if caching should be enabled at all
            Specify 'true' to enable caching and 'false' to disable all caching
      -->
        <setting name="Caching.Enabled" value="true" />

However changing this to false will cause your site to never load! A better solution is to use the HTML Lifetime setting:

      <!--  HTML LIFETIME
            The lifetime of HTML fragments added to the cache.
            Default value: 00:00:00 (ie. eternal life)
      -->
    <setting name="Caching.HtmlLifetime" value="00:00:00" />

Change this from 00:00:00 to 00:00:01.

Niceforms and Checkbox changed events

Published by on
Tags:

It seems that the Niceforms JavaScript does not raise the onchange event of the original checkbox when the checkbox image is clicked.

To correct this problem, and assuming you are using jQuery you need to find the inputCheck function in the NiceForms.js file. Then update the el.dummy.click function as follows:

       el.dummy.onclick = function() {
		if(!this.ref.checked) {
			
			this.ref.checked = true;
			$(this.ref).change(); //added
			this.className = "NFCheck NFh";
		}
		else {
		
			this.ref.checked = false;
			$(this.ref).change(); //added
			this.className = "NFCheck";
		}
	}

Sitecore OMS Multivariate Tests and Sublayouts

Published by on
Tags:

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.

Using a default language in Sitecore 6.2

Published by on
Tags:

I had written a previous blog about setting up a default language for Sitecore, however this was for Sitecore 5.3.x . The Sitecore 6 API is slightly different. I have detailed the Sitecore 6 solution below.

Firstly create the following class:


    public class SqlServerDataProvider : Sitecore.Data.SqlServer.SqlServerDataProvider
    {

        public SqlServerDataProvider(string connectionString)
            : base(connectionString)
        {
        }
        protected override void LoadItemFields(string itemCondition, string fieldCondition, object[] parameters, Sitecore.Collections.SafeDictionary prefetchData)
        {
            base.LoadItemFields(itemCondition, fieldCondition, parameters, prefetchData);

            //set the default language to use
            Language defaultLang;
            Language.TryParse("en", out defaultLang);

            //full list of languages the site uses
            LanguageCollection coll = this.GetLanguages();

            foreach (var data in prefetchData)
            {
                if (data.Value != null)
                {
                    var uris = data.Value.GetVersionUris();
                    //check the item contains the default language before doing anything
                    if (uris.Cast().Any(x => x.Language == defaultLang))
                    {
                        //get the default language fields 
                        var defaultUri = uris.Cast().First(x => x.Language == defaultLang);
                        //loop through each language
                        foreach (Language lang in coll)
                        {
                            //check if language doesn't exist
                            if (!uris.Cast().Any(x => x.Language == lang))
                            {
                                //update language with default language values
                                FieldList fields = data.Value.GetFieldList("en", defaultUri.Version.Number);
                                foreach (var key in fields.GetFieldIDs())
                                {
                                    data.Value.AddField(lang.Name, 1, key, fields[key]);
                                }



                            }
                        }
                    }
                }
            }
        }
    }

The main difference is the change in the for loop. In Sitecore 5.3.x the GetFieldsList method returned a collection of field objects that had two properties, the Key which was the field name and a Value property. This has been replaced with an object that wraps a HashList of ID's and Values. This makes more sense since field names could be change and break code but ID's will be consistent.

FieldList fields = data.Value.GetFieldList("en", defaultUri.Version.Number);
foreach (var key in fields.GetFieldIDs())
{
  data.Value.AddField(lang.Name, 1, key, fields[key]);
}

The XML describing the data provider in the web.config has also changed, add the provider detailed below:


      
$(1)
$(1)

Then alter the provider used by the database from:


  $(id)
  Network/16x16/earth.png
  true
  
    

An update the the provider to:

  $(id)
  Network/16x16/earth.png
  true
  
    

Create Sitecore Database User

Published by on
Tags:

This script creates a SQL Server database user for the Sitecore 6.2 databases manually. You will need to find and replace %username% and %password% with your values.

CREATE LOGIN %username% WITH PASSWORD = '%password%'

USE Sitecore_Master
GO

CREATE USER %username% FOR LOGIN %username%
GO

GRANT EXECUTE TO %username%
GO

sp_addrolemember 'db_datareader', '%username%'
GO

sp_addrolemember 'db_datawriter', '%username%'
GO

USE Sitecore_Web
GO

CREATE USER %username% FOR LOGIN %username%
GO

GRANT EXECUTE TO %username%
GO

sp_addrolemember 'db_datareader', '%username%'
GO

sp_addrolemember 'db_datawriter', '%username%'
GO

USE Sitecore_Master
GO

CREATE USER %username% FOR LOGIN %username%
GO

GRANT EXECUTE TO %username%
GO

sp_addrolemember 'db_datareader', '%username%'
GO

sp_addrolemember 'db_datawriter', '%username%'
GO
 

Projects

Have you read?

Sitecore Sheer XAML Applications - Part 2 - Input Popup Box



Blogs by date