Wagtail Tutorial Series:
To get the latest learning resource for Wagtail 4, please check Build Blog With Wagtail CMS (4.0.0)
- Create Wagtail Project
- Dockerizing Wagtail App
- Add Blog Models to Wagtail
- How to write Wagtail page template
- Add Bootstrap Theme to Wagtail
- How to use StreamField in Wagtail
- Wagtail Routable Page
- Add pagination component to Wagtail
- Customize Wagtail Page URL
- Add Full Text Search to Wagtail
- Add Markdown Support to Wagtail
- Add LaTeX Support & Code Highlight In Wagtail
- How to Build Form Page in Wagtail
- How to Create and Manage Menus in Wagtail
- Wagtail SEO Guide
- Source code: https://github.com/AccordBox/wagtail-tailwind-blog
Wagtail Tips:
- Wagtail Tip #1: How to replace ParentalManyToManyField with InlinePanel
- Wagtail Tip #2: How to Export & Restore Wagtail Site
Write style in Wagtail:
- How to use SCSS/SASS in your Django project (Python Way)
- How to use SCSS/SASS in your Django project (NPM Way)
Other Wagtail Topics:
Objective
By the end of this chapter, you should be able to:
- Understand how
FormBuilder
works and how to use it to build contact page in Wagtail project. - Learn how to make
FormBuilder
work with Bootstrap theme usingdjango-crispy-forms
Setup
Add wagtail-django-recaptcha
and django-crispy-forms
to the requirements.txt
Django>=3.1,<3.2
wagtail>=2.11,<2.12
psycopg2-binary
django-extensions==3.1.0
wagtail-markdown==0.6
Pygments
wagtail-django-recaptcha==1.0
django-crispy-forms==1.10.0
$ docker-compose up -d --build
$ docker-compose logs -f
- Add
crispy_forms
,captcha
, andwagtailcaptcha
to theINSTALLED_APPS
in wagtail_bootstrap_blog/settings/base.py - Please make sure
wagtail.contrib.forms
already exists inINSTALLED_APPS
INSTALLED_APPS = [
# code omitted for brevity
'modelcluster',
'taggit',
'django_extensions',
'wagtailmarkdown',
"crispy_forms",
"captcha",
"wagtailcaptcha",
]
Add CRISPY_TEMPLATE_PACK = "bootstrap4"
to the bottom of the wagtail_bootstrap_blog/settings/base.py, which tell cripsy-form
to render form with bootstrap layout. Template packs
Add code below to wagtail_bootstrap_blog/settings/dev.py
# DO NOT use on production, test key is available in the URL below
# https://developers.google.com/recaptcha/docs/faq
RECAPTCHA_PUBLIC_KEY = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
RECAPTCHA_PRIVATE_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
NOCAPTCHA = True
SILENCED_SYSTEM_CHECKS = ["captcha.recaptcha_test_key_error"]
The config would help make recaptcha
work in dev mode.
# check if config is correct
$ docker-compose run --rm web python manage.py check
System check identified no issues (1 silenced).
Model
Update blog/models.py to add new models below.
from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField
from wagtailcaptcha.models import WagtailCaptchaEmailForm
class FormField(AbstractFormField):
page = ParentalKey("FormPage", related_name="custom_form_fields")
class FormPage(WagtailCaptchaEmailForm):
thank_you_text = RichTextField(blank=True)
content_panels = AbstractEmailForm.content_panels + [
InlinePanel("custom_form_fields", label="Form fields"),
FieldPanel("thank_you_text", classname="full"),
MultiFieldPanel(
[
FieldRowPanel(
[
FieldPanel("from_address", classname="col6"),
FieldPanel("to_address", classname="col6"),
]
),
FieldPanel("subject"),
],
"Email Notification Config",
),
]
@cached_property
def blog_page(self):
return self.get_parent().specific
def get_context(self, request, *args, **kwargs):
context = super(FormPage, self).get_context(request, *args, **kwargs)
context["blog_page"] = self.blog_page
return context
def get_form_fields(self):
return self.custom_form_fields.all()
Notes:
- We created
FormField
to store meta data of the form fields. FormPage
inherit from theWagtailCaptchaEmailForm
, which support email sending after submission and Google reCAPTCHA validation.from_address
,to_address
, andsubject
, these fields are used to send email notificationthank_you_text
here is used to store the thanks message after submission submitted.- Please also remember to make
blog_page
available in the context, so widgets in the sidebar can work.
# migrate the db
$ docker-compose run --rm web python manage.py makemigrations
$ docker-compose run --rm web python manage.py migrate
Template
Create wagtail_bootstrap_blog/templates/blog/form_page.html
{% extends "base.html" %}
{% load static wagtailcore_tags crispy_forms_tags %}
{% block content %}
<h1>Contact</h1>
<br>
<form action="{% pageurl page %}" method="POST" >
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary" >Submit</button>
</form>
{% endblock %}
Notes:
- Here we use Django Template inheritance
{% extends "base.html" %}
{{ form|crispy }}
would call cripsy form to render the form withbootstrap
layout (which we config inCRISPY_TEMPLATE_PACK
)
Create wagtail_bootstrap_blog/templates/blog/form_page_landing.html, this template would be used to render success message after form submission.
{% extends "base.html" %}
{% load static wagtailcore_tags %}
{% block content %}
<h2>{{ page.thank_you_text|richtext }}</h2>
{% endblock %}
Email Test Env
To make us can check email notification sent by Wagtail in local dev environment, update wagtail_bootstrap_blog/settings/dev.py
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
The code above make Django print the Email message to our console, which make us easy to check.
Manual Test
# restart just in case web dever has exit
$ docker-compose up -d
$ docker-compose logs -f
Create a FormPage
which has contact
slug as child of the BlogPage
, and add some form fields.
As you can see, it is very flexible, People who have no coking skill can also create form page!
Next, let's test the form on http://127.0.0.1:8000/contact/
After I click the submit, I can see this
web_1 | Content-Type: text/plain; charset="utf-8"
web_1 | MIME-Version: 1.0
web_1 | Content-Transfer-Encoding: 7bit
web_1 | Subject: AccordBox Contact Message
web_1 | From: [email protected]
web_1 | To: [email protected]
web_1 | Date: Tue, 22 Dec 2020 02:08:26 -0000
web_1 | Message-ID: <[email protected]>
web_1 | Auto-Submitted: auto-generated
web_1 |
web_1 | Name: MichaelYin
web_1 | Email: [email protected]
web_1 | Message: This is a test message from Michael.
You can also check the form submissions in Wagtail admin/forms
and export it as CSV.
Email Reply
Some people like to reply the email notification in Gmail or some 3-party customer service app such as Zendesk.
How to make it work with Wagtail form page.
Let's take a look at this example
- Our Wagtail project send email from
[email protected]
, which is thefrom_address
- Tom, the admin of the Wagtail project has personal email
[email protected]
, which is theto_address
- Now a visitor submit submission using the email
[email protected]
.
The email headers would seem like this
| Subject: Contact Message
| From: [email protected]
| To: [email protected]
If Tom reply email, he will notice the email will sent back to [email protected]
, however, this is not the correct and Rebecca will never receive the reply.
Reply-To
can help us here.
A Reply-To address is identified by inserting the Reply-To header in your email. It is the email address that the reply message is sent when you want the reply to go to an email address that is different than the From: address.
We should make the email headers like this
| Subject: Contact Message
| From: [email protected]
| To: [email protected]
| Reply-To: [email protected]
So other email services can understand it and the email reply can work as expected.
We can override the send_mail
in FormPage
to make this work, code below can help you.
from django.core.mail import EmailMessage
email = EmailMessage(
subject,
content,
from_address,
to_address,
reply_to=[form['email'].data],
)
Notes:
- If you want to build Multi-step form, you can check snippet in Wagtail doc
- If you want the form work with
StreamField
, you can cehck wagtailstreamforms - If you want a more powerfule multi-step form, you can check wagtail-flexible-forms (This project now has not detaild doc but you can check the source code)
Wagtail Tutorial Series:
To get the latest learning resource for Wagtail 4, please check Build Blog With Wagtail CMS (4.0.0)
- Create Wagtail Project
- Dockerizing Wagtail App
- Add Blog Models to Wagtail
- How to write Wagtail page template
- Add Bootstrap Theme to Wagtail
- How to use StreamField in Wagtail
- Wagtail Routable Page
- Add pagination component to Wagtail
- Customize Wagtail Page URL
- Add Full Text Search to Wagtail
- Add Markdown Support to Wagtail
- Add LaTeX Support & Code Highlight In Wagtail
- How to Build Form Page in Wagtail
- How to Create and Manage Menus in Wagtail
- Wagtail SEO Guide
- Source code: https://github.com/AccordBox/wagtail-tailwind-blog
Wagtail Tips:
- Wagtail Tip #1: How to replace ParentalManyToManyField with InlinePanel
- Wagtail Tip #2: How to Export & Restore Wagtail Site
Write style in Wagtail:
- How to use SCSS/SASS in your Django project (Python Way)
- How to use SCSS/SASS in your Django project (NPM Way)
Other Wagtail Topics: