Home » Customization » Shoehorn Sitecore Web Forms for Marketers Field Values During a Custom Save Action

Shoehorn Sitecore Web Forms for Marketers Field Values During a Custom Save Action

Sitecore Technology MVP 2016
Sitecore MVP 2015
Sitecore MVP 2014

Enter your email address to follow this blog and receive notifications of new posts by email.

In a previous article, I discussed how one could remove Web Forms for Marketers (WFFM) field values before saving form data into the WFFM database — which ultimately make their way into the Form Reports for your form.

When I penned that article, my intentions were not to write an another highlighting the polar opposite action of inserting field values — I figured one could easily ascertain how to do this from that article.

However, last night I started to feel some guilt for not sharing how one could do this — there is one step in this process that isn’t completely intuitive — so I worked late into the night developing a solution of how one would go about doing this, and this article is the fruit of that effort.

Besides, how often does one get the opportunity to use the word shoehorn? If you aren’t familiar with what a shoehorn is, check out this article. I am using the word as an action verb in this post — meaning to insert values for fields in the WFFM database. 🙂

I first defined a utility class and its interfaces for shoehorning field values into a AdaptedResultList collection — a collection of WFFM fields:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sitecore.Sandbox.Utilities.Shoehorns.Base
{
    public interface IShoehorn<T, U>
    {
        U Shoehorn(T source);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Sitecore.Form.Core.Client.Data.Submit;

using Sitecore.Sandbox.Utilities.Shoehorns.Base;

namespace Sitecore.Sandbox.Utilities.Shoehorns.Base
{
    public interface IWFFMFieldValuesShoehorn : IShoehorn<AdaptedResultList, AdaptedResultList>
    {
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Sitecore.Diagnostics;
using Sitecore.Form.Core.Client.Data.Submit;
using Sitecore.Form.Core.Controls.Data;

using Sitecore.Sandbox.Utilities.Shoehorns.Base;

namespace Sitecore.Sandbox.Utilities.Shoehorns
{
    public class WFFMFieldValuesShoehorn : IWFFMFieldValuesShoehorn
    {
        private IDictionary<string, string> _FieldsForShoehorning;
        private IDictionary<string, string> FieldsForShoehorning 
        { 
            get
            {
                if (_FieldsForShoehorning == null)
                {
                    _FieldsForShoehorning = new Dictionary<string, string>();
                }

                return _FieldsForShoehorning;
            }
        }

        private WFFMFieldValuesShoehorn(IEnumerable<KeyValuePair<string, string>> fieldsForShoehorning)
        {
            SetFieldsForShoehorning(fieldsForShoehorning);
        }

        private void SetFieldsForShoehorning(IEnumerable<KeyValuePair<string, string>> fieldsForShoehorning)
        {
            AssertFieldsForShoehorning(fieldsForShoehorning);
            
            foreach (var keyValuePair in fieldsForShoehorning)
            {
                AddToDictionaryIfPossible(keyValuePair);
            }
        }

        private void AddToDictionaryIfPossible(KeyValuePair<string, string> keyValuePair)
        {
            if (!FieldsForShoehorning.ContainsKey(keyValuePair.Key))
            {
                FieldsForShoehorning.Add(keyValuePair.Key, keyValuePair.Value);
            }
        }

        private static void AssertFieldsForShoehorning(IEnumerable<KeyValuePair<string, string>> fieldsForShoehorning)
        {
            Assert.ArgumentNotNull(fieldsForShoehorning, "fieldsForShoehorning");

            foreach (var keyValuePair in fieldsForShoehorning)
            {
                Assert.ArgumentNotNullOrEmpty(keyValuePair.Key, "keyValuePair.Key");
            }
        }

        public AdaptedResultList Shoehorn(AdaptedResultList fields)
        {
            if (!CanProcessFields(fields))
            {
                return fields;
            }

            List<AdaptedControlResult> adaptedControlResults = new List<AdaptedControlResult>();

            foreach(AdaptedControlResult field in fields)
            {
                adaptedControlResults.Add(GetShoehornedField(field));
            }

            return adaptedControlResults;
        }

        private static bool CanProcessFields(IEnumerable<ControlResult> fields)
        {
            return fields != null && fields.Any();
        }

        private AdaptedControlResult GetShoehornedField(AdaptedControlResult field)
        {
            string value = string.Empty;

            if (FieldsForShoehorning.TryGetValue(field.FieldName, out value))
            {
                return GetShoehornedField(field, value);
            }

            return field;
        }

        private static AdaptedControlResult GetShoehornedField(ControlResult field, string value)
        {
            return new AdaptedControlResult(CreateNewControlResultWithValue(field, value), true);
        }

        private static ControlResult CreateNewControlResultWithValue(ControlResult field, string value)
        {
            ControlResult controlResult = new ControlResult(field.FieldName, value, field.Parameters);
            controlResult.FieldID = field.FieldID;
            return controlResult;
        }

        public static IWFFMFieldValuesShoehorn CreateNewWFFMFieldValuesShoehorn(IEnumerable<KeyValuePair<string, string>> fieldsForShoehorning)
        {
            return new WFFMFieldValuesShoehorn(fieldsForShoehorning);
        }
    }
}

This class is similar to the utility class I’ve used in my article on ripping out field values, albeit we are inserting values that don’t necessarily have to be the empty string.

I then defined a new WFFM field type — an invisible field that serves as a placeholder in our Form Reports for a given form. This is the non-intuitive step I was referring to above:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

using Sitecore.Diagnostics;

using Sitecore.Form.Web.UI.Controls;

namespace Sitecore.Sandbox.WFFM.Controls
{
    public class InvisibleField : SingleLineText
    {
        public InvisibleField()
        {
        }

        public InvisibleField(HtmlTextWriterTag tag) 
            : base(tag)
        {
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            HideControls(new Control[] { title, generalPanel });
        }

        private static void HideControls(IEnumerable<Control> controls)
        {
            Assert.ArgumentNotNull(controls, "controls");

            foreach (Control control in controls)
            {
                HideControl(control);
            }
        }

        private static void HideControl(Control control)
        {
            Assert.ArgumentNotNull(control, "control");
            control.Visible = false;
        }
    }
}

I had to register this new field in WFFM in the Sitecore Client under /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/Custom:

invisible-field

Next, I created a custom field action that processes WFFM fields — and shoehorns values into fields where appropriate.

In my example, I will be capturing users’ browser user agent strings and their ASP.NET session identifiers — I strongly recommend defining your field names in a patch config file, although I did not do such a step for this post:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;

using Sitecore.Data;
using Sitecore.Form.Core.Client.Data.Submit;
using Sitecore.Form.Submit;

using Sitecore.Sandbox.Utilities.Shoehorns;
using Sitecore.Sandbox.Utilities.Shoehorns.Base;

namespace Sitecore.Sandbox.WFFM.Actions
{
    public class ShoehornFieldValuesThenSaveToDatabase : SaveToDatabase
    {
        public override void Execute(ID formId, AdaptedResultList fields, object[] data)
        {
            base.Execute(formId, ShoehornFields(fields), data);
        }

        private AdaptedResultList ShoehornFields(AdaptedResultList fields)
        {
            IWFFMFieldValuesShoehorn shoehorn = WFFMFieldValuesShoehorn.CreateNewWFFMFieldValuesShoehorn(CreateNewFieldsForShoehorning());
            return shoehorn.Shoehorn(fields);
        }

        private IEnumerable<KeyValuePair<string, string>> CreateNewFieldsForShoehorning()
        {
            return new KeyValuePair<string, string>[] 
            { 
                new KeyValuePair<string, string>("User Agent", HttpContext.Current.Request.UserAgent),
                new KeyValuePair<string, string>("Session ID", HttpContext.Current.Session.SessionID)
            };
        }
    }
}

I then registered my new Save to Database action in Sitecore under /sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Save Actions:

shoehorn-save-to-db

Let’s build a form. I created another random form. This one contains some invisible fields:

another-random-form

Next, I mapped my custom Save to Database action to my new form:

another-random-form-add-save-to-db-action

I also created a new page item to hold my WFFM form, and navigated to that page to fill in my form:

another-random-form-filled

I clicked the submit button and got a pleasant confirmation message:

another-random-form-confirmation

Thereafter, I pulled up the Form Reports for this form, and see that field values were shoehorned into it:

another-random-form-reports

That’s all there is to it.

What is the utility in all of this? Well, you might want to use this approach when sending information off to a third-party via a web service where that third-party application returns some kind of transaction identifier. Having this identifier in your Form Reports could help in troubleshoot issues that had arisen during that transaction — third-party payment processors come to mind.

Advertisement

Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: