Changing the preview date and time is not working when using Sitecore 8.1

Recently I was asked to figure out, why changing the preview date and time from the Experience Editor, using Preview mode, did not set the date correctly in the ribbon panel for the preview date.

In this blog post I'll explain what caused this issue, guiding you through my endeavours to fix it and finally what you should be aware of in the light of the things I noticed while working with this issue.

Finding the troublemaker

In order to find the troublemaker, I first had to figure out how the preview date was generated in the ribbon. In doing so, I started out by locating the DOM element that represents the preview date panel, as shown below:

The outer <div> element is the overall panel for the preview date control. In order to generate it's control layout, it uses the JavaScript file named PreviewDatePanel.js, as defined by the data-sc-require attribute. The child <div> element (the highlighted area) is the part of the control that actually shows the date information. This has a few interesting attributes:

  • data-sc-command: the command that should be executed when the button element is clicked.
  • data-sc-date: the date shown in the panel.
  • data-sc-require: the piece of JavaScript code that contains the command logic.

I found, that when the preview date panel is clicked, the following code for the command is triggered (the comments in the code are mine):

Basically, this command invokes opening a modal dialog that allows the user to set the preview date. When the dialog is opened, the command makes a request to the pipeline processor named ExperienceEditor.PreviewDate.GetPreviewDateUrl, which looks like this:

I can't help noticing that the constant SelectDateTimeUrl is exactly the same as the string being passed into the UrlString(...) instance within the ProcessRequest() method, yet the code does not use that constant. Nevertheless, this pipeline processor looks for a cookie value named sc_date for the current site context, and passes it to the dialog as an url string:

When a new preview date has been set and the user closes the dialog by clicking on the "OK" button, there is a callback function defined for the dialog and that makes a call to the pipeline processor named ExperienceEditor.PreviewDate.SetDateValue. This pipeline processor looks like this:

What all this code does, is that it grabs the date set in the dialog, and then updates the cookie value with the newly set preview date. Once the date is set, the command makes a request to reload the window, whereas the page is reloaded.

The date that wouldn't change

After the window was reloaded things started to go wrong, as the date in the preview date panel was not being updated correctly - the date was set to 7/7/-2016 in the dialog, but the date in the ribbon remained unchanged:

When I opened the dialog once more, the date being displayed here was actually the correct date, meaning that this had to be an isolated issue on how the date value was set in preview date panel inside the ribbon.

After spending some time trying to figure out how the value was set in the preview date panel (whether it was done in javascript or server-side code), I found that there is a namespace in the Sitecore.ExperienceEditor.Speak.Ribbon assembly, that contained a lot of the control logic for the preview date panel ribbon control:

To be a bit more specific, I found the DateAndTime.cs to be quite interesting:

When the control is initialized as part of the default constructor in the method InitializeControl, the CurrentDateAndTime property is set from the cookie value stored in the browser. The actual date value is extracted using the WebEditUtil.GetCurrentDate() method, which is defined in the Sitecore.Kernel assembly:

This function tries to grab the date from the sc_date cookie for the site, by making a call to the SiteContext.GetCookieKey("sc_date") method and if it does not find a value, it sets the default return value to the current UTC date.

Finally the SiteContext.GetCookieKey() method is called, which tries to find a cookie value that is named by the convention sitename#sc_date, and returns the value of the date:

But are we getting the date from right cookie value?

In order to verify if the preview date was stored correctly in the cookie value, I looked at the cookies stored for the site. Here, I noticed that there were not one cookie value for the sc_date cookie value, but multiple; one for mysite#sc_date and one for website#sc_date:

Now, since there are multiple sitename#sc_date cookie values, which one do we get - it should be the cookie value containing the date set for the current site, right?

In order to demystify this question I started up my dotPeek symbol server, and found out that the site context was actually not the context for the site I expected, but a different site named "website" (which is the default site that comes with Sitecore). As a consequence this meant that the cookie value that was returned didn't have a date value (as it was trying to fetch website#sc_date, which was not set), and thus it returned the default value of the current date of the system, and not the date that was set from the dialog.

Doing some more research on this, I found that there are a couple of known problems when using the preview mode in Sitecore, as described in these blog posts:

Based on the advice in both blog posts, and as the solution used Sitecore 8.1, I tried to set the Preview.ResolveSite to true in order to fix the issue (if you are using a version prior to Sitecore 8.1, you'll need to include the hotfix provided by Sitecore, in order to fix this issue). However, that did not solve the problem, although it did solve some other issues in the preview mode since the site context was now set correctly.

I noticed that the URL generated when viewing the item in preview mode contained the query string parameter named sc_site=MySite, but looking back at the code for the WebEditUtil.SiteName it seems there is a problem. If you take a closer look you'll find that when the site name is resolved from the request of the current context, the request is expected to have a query string parameter named sc_pagesite - and if that is not present, it falls back to the default site for preview:

Things started to make sense, as this followed nicely along the fact that the preview worked perfectly fine for an item I created in a clean Sitecore 8.1 installation. By default, Sitecore uses the default site named "website", and since the default preview site is set explicitly to be that site, the preview date will always be set correctly. However, for other sites, the parameter is not correctly found due to the mismatch in the query string parameter name, thus the default preview site is always used - meaning that we never get to read the cookie value stored for our site.

The odd part about this was also that if I changed the query string parameter from sc_site to sc_pagesite, it still didn't work since the query string parameters are resolved internally to be without the sc_ prefix, which means that there might be even more buggy code floating around.

To sum up, based on the above observations a Sitecore Support case has been created.

While we are waiting for Sitecore Support...

While we wait for Sitecore Support to get back, you can use the workaround of changing the Preview.DefaultSite setting to the name of you site, whereas you should see the correct behaviour of setting the preview date (disclaimer: this will not work on multisite solutions!). Once I receive some feedback from Sitecore, I'll make sure to update this post with their solution to this problem.

Update from Sitecore Support

Sitecore Support have now fixed the bug, that I've been testing out and it seems to be working. Unfortunately, Sitecore currently don't have a specific article on the kb.sitecore.net site, that I can link to. This means that if you want to grab the patch, you should refer to the following reference number 82260,111553, when contacting Sitecore Support.

As always, if you have any comments or questions, please let me know in the comments section down below.