Tutorial on Form Validation & Emailing?

Hi all! I know that Kirby has a validation class, and also an emailing helper function, but the docs are a bit too basic for a newbie… :cry:

Has anyone written a step-by-step “for dummies” lesson on how to get, let’s say, a simple site ‘Contact Form’ working, with validation and emailing?

Any guidance would be extremely welcome.

You should have a look at the Uniform plugin: https://github.com/mzur/kirby-uniform

It makes creating contact forms a breeze!

If you don’t want to use the Uniform plugin, have a look at this example contact form by @bastianallgeier https://gist.github.com/bastianallgeier/c396df7923848912393d. It’s not a tutorial but a starting point …

1 Like

Check out this blog post. It’s a step-by-step tutorial on how to implement a contact form using the Uniform plugin.

@texnixe thank you so much - that’s exactly what I needed! :smile:

I did have a good look at the Uniform plugin. It looks fantastic - quite powerful and flexible - but unfortunately it requires us to turn on multi-language options on the site (even if it’s a single-language site), which I really don’t want to do.

Thank you all for your guidance - it’s truly appreciated!

@texnixe I find that I keep going back to @bastianallgeier’s old email controller all the time, for its simplicity… It should be added to the docs, as a Contact Form ‘solution’.

I’m currently working on a project that has a contact form inside a modal dialogue. I’d like to be able to submit the form and update the interface without closing the modal - i.e, via ajax. Is there a step-by-step tutorial on how to do this? - i.e., how to submit a contact form via ajax in Kirby?..

No, there is no tutorial. But basically, submitting a form via ajax is no different than any other ajax call and all not very Kirby specific.

We will certainly start adding tutorials at one point or the other; currently, we are still updating the Cheat Sheet to include all missing methods and with more examples; all this takes up a lot of time, given that we are not working full time on this - or at least not officially :wink:

Your work is truly appreciated - thank you!

There is a tutorial for Uniform on using AJAX with forms that will probably be helpful when you use the simple email controller, too :wink: It’s basically just a matter of how to set up the JSON communication between the JS of the form and the Kirby controller.

@luxlogica: I was about to modify the Uniform plugin to not require the multi-language option for a project I’m working on, when I realized that it has recently been updated. Now, you can simply set a language in your config file, no need to turn on multi-language anymore.

Thanks, @mzur :slight_smile:

Thank you all for giving me hints and tips - it has been very helpful, indeed.
In order to help other newbies, I’ll document here what my current steps are for getting an ajax-based contact form going in Kirby. For someone new to web development getting this going can seem daunting, so hopefully this guide - of sorts - might help… The end result is that we can have a form processor without having to add extra template/snippet/controller/content pages - it’s all done with a route and a plugin.

The code here is built from several different sources, including a post from @Targoran, hints by @texnixe and @mzur, code from @bastianallgeier and guidance from @distantnative. Also, had to do quite a bit of research on GitHub and StackOverflow, to make sure the code was reasonably sound. So, here goes.

Follow these 4 steps:

Step 1

Place the following lines in your site’s ‘config.php’, to create a form-processing route:

c::set('routes', array(
  array(
    // in 'pattern', enter the same url being called from your ajax javascript function
    'pattern' => 'api/form',
    'method' => 'POST',
    'action' => function() {
      // check whether this is an ajax request, and respond with an error if it isn't
      if(!kirby()->request()->ajax()){ return response::error("Page Not Found!","404");}
      // process the form data, send the email - and get the result (as an array)
      $data = mailFormData(kirby()->request()->data());
      // respond with the result - in JSON format
      return response::json($data);
      }
    )
));

Step 2

In one of your templates or snippets, setup a contact form - such as the one below:

<form id="my-form">
    
    <!-- for displaying the results of the sending operation -->
    <span class="form-result"></span>
    
    <label for="my-form-name">Your Name*</label>
    <input type="text" name="name" id="my-form-name" required>
    
    <label for="my-form-email">Your Email*</label>
    <input type="email" name="email" id="my-form-email" required>
    
    <label for="my-form-phone">Your Phone</label>
    <input type="tel" name="phone" id="my-form-phone">
    
    <!-- a 'honeypot' field, to help us detect spam bots (use css to hide it) -->
    <input type="text" name="website" id="my-form-website" value="" class="hidden">
    
    <label for="my-form-message">Your Message</label>
    <textarea name="message" id="my-form-message" rows="9"></textarea>
    
    <button type="submit" name="submit">Send</button>
    
