Build Your Own WordPress Contact Form With An Attachment Aupport And JavaScript Validation

A contact form is an absolute must for a professional blog or website. It is quite common these days to give your readers the opportunity to send you a message (also with an attachment) straight from your website without accessing their e-mailboxes. In this tutorial I will show you how to enclose such functionality inside a short WordPress plugin.

There are at least a dozen contact form WordPress plugins, but I always prefer to write code from scratch to sharpen my plugin development skills and to better understand how different things work inside WordPress. I encourage you to do the same. In this tutorial, we will discuss and use the following WordPress features:

We will also learn how to validate the contents of the contact form fields by using JavaScript.

For simplicity, we will use a WordPress default template and focus on the sending method, paying no attention to the form styling issues.

Step 1: Creating our plugin file and contact form markup

Let's start with creating our plugin file named contact-form.php. We add the file directly to the wp-content/plugins folder inside WordPress installation. We don't have to create a separate directory for our plugin, since it consists of one file only. At the beginning of our plugin file we have to include the following standardized comments that allow WordPress to recognize our plugin:

<?php
/*
Plugin Name: Contact Form
Plugin URI: http://www.kminek.pl/lab/wordpress-contact-form-with-attachment-support/#
Description: Simple WordPress contact form with attachment support and JavaScript validation.
Author: Grzegorz Wójcik
Version: 1.0
Author URI: http://www.kminek.pl/
*/
?>

It's now time to create our contact form markup:

<div id="commentform"><h3>Contact Form</h3>

 <form action="" method="post" enctype="multipart/form-data" style="text-align: left">

 <p><input type="text" name="author" id="author" value="" size="22" /> <label for="author"><small>Your name*</small></label></p>

 <p><input type="text" name="email" id="email" value="" size="22" /> <label for="email"><small>Your contact e-mail*</small></label></p>

 <p><input type="text" name="subject" id="subject" value="" size="22" /> <label for="subject"><small>Subject*</small></label></p>

 <p><textarea name="message" id="message" cols="100%" rows="10">type your message here...</textarea></p>

 <p><label for="attachment"><small>Attachment</small></label> <input type="file" name="attachment" id="attachment" /></p>

 <p><input name="send" type="submit" id="send" value="Send" /></p>

 <input type="hidden" name="contact_form_submitted" value="1">

 </form>

</div>

As you can see, there is nothing unusual about the above markup - it is just a basic HTML form with some standard fields (such as author, email, subject, message, attachment). However, there are a few things that are worth mentioning here:

Step 2: Create shortcode to output contact form markup

Next we will create a PHP function named contact_form_markup() which will return our contact form markup. I'd like to emphasize that we do not want to echo the form markup; we just want the markup to be returned. This is required by WordPress Shortcode API to work correctly.

function contact_form_markup() {

$form_action    = get_permalink();
$author_default = $_COOKIE['comment_author_'.COOKIEHASH];
$email_default  = $_COOKIE['comment_author_email_'.COOKIEHASH];

$markup = <<<EOT

<div id="commentform"><h3>Contact Form</h3>

   <form action="{$form_action}" method="post" enctype="multipart/form-data" style="text-align: left">

   <p><input type="text" name="author" id="author" value="{$author_default}" size="22" /> <label for="author"><small>Your name*</small></label></p>
   <p><input type="text" name="email" id="email" value="{$email_default}" size="22" /> <label for="email"><small>Your contact e-mail*</small></label></p>
   <p><input type="text" name="subject" id="subject" value="" size="22" /> <label for="subject"><small>Subject*</small></label></p>
   <p><textarea name="message" id="message" cols="100%" rows="10">type your message here...</textarea></p>
   <p><label for="attachment"><small>Attachment</small></label> <input type="file" name="attachment" id="attachment" /></p>
   <p><input name="send" type="submit" id="send" value="Send" /></p>

   <input type="hidden" name="contact_form_submitted" value="1">

   </form>

</div>

EOT;

return $markup;

}

We place the form markup inside $markup variable using heredoc syntax available in PHP. At this point, if we wouldn't like to create a shortcode, we can just manually add our contact form to any template file using the following code:

if (function_exists('contact_form_markup')) echo contact_form_markup();

