torsdag den 20. marts 2014

Sitecore 7.2, Media picker, The core database and alot of headaches

Okay, this is an interresting bug.

It seems like the new Media picker in Sitecore 7.x (the SPEAK version) has a bug - you can trigger it this way:

1: Create a template with an image field.
2: Set the source property of the field to a folder inside the media library.
3: Create an item based on this template, and click Browse on the image field.

Notice that no images from the folder is displayed.

To workaround this, the folder structure should be published to the core database (this is the real bug)......

Now, this workaround causes big problems with Sitecore 7.2, since the publishing framework has been changed, which means adding the core database as a publishing target is dangerous.

Here is a simple guide to trigger this problem:

1: Install clean Sitecore 7.2 initial release
2: Create "core" publishing target
3: Click the "Publish Item" button on the Core item
4: Select the /sitecore/layout/Layouts item
5: Click the "Publish Item" button on the Layouts item.
6: Press F5 to reload Sitecore
7: Open the content editor - you will now see "The layout cannot be found".
8: Open /sitecore/admin/dbbrowser.aspx , open the core database and see that the Layouts item no longer has any children.

This means, that if the Layouts (there are other items that is right as dangerous) item gets published to the core database - every layout defined the core database is wiped, and Sitecore is completely broken.

So, if you are using Sitecore 7.x (which you should, since it is great!), here is a better workaround untill the image picker can get fixed.

Create an include file, give it a name, os it gets loaded after Sitecore.Speak.config (Like Support.406666.config) (406666 is the issue number for this issue), and add this to it:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <overrideXmlControls>
      <override xmlControl="Sitecore.Shell.Applications.Media.MediaBrowser" with="/sitecore/client/applications/Dialogs/SelectMediaDialog">
        <patch:delete />
      </override>
    </overrideXmlControls>
  </sitecore>
</configuration>

This changes the media picker, so it reverts to using the old one, that works.

fredag den 14. marts 2014

Fixing Webforms for Marketeers saving dates in different formats

We had an issue a while ago, with a customer where their webforms started saving dates in different formats in the database, which caused the exported data to be mangled.

Sitecore Support found the solution - it seems like the DatePicker control has a bug, where the DatePicker is missing the correct adapter.

The solution is simple - create your own DatePicker class, that extends the builtin DatePicker class, like this:

[Adapter(typeof(DateAdapter))]
public class DatePicker : Sitecore.Form.Web.UI.Controls.DatePicker
{

}

Compile the code, and then go to this item in the master db: "/sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/Simple Types/Date Picker"

Here you change the Assembly and Class fields to match this class, save the item and publish it.

Done! - really, that is all there is to it - do this, and now your dates show up correct.

mandag den 3. marts 2014

Adding new renderings to an item from code

Starting with Sitecore 6.4 and forward, renderings in Sitecore is saved as deltas (differences between the standard values and the "full" rendering) on the item.

This means, that we need to do some work if we want to read, change and save the renderings.

Here is how to both read the renderings, and how to save the deltas back to the item:

public static IEnumerable<RenderingDefinition> GetRenderings(Item item, DeviceItem device)
{
    string xmlLayout = XmlDeltas.GetFieldValue(item.Fields[FieldIDs.LayoutField], XmlDeltas.WithEmptyValue("<r />"));

    LayoutDefinition layoutDefinition = LayoutDefinition.Parse(xmlLayout);
    DeviceDefinition deviceDefinition = layoutDefinition.GetDevice(device.ID.ToString());

    return deviceDefinition.Renderings.ToArray().Cast<RenderingDefinition>();
}

By using the GetFieldValue on the XmlDeltas class, we get the combined layout from the standard values combined with the delta.

Now, to be able to add a new definition to the item, here is what you have to do:

public static void InsertRendering(Item item, DeviceItem device, int index, RenderingDefinition rendering)
{
    string xmlLayout = XmlDeltas.GetFieldValue(item.Fields[FieldIDs.LayoutField], XmlDeltas.WithEmptyValue("<r />"));

    LayoutDefinition layoutDefinition = LayoutDefinition.Parse(xmlLayout);
    DeviceDefinition deviceDefinition = layoutDefinition.GetDevice(device.ID.ToString());

    deviceDefinition.Insert(index, rendering);

    using (new EditContext(item))
    {
        XmlDeltas.SetFieldValue(item.Fields[FieldIDs.LayoutField], layoutDefinition.ToXml());
    }
}

Here we get the definition for the specified device, and just insert the rendering into the passed index, moving the other renderings down the list.

Finally we edit the item, and tells it to set the value of the layout field on the item to the xml defining the entire layout.

The secret is in how SetFieldValue works, since it, behind the scenes, generates the delta between the standard values and the passed xml, and only saves that to the item.

Using this as the base, will allow you to change the renderings, since you can use the same logic to create a ChangeRendering function.