</form>

You can add or remove fields to your form, as you wish. You should also add css classes to its elements, and style the form according to your requirements.

Step 3

In your form template/snippet, right after your form element, place the following javascript:

<script>
    // AJAX FORM PROCESSING
    $('#my-form').on('submit', function(e){
        e.preventDefault();
        var form = $(this);
        $.ajax({
            type: 'POST',
            // use the same url here as the 'pattern' in your route
            url: 'api/form',
            data: form.serialize(),
            success: function(result){
                // form data successfully reached form processor api
                if(result.success){
                    // message successfully sent
                    form.find('.form-result').text('Your message was sent successfully - thank you!');
                } else {
                    // an issue was encountered
                    if(result.errors == undefined || result.errors == null || result.errors.length == 0){
                        // no validation errors - an email sending error was encountered
                        form.find('.form-result').text(result.msg);
                    } else {
                        // a validation error was encountered
                        var msg = "Please note: <br>";
                        if(result.errors.indexOf('name') != -1){ 
                            msg += "Name field must not be empty. <br>";
                         }
                        if(result.errors.indexOf('email') != -1){ 
                            msg += "Email field must contain a valid email. <br>";
                        }
                        if(result.errors.indexOf('website') != -1){ 
                            msg += "You seem to be a robot. <br>";
                        }
                        form.find('.form-result').html(msg);
                    }
                }
            },
            error: function(result){
                // the form was unable to reach processor api
                form.find('.form-result').text('Error '+ result.status + ' - unable to process form: ' + result.statusText);
            },
            dataType: 'json'
        });
    });
</script>

Note that the javascript above uses jQuery.

Step 4

In your ‘site/plugins’ folder, create another folder called ‘mail-form-data’. Inside that folder, create a new document, and call it ‘mail-form-data.php’. Inside this document, place the following PHP function, and customise it to suit!:

<?php

function mailFormData($data) {
    // $data (array) contains the form's sent data
    $name = $data['name'];
    $email = $data['email'];
    $phone = $data['phone'];
    $website = $data['website'];
    $message = $data['message'];
    
    // perform form data validation - we can use Kirby's validators,
    // available via "v":
    $errors = array();
    
    if(empty(trim($name))){ $errors[] = 'name'; }
    if(!v::email($data['email'])) { $errors[] = 'email'; }
    if(!empty($website)){ $errors[] = 'website'; }
    
    $result = array();
    $result['errors'] = $errors;
    
    // if we have validation errors, we can stop and return them:
    if(!empty($errors)){
        $result['success'] = false;
        $result['msg'] = 'Validation Failed';
        return $result;
    }
    
    // if we have no errors, we can go ahead and build an email message.
    // $to, $from and $subject can be hard-coded here, or can alternatively
    // be retrieved from values entered by the user in a page:
    $to = 'recipient@example.com';
    $from = $email;
    $subject = 'Message From Your Website';
    $body = <<<BODY

From: {$name}
--------------------------------------------------------
Email: {$email}
--------------------------------------------------------
Phone: {$phone}
--------------------------------------------------------
Message:

{$message}
BODY;
    
    // now, let's try sending the email:
    $email = email(array('to' => $to,'from' => $from,'subject' => $subject,'body' => $body));
    if($email->send()){
        // email was sent successfully
        $result['success'] = true;
        $result['msg'] = "Email sent successfully.";
    } else {
        // email delivery was not successful - report error
        $result['success'] = false;
        $result['msg'] = 'Email Delivery Failed: ' . $email->error()->message();
    }
    
    return $result;
}

Please be aware that it’s likely that this code still has errors, and can be optimised. Hopefully others will continue to tip in and improve on it!

13 Likes

Hey guys, is this the best practice to do e-mail forms in Kirby? If yes - where do the user e-mails go to when they submit the form?

It depends what your needs are. I would definitely recommend using the Uniform plugin. The form submissions can sent to you as an email, or you can log them to a file on the server, or store them in a database… or all three :slight_smile:

Kirby does have a built in email class if you don’t want to use the plugin, but i have never used it so cant help much other then point you at the docs for it.

If you are not familiar with PHP form handling, use the Uniform plugin. It implements some best practices, including CSRF tokens, the Post-Redirect-Get pattern, a honeypot etc. and has actions for common form actions like uploading, sending email…

If it’s only to send emails I’ve already created a “mini plugin” for Kirby 2 with the help of @bastianallgeier.
No ajax, with honeypot.