While the plugin is disabled it is a good practice to check if the plugin function exists in order to prevent display errors.

But it is far better to use a shortcode solution, since it will enable us to move the contact form around and to insert it in various locations inside WordPress post/page content. Actually, it is a matter of adding just one line to our plugin code to create a usable contact form shortcode:

add_shortcode('contact_form', 'contact_form_markup');

The above code will create the [contact_form] shortcode which can be placed inside post / page content:

At the end of this step, let me discuss briefly three variables defined at the beginning of contact_form_markup() function:

Step 3: Using init hook

Hooks provided by WordPress allow us to call our plugin functions at a specific time or in a specific context. One of the most powerful and frequently used is init hook which runs after WordPress has finished loading but before any HTTP headers are sent. It is ideal for intercepting GET or POST variables or performing custom redirects.

Now we will write the contact_form_process() function that will be the heart of our plugin. This function will process contact form data, perform validation checks and send an e-mail with an optional attachment. We will hook it to the init hook. Remember, by doing so WordPress will execute our function on every generated page.

We begin our function with a simple check:
if ( !isset($_POST['contact_form_submitted']) ) return;

Do you remember the hidden form variable from the first step? We are using it here to tell WordPress that if our form was not submitted, then leave the contact_form_process() function and do nothing (return always stops execution of the function).

Next we perform some standard data sanitization, stripping any redundant whitespaces and possible malicious code in submitted data:

$author  = ( isset($_POST['author']) )  ? trim(strip_tags($_POST['author'])) : null;
$email   = ( isset($_POST['email']) )   ? trim(strip_tags($_POST['email'])) : null;
$subject = ( isset($_POST['subject']) ) ? trim(strip_tags($_POST['subject'])) : null;
$message = ( isset($_POST['message']) ) ? trim(strip_tags($_POST['message'])) : null;

Now, it's time to validate the data. We check to see if the user filled in the required contact form fields (marked with the asterisk). We also validate the e-mail address by using the is_email() WordPress core function. Inside your plugin you can use just about any function loaded by default by the WordPress core:

if ( $author == '' ) wp_die('Error: please fill the required field (name).');
if ( !is_email($email) ) wp_die('Error: please enter a valid email address.');
if ( $subject == '' ) wp_die('Error: please fill the required field (subject).');

We also used another WordPress core function - wp_die(). It is a WordPress wrapper function for standard exit() call in PHP, producing nice layout around exit message passed as parameter:

At this point our function should look like this:

function contact_form_process() {

 if ( !isset($_POST['contact_form_submitted']) ) return;

 $author  = ( isset($_POST['author']) )  ? trim(strip_tags($_POST['author'])) : null;
 $email   = ( isset($_POST['email']) )   ? trim(strip_tags($_POST['email'])) : null;
 $subject = ( isset($_POST['subject']) ) ? trim(strip_tags($_POST['subject'])) : null;
 $message = ( isset($_POST['message']) ) ? trim(strip_tags($_POST['message'])) : null;

 if ( $author == '' ) wp_die('Error: please fill the required field (name).');
 if ( !is_email($email) ) wp_die('Error: please enter a valid email address.');
 if ( $subject == '' ) wp_die('Error: please fill the required field (subject).');

 //we will add e-mail sending support here soon

 header('Location: ' . $_SERVER['HTTP_REFERER']);
 exit();

}

At the end of our function we perform redirect in order to take the user back to our contact form page. We don't have to worry where the contact form is placed because we know where the form originated. Global PHP Server variable - $_SERVER['HTTP_REFERER'] holds that URL for us.

We hook our form processing function to init hook as follows:

add_action('init', 'contact_form_process');

Now you can safely activate the plugin inside the WordPress admin area and play with the form and validation checks. Of course no mail will be sent yet, since we will add mail sending support in the next step.

Step 4: Sending e-mails with phpMailer class

If you look at the wp-includes directory inside WordPress distribution, you will find the class-phpmailer.php file. By default this file is not included by the WordPress core. It is included only when you use the wp_mail() WordPress function which acts as a wrapper for the phpMailer class. But we will disregard the wp_mail() function and learn how to interact with the phpMailer class directly.

Within our contact_form_process() function, first we include the class file and create a class object as follows:

