-
WFFM - Sitecore Context Item NULL inside a Save Action
August 6, 2017 Rodrigo Peplau 0
Business requirements
There is a use case in one of our clients at Nish Tech, where a WFFM form, with a Submit E-mail Save Action, is supposed to be reused at several different parts of the website. It should have the same fields and look & feel at every place we want to reuse it, the only difference would be that the e-mail would be submitted to different addresses depending on what page the form is located.
The pages where this form will be allowed are what we call “Communities”. Each of them has a couple of fields with e-mails (Eg: Sales E-mail, Human Resources E-mail) from which we wanted to have WFFM looking for, instead of using the one hardcoded at the WFFM itself.
One may ask: why not duplicate the WFFM form and hardcode a different e-mail for each page we need? The answer is plenty clear: we will have more than 80 communities, and growing. That would mean more than 80 duplications of the WFFM form, which sound quite abusive. If we happen to need some kind of maintenance at these forms, this would be a nightmare.
The resulting implementation will be subject of a future blog post, this one in particular will focus in a specific challenge: how to access the Sitecore.Context.Item inside a WFFM Save Action.
Technical challenge
So the idea is that WFFM should look into a field at the item where it is located, grabbing the destiny e-mail from there instead of the hardcoded e-mail at the WFFM Form itself. To achieve this we will need to access the current context item (Sitecore.Context.Item), which surprisingly is not available inside a Save Action, as confirmed by Sitecore in a Helpdesk ticket we created.
To be fair, Sitecore.Context.Item is available in Preview Mode because Sitecore explicitly sets the current item ID at the querystring. However, in publish mode there are no such parameter at the querystring, which happens to let Sitecore.Context.Item with value NULL when you are inside a Save Action. This happens because the Item Resolver only runs AFTER the Save Action, thus Context.Item will only be filled after the Save Action is executed.
Implementing a Solution
So here is the solution we ended up arranging, with best possible reusing of same WFFM and not jeopardizing WFFM’s or Sitecore’s normal pipelines and flows.
Step 1 – Create a new WFFM field for Sitecore.Context.Item
This would be a hidden field at the form, responsible for carry on the Sitecore.Context.Item.ID, available at the time when the form is rendering, to the Save Action where that is not available.
- At /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/Simple Types start by duplicating the “Single-Line Text” field to serve as a basis for our new field;
- Rename it to “Sitecore Context Item ID”;
- Fill the field “MVC Type” with the assembly we are going to create to our new field:
ClientName.Website.Core.WFFM.Fields.SitecoreContextItemId, ClientName.Website.Core - Create a view called “SitecoreContextItemId.cshtml” for this field under /Views/Form/EditorTemplates and add the following content. Notice the <span style=”display:none;”> surrounding the field, which will make it hidden when the form renders
@using Sitecore.Forms.Mvc.Html @model Sitecore.Forms.Mvc.ViewModels.FieldViewModel <span style="display:none;"> @using (Html.BeginField()) { @Html.BootstrapEditor("Value") } </span>
Step 2 – Make that field comes auto-populated with Context.Item
This class, which is tied to the field at the bullet 3 of Step 1, implements the logic that makes the field renders with Sitecore.Context.Item.ID auto-populated. Notice that this is simply inheriting from SingleLineTextField, adding the ID to the field Value, and nothing else.
using Sitecore.Forms.Mvc.ViewModels.Fields; namespace ClientName.Website.Core.WFFM.Fields { public class SitecoreContextItemId : SingleLineTextField { public override void Initialize() { if (this.MaxLength != 0) return; this.MaxLength = 256; this.Value = Sitecore.Context.Item.ID.ToString(); } } }
Step 3 – Make Context.Item be automatically filled from that field
We could very well now just go ahead and read from that field, couldn’t we? But to make things pretty, instead of that we are going to implement a pipeline processor to populate Sitecore.Context.Item.
- Create an include file “Sitecore.WFFM.SetContextItem.config” with following content:
<?xml version="1.0" encoding="utf-8"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <wffm.submit> <processor type="ClientName.Website.Core.WFFM.Pipelines.SetContextItem,ClientName.Website.Core" patch:after="processor[@type='Sitecore.Forms.Mvc.Pipelines.Submit.RegisterFormSubmitEvent,Sitecore.Forms.Mvc']"/> </wffm.submit> </pipelines> </sitecore> </configuration>
- Then let’s implement this class to make Sitecore.Context.Item be populated.
using System.Linq; using Sitecore.Data; using Sitecore.Diagnostics; using Sitecore.Forms.Mvc.Interfaces; using Sitecore.Forms.Mvc.Models; using Sitecore.Forms.Mvc.Pipelines; namespace ClientName.Website.Core.WFFM.Pipelines { public class SetContextItem : FormProcessorBase<IFormModel> { public override void Process(FormProcessorArgs<IFormModel> args) { Assert.ArgumentNotNull((object)args, "args"); var model = args.Model as FormModel; if (model == null || Sitecore.Context.Item!=null) return; var contextField = model.Item.Fields.FirstOrDefault(p => p.MVCClass.Contains(typeof(Fields.SitecoreContextItemId).FullName)); if (contextField == null) return; var contextFieldResult = model.Results.FirstOrDefault(p => p.FieldName == contextField.Name); if (contextFieldResult == null) return; var contextItem = Sitecore.Context.Database.GetItem(new ID(contextFieldResult.Value.ToString())); Sitecore.Context.Item = contextItem; } } }
Pay special attention to the following lines:
var contextField = model.Item.Fields.FirstOrDefault(p => p.MVCClass.Contains(typeof(Fields.SitecoreContextItemId).FullName));
Where the assembly name we created at Step 2 is used to find our field and next:
var contextFieldResult = model.Results.FirstOrDefault(p => p.FieldName == contextField.Name);
Where the ID value is taken to later populate Sitecore.Context.Item:
var contextItem = Sitecore.Context.Database.GetItem(new ID(contextFieldResult.Value.ToString())); Sitecore.Context.Item = contextItem;
Step 4 – Add the field to your WFFM Form
Easy part, but if forgotten nothing will work. Make sure your new field is present at your WFFM Form:
Categories: WFFM
Corey Peplau wrote this - WFFM conflict with Unity DI and a lesson on how Sitecore community is so amazing How we won the Hackathon
Proudly 10x Sitecore MVP!
(2016-2025)
Localization
Recent Posts
Recent Comments
- navan on Meet MVPinny: the AI-Powered Sitecore Assistant
- Adriana on Content generation with Sitecore Connect and ChatGPT
- NAVAN on Automatic Sitecore NuGet upgrades with Powershell
- Hedipo S Menezes on Corey Peplau wrote this - WFFM conflict with Unity DI and a lesson on how Sitecore community is so amazing
- Rodrigo Peplau on ERROR [Content Testing]: Cannot find PhantomJS executable at ' (...) /data/tools/phantomjs/phantomjs.exe'. Aborting screenshot generation.
Archives
- March 2025
- January 2025
- June 2024
- April 2024
- February 2024
- December 2023
- November 2023
- August 2023
- July 2023
- January 2023
- February 2022
- December 2021
- November 2021
- March 2021
- July 2020
- February 2020
- September 2019
- July 2019
- April 2019
- March 2019
- December 2018
- February 2018
- January 2018
- November 2017
- September 2017
- August 2017
- July 2017
- March 2017
- February 2017
- November 2016
- September 2016
- August 2016
- July 2016
- April 2016
- November 2015
- September 2015
- July 2015
- April 2015
- March 2015
- February 2015
Categories
- Actions
- Active Directory
- Analytics
- Architecture
- Bug fixing
- CDP/Personalize
- ChatGPT
- Content Edition Experience
- Content Hub
- Continuous Integration
- Dev
- Development
- Environments
- Experience Editor
- Experience Forms
- Front-end
- Hackathon
- Health Check builds
- Helix
- How To
- LDAP
- MVP
- MVP Summit
- MVPinny
- Phantom JS
- Powershell
- QA
- Richtext Editor
- Rules
- Security Provider
- SIF
- Sitecore 9
- Sitecore API
- Sitecore Community
- SItecore Connect
- Sitecore Modules
- Sitecore Rocks
- Sitecore Rule Processor
- Sitecore Symposium
- SPE
- SPE-only Alliance
- SPEAK
- SUG
- Support Ticket
- TDS
- Team City
- Uncategorized
- Upgrades
- Visual Studio
- WFFM
- Workflow
- XConnect
- xDB
- XM Cloud