With the release of 1.6.0 InformationCollectionBundle provides ReCaptcha integration. Captcha settings can be configured globally or per content type.
This configuration example enables captcha globally for all forms generated by InformationCollectionController
with some additional options
like hostname
, action
, and score_threshold
.
netgen_information_collection:
system:
default:
captcha:
enabled: true
options:
hostname: 'www.example.com'
action: 'global'
score_threshold: 0.4
secret: 'secret'
site_key: 'sitekey'
action_config:
email:
templates:
default: "@ezdesign/info_collection/email.html.twig"
default_variables:
sender: "[email protected]"
recipient: "[email protected]"
actions:
default:
- database
- email
This example disables captcha globally, but enables it on for ng_feedback_form
content type and overrides site_key
value, plus sets action
option to feedback
.
netgen_information_collection:
system:
default:
captcha:
enabled: false
override_by_type:
ng_feedback_form:
enabled: true
site_key: 'mycustomsitekey'
options:
action: 'feedback'
options:
hostname: 'www.example.com'
score_threshold: 0.4
challenge_timeout: 54
secret: 'secret'
site_key: 'sitekey'
action_config:
email:
templates:
default: "@ezdesign/info_collection/email.html.twig"
default_variables:
sender: "[email protected]"
recipient: "[email protected]"
actions:
default:
- database
- email
All available options under options
configuration are:
hostname
apk_package_name
action
score_threshold
challenge_timeout
This bundle does not provides frontend/template integration with captcha, rather leave's end implementation to developer. Backend supports both visible and invisible captcha's.
To help with frontend implementation bundle provides two Twig functions:
info_collection_captcha_is_enabled()
info_collection_captcha_get_site_key()
Both accepts eZ Location value object as argument.
Example template implementation for ng_feedback_form
would be something like this (visible captcha):
{% block content %}
<div class="view-type view-type-{{ view_type }} ng-feedback-form">
<div class="full-form-content">
{% if not is_valid %}
{% if not content.fields.body.empty %}
{{ ng_render_field(content.fields.body) }}
{% endif %}
{{ form_start(form) }}
{{ form_errors(form) }}
<fieldset>
{{ form_row(form.sender_name, {attr: {class: 'form-control'}}) }}
{{ form_row(form.email, {attr: {class: 'form-control'}}) }}
{{ form_row(form.subject, {attr: {class: 'form-control'}}) }}
{{ form_row(form.message, {attr: {class: 'form-control'}}) }}
<button type="submit" class="btn btn-primary">Send</button>
</fieldset>
{{ form_rest(form) }}
{{ form_end(form) }}
{% if info_collection_captcha_is_enabled(location.innerLocation) %}
<div class="info-collector-captcha">
<script src='https://www.google.com/recaptcha/api.js'></script>
{% set captcha = info_collection_captcha_get_site_key(location) %}
<div class="g-recaptcha" data-sitekey="{{ captcha }}"></div>
</div>
{% endif %}
{% else %}
{{ block('success') }}
{% endif %}
</div>
</div>
{% endblock %}
Or, using captcha v3:
{% block content %}
<div class="view-type view-type-{{ view_type }} ng-feedback-form">
<div class="full-form-content">
{% if not is_valid %}
{% if not content.fields.body.empty %}
{{ ng_render_field(content.fields.body) }}
{% endif %}
{{ form_start(form) }}
{{ form_errors(form) }}
<fieldset>
{{ form_row(form.sender_name, {attr: {class: 'form-control'}}) }}
{{ form_row(form.email, {attr: {class: 'form-control'}}) }}
{{ form_row(form.subject, {attr: {class: 'form-control'}}) }}
{{ form_row(form.message, {attr: {class: 'form-control'}}) }}
<input name="g-recaptcha-response" hidden>
<button type="submit" class="btn btn-primary">Send</button>
</fieldset>
{{ form_rest(form) }}
{{ form_end(form) }}
{% if info_collection_captcha_is_enabled(location.innerLocation) %}
{% set captcha = info_collection_captcha_get_site_key(location.innerLocation) %}
<div class="info-collector-captcha">
<script src="https://www.google.com/recaptcha/api.js?render={{ captcha }}"></script>
<script>
grecaptcha.ready(function () {
grecaptcha.execute('{{ captcha }}', {action: 'feedback'}).then(function (token) {
$('[name="g-recaptcha-response"]').val(token);
});
});
</script>
</div>
{% endif %}
{% else %}
{{ block('success') }}
{% endif %}
</div>
</div>
{% endblock %}
Or, using invisible captcha:
{% block content %}
<div class="view-type view-type-{{ view_type }} ng-feedback-form">
<div class="full-form-content">
{% if not is_valid %}
{% if not content.fields.body.empty %}
{{ ng_render_field(content.fields.body) }}
{% endif %}
{{ form_start(form, { 'attr': { 'id': 'ng_feedback_form'} } ) }}) }}
{{ form_errors(form) }}
<fieldset>
{{ form_row(form.sender_name, {attr: {class: 'form-control'}}) }}
{{ form_row(form.email, {attr: {class: 'form-control'}}) }}
{{ form_row(form.subject, {attr: {class: 'form-control'}}) }}
{{ form_row(form.message, {attr: {class: 'form-control'}}) }}
<input name="g-recaptcha-response" hidden>
<button type="submit" class="btn btn-primary g-recaptcha" data-sitekey={{info_collection_captcha_get_site_key(location.innerLocation)}} data-callback='onSubmit'>Send</button>
</fieldset>
{{ form_rest(form) }}
{{ form_end(form) }}
{% if info_collection_captcha_is_enabled(location.innerLocation) %}
<div class="info-collector-captcha">
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script>
function onSubmit(token) {
document.getElementById("ng_feedback_form").submit();
}
</script>
</div>
{% endif %}
{% else %}
{{ block('success') }}
{% endif %}
</div>
</div>
{% endblock %}
If captcha validation results in error with code missing-input-response
you probably did not send reCAPTCHA token in variable g-recaptcha-response
.
Another error you might encounter is action-mismatch
. In this case make sure that the action you specified in captcha config (globally or per content type)
is the same as the one you use when executing captcha check.