This recipe extends the basic contact form example, but this time the user can attach some files. As an example we use a job application form.
To follow this example, your content structure should look like this:
We also need the following files:
- an applications template with the form snippet
- the application form snippet
- the controller that handles the form logic
- a plain text or an HTML email template
- two templates for the
jobsoverview page and its subpages (see the demo download below)
The workflow is like this:
When users visit a job page, they can click on a link that leads to the application form. The link contains the reference that is then prefilled in the form's reference field. Users can however change this field input if they decide they would rather apply for another job (or if they visit the
applications page directly).
With this setup, we keep the application process away from the job listings and can put it behind a login wall if needed. Instead of handling the applications on a general applications form like in this example, you could also show the form on every job page.
applications page with an
applications.txt content file. For our means, we only need the title in the content file, the rest is up to you.
For use in the Panel, you can create a blueprint for the page. We will skip this step here.
The template contains the form and will display error messages if something goes wrong. To keep the
applications.php template clean, we include the form as a snippet.
The form snippet contains some form fields (
file) and a honeypot field to ensure a minimum level of spam bot protection.
The honeypot field needs to be positioned off the screen via CSS. Therefore add these styles to your stylesheet (you can change the class and styling).
Note that since we want to upload files, we have to set the encoding type attribute to
$alert variables get controlled by user input, it is important to escape the text to protect against XSS vulnerabilities.
The controller handles our form validation logic.
Let's go through the most important steps here in detail. The rest is commented in the code snippet.
In our controller, the form evaluation starts once we receive a
POST request. First, we check if a bot got trapped in our honeypot. In this case, we send him back to the page and stop script execution.
Next, we check if all form fields have been filled in according to our validation rules using the
- All fields are required and must be filled out.
namefield must be at least 3 characters long.
messagefield must be between 10 and 3000 characters.
referencefield must be a valid reference from one of the
We then handle the file submissions. We fetch the uploaded file(s) with
file is the name of our input field. If the user tries to upload more than 3 files, we add a message to the
Then we loop through the files array and check for each upload if it is valid:
- We check the
$upload['error']value to make sure that we have at least one upload and no other error occurred
- We check the file size to make sure that the file is not larger than allowed
- We check if the uploaded is a PDF
As the last step in this loop we rename the temporary upload name to a sanitized version of the original file name.
If all went well, we try to send the email together with the file attachments in a
try - catch block.
If the email was sent, we store the user's name and the job reference number in the session and redirect the user to the
$kirby->email() method above, we defined a template we want to use to send the email. In this example, we use a template called
We can use both a plain text template and/or an HTML version. You can read more about this in the email guide.
Here are the two email templates:
The plain text template gets the extension
The HTML template gets the extension
Both templates are kept very simple. Kirby provides the variables we defined in the
data array ready to be used in the email templates as
$sender. You can of course change them to your liking.
The success content file contains placeholders for the applicant's name and the job reference number:
In the plugin, we replace the name and event placeholders in the text with the data we stored in the session.
For a working example, download the demo "Jobkit".
You can of course extend this example:
- Integrate other field types.