Hello Sitecorians,
I’ve been exploring Sitecore Forms and implemented the Google Re-captcha form element within the Sitecore forms. Re-captcha is the basic requirement for the form submission process and in order to implement this, we’ve to write some code to it.
We will go through step by step process to implement the Google Recaptcha with Sitecore Forms using the custom form element. And will create a generic component which you can use for any other form as well.
How to do ?
First we will create the sitecore template changes,
We will need the following fields for Recapthca Field
- Public Key
- Private Key
- Error Message
Core DB Changes :
1. Go to the “/sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Common/Details” and duplicate the “FieldName” Item.
2. Update the “FormLabel” to “Private Key” and “BindingConfiguration” like below screenshot
3. Do the same steps to the remaining two fields.
Now we need to create the Property Editor.
- Go to the “/sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Settings” Item.
- Duplicate the “SingleLineText” and Update the details section.
- Add the newly created details items to “GoogleRecapthca” item like below screenshot
Master DB changes :
- Go to the “/sitecore/templates/System/Forms/Fields” and duplicate the “/sitecore/templates/System/Forms/Fields/Input” Item.
- We need to add the below fields in the “Google Recaptcha” Item and create the _StandardValues as well.
- Public Key
- Private Key
- Error Message
3. Update the PrivateKey and PublicKey in _StandardValues .
Code Changes :
Create the new class “GoogleRecaptcha” like below,
using Sitecore.Data.Items; using Sitecore.ExperienceForms.Mvc.Models.Fields; namespace Sitecore.Scientist.Forms.Fields { public class GoogleRecaptcha : StringInputViewModel { public string PublicKey { get; set; } public string PrivateKey { get; set; } public string ErrorMessage { get; set; } protected override void InitItemProperties(Item item) { base.InitItemProperties(item); PublicKey = StringUtil.GetString(item.Fields["Public Key"]); PrivateKey = StringUtil.GetString(item.Fields["Private Key"]); ErrorMessage = StringUtil.GetString(item.Fields["Error Message"]); } protected override void UpdateItemFields(Item item) { base.UpdateItemFields(item); item.Fields["Public Key"].SetValue(PublicKey, true); item.Fields["Private Key"].SetValue(PrivateKey, true); item.Fields["Error Message"].SetValue(ErrorMessage, true); } } }
Create the new view “GoogleRecaptcha.cshtml” and place under the “Views\FormBuilder\FieldTemplates”
@using Sitecore.ExperienceForms.Mvc.Html
@model Sitecore.Scientist.Forms.Fields.GoogleRecaptchahttps://www.google.com/recaptcha/api.js
<span class=”field-validation-error” id=”captchaError-@Html.IdFor(m => Model.Value)” style=”display:none”>@Model.ErrorMessage</span>
<input id=”@Html.IdFor(m => Model.Value)” name=”@Html.NameFor(m => Model.Value)” class=”@Model.CssClass” value=”@Model.Value” type=”hidden” data-sc-tracking=”@Model.IsTrackingEnabled” data-sc-field-name=”@Model.Name” @Html.GenerateUnobtrusiveValidationAttributes(m => m.Value) />
@Html.ValidationMessageFor(m => Model.Value)if ($(‘#’+’@Html.IdFor(m => Model.Value)’).parent(‘form’)) {
$($(‘#’ + ‘@Html.IdFor(m => Model.Value)’).parent(‘form’)).submit(function () {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘span[data-valmsg-for=”@Html.NameFor(m => Model.Value)’).hide();
var recaptchaResponse = grecaptcha.getResponse();
if (recaptchaResponse.length == 0) {
document.getElementById(‘captchaError-‘ + ‘@Html.IdFor(m => Model.Value)’).value = $(‘#’ + ‘@Html.IdFor(m => Model.Value)’).data(‘val-required’);
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “block”;
return false;
}
else {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘#’+’@Html.IdFor(m => Model.Value)’).val(recaptchaResponse);
return true;
}
});
}
function captchaCallback() {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘span[data-valmsg-for=”@Html.NameFor(m => Model.Value)’).hide();
if (recaptchaResponse.length == 0) {
document.getElementById(‘captchaError-‘ + ‘@Html.IdFor(m => Model.Value)’).value = $(‘#’ + ‘@Html.IdFor(m => Model.Value)’).data(‘val-required’);
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “block”;
}
else {
document.getElementById(‘captchaError-‘+’@Html.IdFor(m => Model.Value)’).style.display = “none”;
$(‘#’+’@Html.IdFor(m => Model.Value)’).val(recaptchaResponse);
}
}
Coding part is done .Its time to create the field.Create the new field “Google Recaptcha” under the “/sitecore/system/Settings/Forms/Field Types/Security” path and update red marked field.
Lets create the form
We are not done yet.Its very important to create the server side validator for the recaptcha. Create the new class called “CaptchaValidator.cs” like below,
using Newtonsoft.Json; using Sitecore.Data; using Sitecore.ExperienceForms.Mvc.Models.Fields; using Sitecore.ExperienceForms.Mvc.Models.Validation; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Net; using System.Web.Mvc; namespace Sitecore.Scientist.Forms.Validator { public class CaptchaResponse { [JsonProperty("success")] public bool Success { get; set; } [JsonProperty("error-codes")] public List ErrorMessage { get; set; } } public class CaptchaValidator : ValidationElement { public override IEnumerable ClientValidationRules { get { if (string.IsNullOrEmpty(this.PrivateKey)) { yield break; } } } protected virtual string PrivateKey { get; set; } protected virtual string Title { get; set; } protected virtual string FieldName { get; set; } public CaptchaValidator(ValidationDataModel validationItem) : base(validationItem) { } public override void Initialize(object validationModel) { base.Initialize(validationModel); StringInputViewModel stringInputViewModel = validationModel as StringInputViewModel; if (stringInputViewModel != null) { var fieldItem = Context.Database.GetItem(ID.Parse(stringInputViewModel.ItemId)); if(fieldItem!=null) { this.PrivateKey = fieldItem["Private Key"]; } this.Title = stringInputViewModel.Title; this.FieldName = stringInputViewModel.Name; } } public override ValidationResult Validate(object value) { if (value == null) { return ValidationResult.Success; } var isCaptchaValid = ValidateCaptcha((string)value, this.PrivateKey); if (!isCaptchaValid) { return new ValidationResult(this.FormatMessage(new object[] { this.Title })); } return ValidationResult.Success; } public static bool ValidateCaptcha(string response, string secret) { var client = new WebClient(); var reply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secret, response)); var captchaResponse = JsonConvert.DeserializeObject(reply); return System.Convert.ToBoolean(captchaResponse.Success); } } }
Create the new Captchavalidator under the “/sitecore/system/Settings/Forms/Validations” like below screenshot
Select the CaptchaValidator in GoogleRecaptcha Validations.
we are done for creating the google recaptcha field .Let’s test the field
Thanks to Nikki Punjabi . I have referred his post and created this post.
Lazy developers don’t like to create this field from all of the above steps.That’s why i created the sitecore package for the lazy guys.Please download the package from this Google Recaptcha SC9 Form Field-V1.0.zip
After installing the package, if you are getting the below error then update your recaptcha “Private Key” and “Public Key”.
Download the source code from Github.
Thanks you for visiting my blog . Happy Coding.
Hi!
This bit in the Validate method of the serverside validation:
if (value == null)
{
return ValidationResult.Success;
}
Is it correct? Should success be returned when value is null?
LikeLike
I think this might be wrong .We should return false if value is null
LikeLike
Hi again, thanks for your reply!
Another question: var recaptchaResponse = grecaptcha.getResponse(); riht when inline script is loaded, not inside the recatpcha callback. Is this correct? It’s not pssobily to be sure that the grecaptcha module is fully initilizaed by then, is it?
LikeLike
I read the script wrong, nvm 🙂
LikeLike
Nice blog, keep writing. However I just want to highlight one issue here, even if we have selected captcha, if we submit button it is throwing validation error. Is it known issue??
LikeLike