Google INVISIBLE reCaptcha + jQuery validate() issue

dev101 picture dev101 · Mar 11, 2017 · Viewed 18.9k times · Source

I have implemented new Google's INVISIBLE reCaptcha on several sites successfully, however, it conflicts with jQuery validate(), in such a way that the js validation is no longer executed on button/form submit, and reCaptcha instantly kicks-in. If user forgets to fill-in a requried form field, it will have to wait for server response, and get back to it next time.

jQuery .validate() supports callback, but because of the fact that it is hard-coded inside an internal class of a CMS, is there a way I can modify it somehow outside (e.g. from front-end theme, on document load, when validation code is already rendered)?

Or, another idea would be to postpone captcha's callback somehow, so that validation step can get a chance to run.

Thanks!

jQuery Validate form: (hard-coded in the core, can't be modified, unless I edit core file or extend class/clone function - not optimal)

<script type="text/javascript">
$(document).ready(function(){
    $("form[name=comment_form]").validate({
        rules: {
            body: {
                required: true,
                minlength: 1
            },
            authorEmail: {
                required: true,
                email: true
            }
        },
        wrapper: "li",
        errorLabelContainer: "#comment_error_list",
        invalidHandler: function(form, validator) {
            $('html,body').animate({ scrollTop: $('#comment_error_list').offset().top }, { duration: 250, easing: 'swing'});
        },
        submitHandler: function(form){
            $('button[type=submit], input[type=submit]').attr('disabled', 'disabled');
            form.submit();
        }
    });
});
</script>

reCaptcha explicit render:

<script type='text/javascript'>
    var renderInvisibleReCaptcha = function() {
    for (var i = 0; i < document.forms.length; ++i) {
        var form = document.forms[i];
        var holder = form.querySelector('.invisible-recaptcha');
        if (null === holder) continue;
        (function(frm){
            var holderId = grecaptcha.render(holder, {
            'sitekey': 'my-key-here',
            'badge': 'inline',
            'size': 'invisible',
            'callback': function (recaptchaToken) {HTMLFormElement.prototype.submit.call(frm);},
            'expired-callback': function(){grecaptcha.reset(holderId);}
            });
            frm.onsubmit = function (evt){evt.preventDefault();grecaptcha.execute(holderId);};
        })(form);
    }
};
</script>

Answer

JoanF picture JoanF · Jun 4, 2018

I had the same problem, I finally found the right way to integrate jquery validate with invisible reCaptcha. It's a mix of some of the proposed solutions here.

First of all, the the HTML part:

<div class="g-recaptcha" data-sitekey="<your key here>"
    data-size="invisible" 
    data-callback="formSubmit">
</div>

Then, you must implement the reCaptcha callback in that way:

function formSubmit(response) {
    // submit the form which now includes a g-recaptcha-response input
     $("#orderform").submit();
    return true;
}

And finally, the tricky part is in the jquery validate's submitHandler:

   submitHandler: function (form) {
        if (grecaptcha.getResponse()) {
                // 2) finally sending form data
                form.submit();
        }else{
                // 1) Before sending we must validate captcha
            grecaptcha.reset();
            grecaptcha.execute();
        }           
    }

The sequence is as follows:

  1. When user hits submit button, jquery's submitHandler is called, as invisible recaptcha isn't executed yet, we call grecaptcha.execute(). It takes some seconds for google's recaptcha to validate, and when it's fully validated it'll call formSubmit callback (while this callback isn't called, we cannot send form data to the server!).
  2. In formSubmit callback we call $('#orderform').submit to force to enter submitHandler again.
  3. Inside submitHandler again, this time as grecaptcha.getResponse is not null, we can post the form data to the server, it will include the recaptcha hidden field, which must then be validated on the server side.

Hope this helps.