require_once ABSPATH . WPINC . '/class-phpmailer.php';

$mail_to_send = new PHPMailer();

Notice how the file path is constructed by using constants offered by WordPress. ABSPATH is one of the best known WordPress constants. It holds a filesystem path to the WordPress installation. WPINC holds the name of includes directory within distribution.

Next, we set some basic object properties (assigning variables defined earlier) required to send an e-mail successfully. The following is rather self-explanatory:

$mail_to_send->FromName = $author;
$mail_to_send->From     = $email;
$mail_to_send->Subject  = $subject;
$mail_to_send->Body     = $message;

$mail_to_send->AddReplyTo($email);
$mail_to_send->AddAddress('[email protected]'); //contact form destination e-mail

Now it's time to handle the attachment field. We will be working with the $_FILES super global PHP variable. This variable is a multi-dimensional array containing information about all submitted files. When someone inserts a file inside our attachment form field, all information about this upload will be stored inside the $_FILES['attachment'] array:

To attach a file to an e-mail when using PHPMailer class you invoke AddAttachment() method - which accepts following parameters:

AddAttachment($attachment_file_path, $attachment_file_name);

so we can easily attach our uploaded file with following statement:

$mail_to_send->AddAttachment($_FILES['attachment']['tmp_name'], $_FILES['attachment']['name']);

Below you can see the entire attachment handling part (notice the use of the is_uploaded_file() PHP function to add extra security to our script):

if ( !$_FILES['attachment']['error'] == 4 ) { //something was send

   if ( $_FILES['attachment']['error'] == 0 && is_uploaded_file($_FILES['attachment']['tmp_name']) )

      $mail_to_send->AddAttachment($_FILES['attachment']['tmp_name'], $_FILES['attachment']['name']);

   else

      wp_die('Error: there was a problem with the file upload. Try again later.');

}

We have the upload in place so now all we have to do is to send an e-mail:

if ( !$mail_to_send->Send() ) wp_die('Error: unable to send e-mail - status code: ' . $mail_to_send->ErrorInfo);

The Send() method sends an email and returns true (success) or false (failure, for instance when SMTP sever is down).

Step 5: 'Thank you' message

There is one final task. We want to display the message 'Thank you for your inquiry. We will contact you shortly to answer your questions.' once the inquiry is successfully submited (just as on the screenshot above). To do so we must:

  1. initialize PHP sessions in WordPress by placing session_start() at the begining of the contact_form_process() function
  2. set the $_SESSION['contact_form_success'] session variable just before the redirect inside contact_form_process() function
  3. read session variable inside contact_form_markup() function - if it is present - we will add the message to the contact form markup and destroy session variable.

PHP sessions are the best way to remember variable states between successive requests. Here is our plugin code with the above changes (with header comment stripped for clarity):

<?php

function contact_form_markup() {

$form_action = get_permalink();
$author_default = $_COOKIE['comment_author_'.COOKIEHASH];
$email_default = $_COOKIE['comment_author_email_'.COOKIEHASH];

if ( ($_SESSION['contact_form_success']) ) {
$contact_form_success = '<p style="color: green"><strong>Thank you for your inquiry. We will contact you shortly to answer your questions.</strong></p>';
unset($_SESSION['contact_form_success']);
}

$markup = <<<EOT

<div id="commentform"><h3>Contact Form</h3>

{$contact_form_success}

<form action="{$form_action}" method="post" enctype="multipart/form-data" style="text-align: left">

<p><input type="text" name="author" id="author" value="{$author_default}" size="22" /> <label for="author"><small>Your name*</small></label></p>
<p><input type="text" name="email" id="email" value="{$email_default}" size="22" /> <label for="email"><small>Your contact e-mail*</small></label></p>
<p><input type="text" name="subject" id="subject" value="" size="22" /> <label for="subject"><small>Subject*</small></label></p>
<p><textarea name="message" id="message" cols="100%" rows="10">type your message here...</textarea></p>
<p><label for="attachment"><small>Attachment</small></label> <input type="file" name="attachment" id="attachment" /></p>
<p><input name="send" type="submit" id="send" value="Send" /></p>

<input type="hidden" name="contact_form_submitted" value="1">

</form>

</div>

EOT;

return $markup;

}

