I am using the hosted version of Locomotive CMS.
Locomotive CMS provides a means by which to collect form submissions and a means by which to send an email using the Actions API.
I want to collect form submissions and then send an email to the person who submitted the form.
I have 3 caveats:
All of the aforementioned items are available out of the box in the hosted version of Locomotive CMS. However, I can't figure out how to submit a content type form with Google reCAPTCHA via AJAX and send an email at the same time. The Send Email functionality requires an action on a dedicated page which I believe needs to be loaded in order for the action to run. Additionally I don't know how to get the data from the form submission to the page on which the Send Email action runs.
How can I submit a Locomotive CMS content type form via AJAX with Google reCAPTCHA enabled and send an email containing the form submission data to the person who submitted in the form?
A couple of prerequisites:
Set up metafields_schema.yml to include the necessary information for sending emails:
smtp_settings:
label: Outgoing Email
fields:
server:
label: SMTP Server
type: string
localized: false
username:
label: Username
type: string
localized: false
password:
label: Password
type: string
localized: false
port:
label: Port
type: string
hint: TLS
localized: false
Set up an email template:
email-template.liquid:
<p>Dear {{ entryData.first_name }},</p>
<!-- include form submission data via entryData.form_field_name -->
We "simply" pass the form data to a custom page where we send an email and create a content entry using the Actions API.
Setup as follows:
Manually create a form to collect the content type data. Note the form action points to a custom page:
<form method="POST" enctype="multipart/form-data" class="form" action="{% path_to 'page-with-send-email-and-create-content-entry-action' %}">
<!-- form fields here -->
</form>
<script defer src="{{ 'form-submit.js' | javascript_url }}"></script>
Submit the form with AJAX:
form-submit.js:
$('.form').on('submit', function(e) {
e.preventDefault();
var form = $(this);
// error handling functions removed for brevity
$.ajax({
type: 'POST',
url: form.attr('action'),
data: form.serialize(),
dataType: 'json',
success: function(data) {
console.log('Success:', data);
},
error: function(xhr, status, error) {
console.log('Status:', status);
console.log('Error:', error);
var errors = jQuery.parseJSON(xhr.responseText).errors;
console.log(errors);
for (error in errors) {
myError = error;
console.log(myError);
}
}
});
});
Send an email and create a content type entry using the Actions API:
page-with-send-email-and-create-content-entry-action.liquid:
{% action "send email and create content type entry" %}
var SMTPsettings = getProp('site').metafields.smtp_settings;
var entryData = getProp('params'); // params holds the data passed to the page via AJAX
// save entryData into a Liquid variable to be called in the Email Template
setProp('entryData',entryData);
sendEmail({
to: formData.email_address, // must match the name attribute of the field used to collect the email address
from: SMTPsettings.username,
subject: '[Email Subject]',
page_handle: 'email-template', // template page for email
smtp: {
address: SMTPsettings.server,
port: SMTPsettings.port,
user_name: SMTPsettings.username,
password: SMTPsettings.password,
authentication: 'plain',
enable_starttls_auto: true
}
});
createEntry('content_entry_name', {
content_type_field_name: formData.form_field_name,
// comma-separated list - last item has no comma
});
{% endaction %}
{"success":true}
I don't believe there is a way to manually create a form in Locomotive CMS with Google reCAPTCHA enabled, which means the above method won't work.
Google reCAPTCHA is available in Locomotive CMS via the default content type form setup:
{% model_form 'content_type_slug', class: 'form', json: true, recaptcha: true %}
// form fields here
{% endmodel_form %}
<script src="https://www.google.com/recaptcha/api.js?render={{ site.metafields.google.recaptcha_site_key }}"></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('{{ site.metafields.google.recaptcha_site_key }}', {
action: 'enquiry'
})
.then(function(token) {
document.getElementById('g-recaptcha-response').value = token;
});
});
</script>
<script defer src="{{ 'form-submit.js' | javascript_url }}"></script>
Note: The property recaptcha_required
needs to be set to true
in the content_type yml file.
In this case we cannot set a custom url for the form action. Additionally the reCAPTCHA verification means we need to let the form submit and create the content entry via the usual process and send the email separately.
To do this we will need to get the ID of the content entry created upon form submission. We can then run an additional AJAX request and pass the ID to a custom page containing a send email action. On the custom page we will use the ID to reference the content entry and get the data to populate the email.
Setup as follows:
Create form via default method above.
Submit the form with AJAX. Upon successful submission, get the content entry ID and pass it to a secondary AJAX request:
form-submit.js:
$('.form').on('submit', function(e) {
e.preventDefault();
var form = $(this);
// error handling functions removed for brevity
$.ajax({
type: 'POST',
url: form.attr('action'),
data: form.serialize(),
dataType: 'json',
success: function(data) {
console.log('Success:', data);
// get the content entry ID
var entryID = data._id;
// set up the data to be sent in the correct format
var newData = 'id=' + entryID;
// set up our secondary AJAX request
function sendEmail() {
$.ajax({
type: 'POST',
url: 'page-with-send-email-action',
data: newData,
dataType: 'json',
success: function(data) {
console.log('Success:', data);
},
error: function(xhr, status, error) {
console.log('Status:', status);
console.log('Error:', error);
var errors = jQuery.parseJSON(xhr.responseText).errors;
console.log(errors);
for (error in errors) {
myError = error;
console.log(myError);
}
}
});
}
sendEmail();
showSuccess();
},
error: function(xhr, status, error) {
console.log('Status:', status);
console.log('Error:', error);
var errors = jQuery.parseJSON(xhr.responseText).errors;
console.log(errors);
for (error in errors) {
myError = error;
console.log(myError);
showError();
}
}
});
});
Find the submitted content entry and send an email using the Actions API:
page-with-send-email-action.liquid:
{% action "send email" %}
var SMTPsettings = getProp('site').metafields.smtp_settings;
var entryID = getProp('params').id;
var entryData = findEntry('content_type_slug', entryID);
// save entryData into a Liquid variable to be called in the Email Template
setProp('entryData',entryData);
sendEmail({
to: entryData.email_address,
from: SMTPsettings.username,
subject: '[Email Subject]',
page_handle: 'email-template',
smtp: {
address: SMTPsettings.server,
port: SMTPsettings.port,
user_name: SMTPsettings.username,
password: SMTPsettings.password,
authentication: 'plain',
enable_starttls_auto: true
}
});
{% endaction %}
{"success":true}