fixing WFFM tracking field

After installing a the new version of WFFM (8.2) we were seeing broken links on existing form items. Thanks to the lovely broken links gutter, to guide us to this mistake.

After some googling, as any self respecting developer does when facing a problem for the first time, I found this blog post. It seems that the custom XML being stored as the raw value of the Tracking field has had an update in the newer WFFM versions. As suggested in the blog, one way to fix this is by opening the attributes and goals of the tracking field and clicking OK, without making any changes. This updates the XML and as if by magic the gutter disappears.

So what changed in the raw values? Well in the new version, the events now have an ID attribute. Here is an example of the raw values before the “fix”:

1
2
3
4
5
6
7
<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>

And the raw values afer the “fix”:

1
2
3
4
5
6
7
<tracking>
<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" />
<event id="{AA3AE715-E87D-4B4D-80C7-4290546F770F}" name="Field Changed" />
<event id="{F0113A93-570A-4F69-8C7C-BA08037D1E34}" name="Field Completed" />
</tracking>

Since I didn’t feel like clicking a thousand times to update 400+ forms (older versions are forms too!) I wrote an admin page to fix it. Here’s the code I used. It might not be the cleanest, but it gets the job done. Just save it as an .ASPX file in your site under /sitecore/admin and you are good to go.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<%@ Page Language="C#" %>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="Sitecore.ContentSearch" %>
<%@ Import Namespace="Sitecore.ContentSearch.SearchTypes" %>
<%@ Import Namespace="Sitecore.Data" %>
<%@ Import Namespace="Sitecore.Data.Items" %>
<script runat="server" type="text/C#">
private bool authorized = false;
private string UnauthorizedMessage = "You are not authorized to view this page";
protected void Page_Load(object sender, EventArgs e)
{

if (!(true
//&& Request.IsSecureConnection // Check for HTTPS
&& Request.UserHostAddress == "127.0.0.1"
&& Sitecore.Context.IsLoggedIn
&& Sitecore.Context.IsAdministrator
//&& Sitecore.Context.User.IsInRole(@"sitecore\Developer") //check for specific role
))
{
Response.StatusCode = (int) System.Net.HttpStatusCode.Forbidden;
Response.Write(UnauthorizedMessage);
Response.TrySkipIisCustomErrors = true;
Response.End();
return;
}
else
{
authorized = true;
}

}

protected void FixFields_OnClick(object sender, EventArgs e)
{

if (!authorized)
{
output.InnerHtml = string.Format("<div style=\"color:red;\">{0}", UnauthorizedMessage);
return;
}
ID formTemplateId = new ID("{FFB1DA32-2764-47DB-83B0-95B843546A7E}");
ID contenTreeId = new ID("{0DE95AE4-41AB-4D01-9EB0-67441B7C2450}");
ISearchIndex index = ContentSearchManager.GetIndex("sitecore_master_index");
string TrackingFieldName = "__tracking";
int changeCount = 0;
int errorCount = 0;
output.InnerHtml += "<div>Starting update of fields</div>";

Dictionary<string, string> replacements = GetReplacements();
List<Item> indexResults = null;
using (IProviderSearchContext context = index.CreateSearchContext())
{
indexResults = context.GetQueryable<SearchResultItem>()
.Where(x => x.TemplateId == formTemplateId
&& x.Paths.Contains(contenTreeId))
.Select(x => x.GetItem()).ToList();

indexResults = indexResults.Where(x => x != null).Where(x => x.Fields[TrackingFieldName] != null).ToList();
if (!indexResults.Any())
{
output.InnerHtml += "<div>No Form items found to modify. </div>";
return;
}

foreach (Item item in indexResults)
{
try
{
string value = item.Fields[TrackingFieldName].Value;
foreach (var dictionaryItem in replacements)
{
value = value.Replace(dictionaryItem.Key, dictionaryItem.Value);
}

item.Editing.BeginEdit();
using (new EditContext(item))
{
item.Fields[TrackingFieldName].Value = value;
output.InnerHtml += string.Format("<div>Item - {0} - changed</div>", item.Name);
}
item.Editing.EndEdit();
changeCount++;
}
catch (Exception ex)
{
output.InnerHtml += string.Format("<div>Item - {0} - {1}</div>", item.Name, ex.Message);
errorCount++;
}
}
}
output.InnerHtml += string.Format("<div>Update of tracking fields finished. {0} items modified, {1} errors ocurred. </div>", changeCount, errorCount);

}

private Dictionary<string, string> GetReplacements()
{
Dictionary<string, string> replacements = new Dictionary<string, string>();
replacements.Add("<event name=\"Field Changed\" />", "<event id=\"{AA3AE715-E87D-4B4D-80C7-4290546F770F}\" name=\"Field Changed\" />");
replacements.Add("<event name=\"Field Completed\" />", "<event id=\"{F0113A93-570A-4F69-8C7C-BA08037D1E34}\" name=\"Field Completed\" />");
replacements.Add("<event name=\"Field Not Completed\" />", "<event id=\"{7E86B2F5-ACEC-4C60-8922-4EB5AE5D9874}\" name=\"Field Not Completed\" />");
replacements.Add("<event name=\"Field Out of Boundary\" />", "<event id=\"{F3D7B20C-675C-4707-84CC-5E5B4481B0EE}\" name=\"Field Out of Boundary\" />");
replacements.Add("<event name=\"Invalid Field Syntax\" />", "<event id=\"{844BBD40-91F6-42CE-8823-5EA4D089ECA2}\" name=\"Invalid Field Syntax\" />");

return replacements;
}
</script>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>WFFM 8.2 fix tracking field</title>
</head>
<body>
<form id="trackingUpdater" runat="server">
<h3>Update tracking field for WFFM form items</h3>
<div style="margin-left:15px;">
Click the button below to fix the Tracking field for WFFM forms. This will add ID attributes to the selected items in this field.
Modify the dictionary to replace more/less as needed.
<br/><br/>
<asp:Button runat="server" ID="FixFields" OnClick="FixFields_OnClick" Text="Update form tracking field" />
</div>
<div id="output" runat="server" style="width: 1000px; height: 500px; overflow-scrolling: auto;">
</div>
</form>
</body>
</html>

The dictionary can be easily expanded in case you selected any other goals or attributes in this field. I only added the ones that I had selected in my forms.