Saturday 25 June 2016

Error in event item:saved when migrating old WFFM items by Razl

Last time when I was upgrading another website from version 6.5 to 8.1, I have faced the problem with WFFM forms. I was transferring all content from old database to new one, using Razl. Almost everything went OK, but WFFM Form items.

The error I got, was rather misterious:



18684 11:12:39 ERROR One or more exceptions occurred while processing the subscribers to the 'item:saved' event.
Exception[1]: System.FormatException
Message[1]: Unrecognized Guid format.
Source[1]: mscorlib
   at System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String failureArgumentName, Exception innerException)
   at System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result)
   at System.Guid..ctor(String g)
   at Sitecore.Analytics.Data.TrackingField.<>c__DisplayClass21.b__20(XElement e)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at Sitecore.Analytics.Data.TrackingField.ValidateLinks(LinksValidationResult result)
   at Sitecore.Links.ItemLinks.AddLinks(Field field, List`1 links, ItemLinkState linkState)
   at Sitecore.Links.ItemLinks.GetLinks(ItemLinkState linkState, Boolean allVersions, Boolean includeStandardValuesLinks)
   at Sitecore.Links.SqlLinkDatabase.UpdateItemVersionReferences(Item item)
   at Sitecore.Links.ItemEventHandler.OnItemSaved(Object sender, EventArgs args)
   at Sitecore.Events.Event.EventSubscribers.RaiseEvent(String eventName, Object[] parameters, EventResult result)


18684 11:12:39 ERROR Razl service error
Exception: System.AggregateException
Message: One or more exceptions occurred while processing the subscribers to the 'item:saved' event.
Source: Sitecore.Kernel
   at Sitecore.Events.Event.EventSubscribers.RaiseEvent(String eventName, Object[] parameters, EventResult result)
   at Sitecore.Events.Event.RaiseEvent(String eventName, Object[] parameters)
   at Sitecore.Events.Event.RaiseItemSaved(Object sender, ItemSavedEventArgs args)
   at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
   at Sitecore.Data.Engines.EngineCommand`2.RaiseEvent[TArgs](EventHandler`1 handlers, Func`2 argsCreator)
   at Sitecore.Data.Engines.EngineCommand`2.Execute()
   at Sitecore.Data.Engines.DataEngine.SaveItem(Item item)
   at Sitecore.Data.Managers.ItemProvider.SaveItem(Item item)
   at Sitecore.Data.Managers.PipelineBasedItemProvider.ExecuteAndReturnResult[TArgs,TResult](String pipelineName, String pipelineDomain, Func`1 pipelineArgsCreator, Func`1 fallbackResult)
   at Sitecore.Data.Managers.PipelineBasedItemProvider.SaveItem(Item item)
   at Sitecore.Data.Items.ItemEditing.AcceptChanges(Boolean updateStatistics, Boolean silent)
   at Sitecore.Data.Items.EditContext.Dispose()
   at HedgehogDevelopment.Razl.Service.RazlService.SetItemDetails(Guid accessGuid, String database, Guid itemId, ItemDetails itemDetails)

It was really confusing for me. Later, I realized that it was caused by value of field Tracking in Personalization section. In my old database the value was:

<tracking>
     <event name="Field Changed" />
     <event name="Field Completed" />
     <event name="Field Not Completed" />
     <event name="Field Out of Boundary" />
     <event name="Invalid Field Syntax" />
</tracking>

In new version those events need an id parameter, not only name.

I decided to prepare that items by hand and put them in Sitecore package. I really wanted to make it all automated, but on the other hand, that solution wasn't really bad.

So I prepared that field in a way like this (Tracking field in 8.1 is in Advanced section):

<tracking>
    <event id="{AA3AE715-E87D-4B4D-80C7-4290546F770F}" name="Field changed" />
    <event id="{F0113A93-570A-4F69-8C7C-BA08037D1E34}" name="Field Completed" />
    <event id="{7E86B2F5-ACEC-4C60-8922-4EB5AE5D9874}" name="Field Not Completed" />
    <event id="{F3D7B20C-675C-4707-84CC-5E5B4481B0EE}" name="Field Out of Boundary" />
    <event id="{844BBD40-91F6-42CE-8823-5EA4D089ECA2}" name="Invalid Field Syntax" />
</tracking>

And it works :)


Thursday 9 June 2016

WFFM - Creating custom hidden field with Context Item ID

Last time I was creating article comment functionality using Web Forms For Marketers. I have designed it that all comments was saved as Sitecore items and put into bucket in specified location. One of the problems was to put some information about article we are commenting.

I have chose Sitecore ID to be put inside that comment item. Unfortunately I wasn't able to do it out-of the-box. I needed to write some custom code and I thought that custom WFFM field would be the best idea.

WFFM version I was using was 8.1 rev. 151217 (Update-1). It's code changes very frequently so tutorials found in internet was a bit of outdated (very probably that mine will be soon too ;)).

I decided that the best and pretty easy way, will be create control that will put hidden html field and populate it with context item ID. I was told that the best way to achieve it will be create derivative from SingleLineText field. Tools like ILSpy or dotPeek was very helpful to take a look at the code inside. The value of Sitecore.Context.Item.ID is taken in OnLoad() method. To make it more flexible I have added field that made it switchable.

Here is the code:

using Sitecore.Form.Core.Attributes;
using Sitecore.Form.Web.UI.Controls;
using System.ComponentModel;
using System.ComponentModel.Design;
 
namespace SitecoreCoffee.WFFM.CustomFields
{
    /// <summary>
    /// Hidden Id Field
    /// </summary>
    [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design"typeof(IDesigner))]
    public class HiddenIdField : SingleLineText
    {
        private bool _isHidden = true;
 
        /// <summary>
        /// Used to switch hidden/visible
        /// </summary>
        [VisualCategory("Configuration")]
        [VisualFieldType(typeof(Sitecore.Form.Core.Visual.BooleanField))]
        [VisualProperty("Is Hidden?"10), DefaultValue("Yes")]
        public string IsHidden
        {
            get
            {
                return _isHidden ? "Yes" : "No";
            }
 
            set
            {
                _isHidden = value == "Yes";
            }
        }
 
        protected override void OnLoad(System.EventArgs e)
        {
            Text = Sitecore.Context.Item.ID.ToString();
 
            if (_isHidden)
            {
                Attributes["style"= "display: none";
            }
        }
    }
} 

If you are using MVC you should also create ViewModel for that field:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
 
namespace SitecoreCoffee.WFFM.CustomFields
{
    /// <summary>
    /// View Model for Hidden Id Field
    /// </summary>
    public class HiddenIdFieldViewModel : Sitecore.Forms.Mvc.ViewModels.Fields.SingleLineTextField
    {
        [DataType(DataType.Text)]
        public override string Value { get; set; }
 
        /// <summary>
        /// Initializes field
        /// </summary>
        public override void Initialize()
        {
            KeyValuePair<string, string> isHidden = Parameters.FirstOrDefault(x => x.Key.ToUpper() == "ISHIDDEN");
 
            if (isHidden.Value.ToUpper() != "NO")
            {
                if (!string.IsNullOrWhiteSpace(CssClass))
                {
                    CssClass += " hidden";
                }
 
                else
                {
                    CssClass = "hidden";
                }
            }
 
            ShowTitle = false;
 
            Value = Sitecore.Context.Item.ID.ToString();
        }
    }
}

The last part is to create Sitecore item. It should be added below /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types. This item should be based on template /sitecore/templates/Web Forms for Marketers/Field Type and be populated with:
  • Assembly - file name of code assembly
  • Class - class name of field type with full namespace
  • MVC Type - class name of field type view model with full namespace and its assembly name (after comma)


And it can be used in form:



Hope it will be helpful :)

Monday 6 June 2016

Issue with Final Layout and Experience Editor: The layout for the requested document was not found

Recently I have found some bug with Sitecore 8.1 Update-2 and Experience Editor.

When I add some rendering and save the page, it appears and it's all ok. But when I remove it and save, I am getting this error:

The layout for the requested document was not found



Also all Final Renderings are gone:



I have found out that when I edit 'Final renderings' field by hand, save it, and then remove all contents of this, the same issue appears.


I am resolving it by resetting the Final Layout. I think it may be some inconsistency with checking null or empty string.

I also find out that this case is known issue: https://github.com/Sitecore/Habitat/issues/136
With public reference number 108023

I have asked support about  this issue and I get a fix for that. Unfortunately it didn't help me.
However I also got an information how to workaround this issue.

There is a "Reset blank" checkbox field in __Final Renderings item. It is located in
/sitecore/templates/System/Templates/Sections/Layout/Layout/__Final Renderings
Purpose of this option is to reset field value to default when saving field is set to empty value.



And the information that I got from Support:
This is very handy in situations where it doesn’t make sense to have the field blank. And, as the initial issue led to erasing the contents of the __Final Rendering field, ticking this checkbox allows Sitecore to use the Standard Values of the item's template. And this fixes the issue.
 Hope this will be helpful for someone :)