add_shortcode('contact_form', 'contact_form_markup');



function contact_form_process() {

session_start();

if ( !isset($_POST['contact_form_submitted']) ) return;

$author = ( isset($_POST['author']) ) ? trim(strip_tags($_POST['author'])) : null;
$email = ( isset($_POST['email']) ) ? trim(strip_tags($_POST['email'])) : null;
$subject = ( isset($_POST['subject']) ) ? trim(strip_tags($_POST['subject'])) : null;
$message = ( isset($_POST['message']) ) ? trim(strip_tags($_POST['message'])) : null;

if ( $author == '' ) wp_die('Error: please fill the required field (name).');
if ( !is_email($email) ) wp_die('Error: please enter a valid email address.');
if ( $subject == '' ) wp_die('Error: please fill the required field (subject).');

require_once ABSPATH . WPINC . '/class-phpmailer.php';

$mail_to_send = new PHPMailer();

$mail_to_send->FromName = $author;
$mail_to_send->From = $email;
$mail_to_send->Subject = $subject;
$mail_to_send->Body = $message;

$mail_to_send->AddReplyTo($email);
$mail_to_send->AddAddress('[email protected]'); //contact form destination e-mail

if ( !$_FILES['attachment']['error'] == 4 ) { //something was send

   if ( $_FILES['attachment']['error'] == 0 && is_uploaded_file($_FILES['attachment']['tmp_name']) )

      $mail_to_send->AddAttachment($_FILES['attachment']['tmp_name'], $_FILES['attachment']['name']);

   else

      wp_die('Error: there was a problem with file upload. Try again later.');

}



if(!$mail_to_send->Send()) wp_die('Error: unable to send e-mail - status code: ' . $mail_to_send->ErrorInfo);


$_SESSION['contact_form_success'] = 1;

header('Location: ' . $_SERVER['HTTP_REFERER']);
exit();

}

add_action('init', 'contact_form_process');

?>

Step 6: Adding simple JavaScript validation

Our contact form is now fully operational. We have server-side validation in place. To enhance user's experience a bit, we will add simple JavaScript validation. Remember, you should NEVER rely on the client-side validation alone.

To begin with, we attach our JavaScript validation function to form's onsubmit event inside contact_form_markup() function:

<form onsubmit="return validateForm(this);" action="{$form_action}" method="post" enctype="multipart/form-data" style="text-align: left">

If the validateForm() JavaScript function returns true, our form will be submitted. Otherwise it won't be. JavaScript keyword this always points to the current object, i.e. contact form in our example.

function validateForm(form) {

   var errors = '';

   var regexpEmail = /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/;

   if (!form.author.value) errors += "Error: please fill the required field (name).\n";
   if (!regexpEmail.test(form.email.value)) errors += "Error: please enter a valid email address.\n";
   if (!form.subject.value) errors += "Error: please fill the required field (subject).\n";

   if (errors != '') {
      alert(errors);
      return false;
   }

   return true;

}

At the beginning we defined the errors variable as an empty string. Then afterwards we check each form field to see if it meets a certain condition and if it does, we append the error message to this variable. If there are no errors, the errors variable will remain an empty string. But if there are any errors we alert this variable and stop the execution of the function by returning false. We test e-mail address against quite fancy regular expression (borrowed from wForms 2.0 library).

Now we will output our JavaScript code inside <head> section on every WordPress page. First you have to create the PHP function that echos the code:

function contact_form_js() { ?>

<script type="text/javascript">
function validateForm(form) {

   var errors = '';
   var regexpEmail = /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/;

   if (!form.author.value) errors += "Error: please fill the required field (name).\n";
   if (!regexpEmail.test(form.email.value)) errors += "Error: please enter a valid email address.\n";
   if (!form.subject.value) errors += "Error: please fill the required field (subject).\n";

   if (errors != '') {
      alert(errors);
      return false;
   }

return true;

}
</script>

<?php }

Then, hook it to the wp_head hook:

add_action('wp_head', 'contact_form_js');

That's all. Hope you enjoyed it! :)

Like it or not? Leave your comments and suggestions here.

See also:

by Grzegorz Wójcik
my e-mail address
© 2007-2025 kminek.pl