A very popular feature of many themes is an Ajaxified contact form, often inserted through a shortcode. So I’m going to show you how to create one from scratch as a plugin that can be dropped into any WordPress theme.

Note: several of the techniques used in this tutorial are out of date and now not considered good practices.

1 – The Plugin File / Folder Structure

As our plugin is going to be really quite simple, we only need one folder and two files.

2 – Create the Main Plugin File

First we will put all of the plugin header code into our file. This tells WordPress about our plugin: the plugin name, author name, version number, etc. We are also declaring a global variable that contains the path to the plugin’s root folder, which we will use later.

1
2
3
4
5
6
7
8
9
10
11
/*
Plugin Name: jQuery Contact Shortcode
Plugin URI: https://pippinsplugins.com/contact-shortcode/
Description: Adds a shortcode for displaying a jQuery Validated Contact Form
Version: 1.0
Author: Pippin Williamson
Author URI: http://184.173.226.218/~pippin 
*/
 
// plugin root folder
$cs_base_dir = WP_PLUGIN_URL . '/' . str_replace(basename( __FILE__), "" ,plugin_basename(__FILE__));

Next we will write the function that displays our contact forms HTML, and also outputs our jQuery to perform the validation upon submission.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
function pippin_shortcode_contact( $atts, $content = null)	{
 
	// gives access to the plugin's base directory
	global $cs_base_dir;
 
	extract( shortcode_atts( array(
      'email' => get_bloginfo('admin_email')
      ), $atts ) );
 
		$content .= '
		<script type="text/javascript"> 
			var $j = jQuery.noConflict();
			$j(window).load(function(){				
				$j("#contact-form").submit(function() {
				  // validate and process form here
					var str = $j(this).serialize();					 
					   $j.ajax({
					   type: "POST",
					   url: "' . $cs_base_dir . 'sendmail.php",
					   data: str,
					   success: function(msg){						
							$j("#note").ajaxComplete(function(event, request, settings)
							{ 
								if(msg == "OK") // Message Sent? Show the Thank You message and hide the form
								{
									result = "Your message has been sent. Thank you!";
									$j("#fields").hide();
								}
								else
								{
									result = msg;
								}								 
								$j(this).html(result);							 
							});					 
						}					 
					 });					 
					return false;
				});			
			});
		</script>';
 
                // now we put all of the HTML for the form into a PHP string
		$content .= '<div id="post-a-comment" class="clear">';
			$content .= '<div id="fields">';
				$content .= '<h4>Send A Message</h4>';
				$content .= '<form id="contact-form" action="">';
					$content .= '<input name="to_email" type="hidden" id="to_email" value="' . $email . '"/>';
					$content .= '<p>';
						$content .= '<input name="name" type="text" id="name"/>';
						$content .= '<label class="error" for="name">Name *</label>';
					$content .= '</p>';
					$content .= '<p>';
						$content .= '<input name="email" type="text" id="email"/>';
						$content .= '<label for="email">E-mail address *</label>';
					$content .= '</p>';
					$content .= '<p><textarea rows="" cols="" name="message"></textarea></p>';
					$content .= '<p><input type="submit" value="Submit" class="button" id="contact-submit" /></p>';
				$content .= '</form>';
			$content .= '</div><!--end fields-->';
			$content .= '<div id="note"></div> <!--notification area used by jQuery/Ajax -->';
		$content .= '</div>';
	return $content;
}

The code may look more complicated than it really is, but all that I’ve done is put all of the necessary HTML and jQuery code into a single PHP string that is then returned at the end of the function.

I’m not going to go in depth and explain exactly what the code here does; that is for another tutorial.

For the purposes of this tutorial, we are keeping our form simple and only displaying name, email, and message fields. If you wish to extend the plugin with additional fields, it’s really quite simple. Please leave a comment if you need support.

Next what we need to do is add in the hook that will tie our function to a short code, and make the short code available for use.

1
add_shortcode('contact', 'pippin_shortcode_contact');

If you are unfamiliar with how to create a basic short code, check out my quick tip on creating short codes in plugins.

1
wp_enqueue_script('jquery');

That’s it for our main plugin file.

3 – Creating the Send Mail File

We now have to set up another file that will receive the information posted from our contact form, validate it, and perform the final steps, such as sending the email and displaying error / success messages.

First, create a file called sendmail.php and place it in the main plugin folder.

Next, in order to make use of core WordPress functions, we need to include wp-load.php

1
2
3
4
5
6
7
// allow us to use core wordpress functions
 
// make sure to replace this with the name of the plugin's root folder name
$plugin_name = 'contact_shortcode';
$oldURL = dirname(__FILE__);
$newURL = str_replace(DIRECTORY_SEPARATOR . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $plugin_name, '', $oldURL);
include($newURL . DIRECTORY_SEPARATOR . 'wp-load.php');

Now we are going to write a function that will check the submitted email to make sure it has a valid format.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function ValidateEmail($email)
{
	/*
	(Name) Letters, Numbers, Dots, Hyphens and Underscores
	(@ sign)
	(Domain) (with possible subdomain(s) ).
	Contains only letters, numbers, dots and hyphens (up to 255 characters)
	(. sign)
	(Extension) Letters only (up to 10 (can be increased in the future) characters)
	*/
 
	$regex = '/([a-z0-9_.-]+)'. # name

	'@'. # at

	'([a-z0-9.-]+){2,255}'. # domain & possibly subdomains

	'.'. # period

	'([a-z]+){2,10}/i'; # domain extension 

	if($email == '') { 
		return false;
	}
	else {
		$eregi = preg_replace($regex, '', $email);
	}
 
	return empty($eregi) ? true : false;
}

And finally, there is just one more piece of code to write. This next bit will detect the information sent from the contact form and store it into the necessary variables, perform email validation, check for empty fields, and then send the email if everything checks out okay.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
$post = (!empty($_POST)) ? true : false;
 
if($post)
{
	$name = stripslashes($_POST['name']);
	$subject = 'Contact Form';
	$email = trim($_POST['email']);
	$to = trim($_POST['to_email']);
	$message = stripslashes($_POST['message']);
	$error = '';
 
	// Check name
 
	if(!$name)
	{
		$error .= 'Please enter your name.<br />';
	}
 
	// Check email
 
	if(!$email)
	{
		$error .= 'Please enter an e-mail address.<br />';
	}
 
	if($email && !ValidateEmail($email))
	{
		$error .= 'Please enter a valid e-mail address.<br />';
	}
 
	// Check message (length)
 
	if(!$message || strlen($message) < 15)
	{
		$error .= "Please enter your message. It should have at least 15 characters.<br />";
	}
 
	if(!$error) // send email
	{
		$mail = wp_mail($to, $subject, $message,
			 'From: '.$name.' <'.$email.'>\r\n'
			.'Reply-To: '.$email.'\r\n'
			.'X-Mailer: PHP/' . phpversion());
 
		if($mail)
		{
			echo 'OK';
		}
 
	}
	else
	{
		echo '<div class="notification_error">'.$error.'</div>'; // set up error div for jQuery/Ajax
	}
 
}

And that’s it! We can now activate our plugin and display the contact form using:

[contact email="youraddress"]

The email parameter is optional. If you leave it blank, the admin email will be used instead.

And our final result looks like this!

Send A Message

If you have any trouble with this code, please ask in the comments below. You can also download the full plugin below.

Download disabled. This plugin is out of date and does not illustrate best practices.

Enjoy!

  1. Paul

    Thanks for this detailed tutorial. Will put it to good use.

  2. Clem

    Thanks for this tutorial and this plugin. But, IMO you should replace your ValidateEmail() function with : filter_var($email, FILTER_VALIDATE_EMAIL) 😉

    • pippin

      Why is that? I don’t know anything about filter_var

  3. cgcs

    Thanks alot for the great code, though I have one question if you can help?

    I wanted to include this in a custom template and instead of having the user activate the plugin is there anyway to hardcode it into the theme so all the user has to do is use the shortcode?

    • pippin

      @cgcs – you can simply copy and paste the function and then correct the file paths so that they point to the files in your theme folder.

  4. cgcs

    Hi again, I just wanted to say thanks it worked. This code really came in like a dark horse at a time when I really needed it. I must’ve spent 5 days trying to create a contact form shortcode and nothing worked but this. Beautiful code and many many thanks for posting this tutorial.

    • pippin

      @cgcs – you are welcome :)

  5. cgcs

    Hi again,

    If the PLUGIN_PATH is set to WP_PLUGIN_DIR and the PLUGIN_URL is set to WP_PLUGIN_URL what do I change those to so it reads my template path directories instead? Any help would be highly appreciated.

    • pippin

      You can use get_bloginfo(‘template_directory’) or get_bloginfo(‘stylesheet_directory’)

  6. cgcs

    Thanks again pippin. That worked. Although I have been mucking around in WordPress for nearly a year it’s little things like this that always trip me up. I have alot to learn about plugins. Really appreciate the help.

    • pippin

      Always glad to help.

  7. Kel

    I noticed that the using the shortcode in content, it is always above the other content on the page. Do you know of a way to fix this?

    • Pippin

      Hmm, it shouldn’t. Look in the plugin code and see if the final line of the short code function is echoing $content, or returning it. It needs to return $content.

  8. Merkados

    First of all, great tutorial. Thank you for taking the time to put it together. I wanted to take a second to advice you of a vulnerability that would be introduced by the use of the code as you have it. When you are setting the “to_email” as a hidden form item, it can be exploited and used to send email from your server to any address. Since I saw that you took good care in sanitizing the rest of the code, I thought I would tell you.
    Thank you

    Alex Centeno.

    • Pippin

      Ah yes, good call. Thanks for pointing it out.

  9. tammyhart

    Hey Pippin,

    I probably shouldn’t be reading tutorials at 2 am after a long week of work, but does the last block of code where wp_mail() resides go inside pippin_shortcode_contact()?

  10. tammyhart

    Nevermind. Now that I’ve had some sleep, I see it. :) This works great, thanks!

    • Pippin

      No problem, glad it’s working for you :)

  11. Mahabub

    thanks for share this contact from coding

  12. Smith M

    download link not working …

    • Pippin

      try now.

    • Chr Laugesen

      Thanks for the tutorial!
      Download like doesn’t work ;o)

  13. neevan

    hi thanks a very good tutus posted. this is the best for beginers but one more thing i wana show individual error one error at a time so could u help

    • Pippin

      What’s the error?

  14. neevan

    error means like fill your name till he is not filling his name it shud show the same error msg fill the name first instead fill ua name, fill ua email etc…wana show one error msg at a time

  15. neevan

    and one more thing i wana use the same form on different place based on some condition so how to create conditional shortcode

  16. Nathan Robjohn

    Hi,

    i don’t understand the root directorys you have set up? i have put my files inside the theme directory then into shortcode how would i link to that?

    • Pippin

      This is created as a plugin, so it goes in wp-content/plugins. Once you’ve put it there, you’ll be able to activate it just like any other plugin.

  17. Nathan Robjohn

    Hi Pippin,

    I have put it in my theme and then into a folder called shorts this is the code i have the form sends but for some reason doesn’t display success message or errors.


    function nathan_shortcode_contact( $atts, $content = null) {

    extract( shortcode_atts( array(
    'email' => get_bloginfo('admin_email')
    ), $atts ) );

    $content .='
    var $j = jQuery.noConflict();
    $j(window).load(function(){
    $j("#contact-form").submit(function() {
    // validate and process form here
    var str = $j(this).serialize();
    $j.ajax({
    type: "POST",
    url: "' . get_stylesheet_directory_uri() . '/short/sendmail.php",
    data: str,
    success: function(msg){
    $j("#note").ajaxComplete(function(event, request, settings)
    {
    if(msg == "OK") // Message Sent? Show the Thank You message and hide the form
    {
    result = "Your message has been sent. Thank you!";
    $j("#fields").hide();
    }
    else
    {
    result = msg;
    }
    $j(this).html(result);
    });
    }
    console.log(msg)
    });
    return false;
    });
    });
    ' ;

    // now we put all of the HTML for the form into a PHP string
    $content .= '';
    $content .= '';
    $content .= 'Enquire';
    $content .= ' ';
    $content .= '';
    $content .= '';
    $content .= '';
    $content .= 'Name *';
    $content .= '';
    $content .= '';
    $content .= '';
    $content .= 'Phone number *';
    $content .= '';
    $content .= '';
    $content .= '';
    $content .= 'Best time to call';
    $content .= '

    Morning
    Afternoon
    Anytime
    ';
    $content .= '';
    $content .= '';
    $content .= 'E-mail address *';
    $content .= '';
    $content .= '';
    $content .= 'Enquiry message *';
    $content .= '';
    $content .= '';
    $content .= '';
    $content .= '';
    $content .= '';
    return $content;
    }
    add_shortcode('contact', 'nathan_shortcode_contact');

    thats my contact-form.php

    here is my sendmail.php


    <?php
    $plugin_name = 'contact_shortcode';

    function ValidateEmail($email)
    {
    /*
    (Name) Letters, Numbers, Dots, Hyphens and Underscores
    (@ sign)
    (Domain) (with possible subdomain(s) ).
    Contains only letters, numbers, dots and hyphens (up to 255 characters)
    (. sign)
    (Extension) Letters only (up to 10 (can be increased in the future) characters)
    */

    $regex = '/([a-z0-9_.-]+)'. # name

    '@'. # at

    '([a-z0-9.-]+){2,255}'. # domain & possibly subdomains

    '.'. # period

    '([a-z]+){2,10}/i'; # domain extension

    if($email == '') {
    return false;
    }
    else {
    $eregi = preg_replace($regex, '', $email);
    }

    return empty($eregi) ? true : false;
    }

    $post = (!empty($_POST)) ? true : false;

    if($post)
    {
    $name = stripslashes($_POST['name']);
    $time = stripslashes($_POST['time']);
    $phone = stripslashes($_POST['phone']);
    $subject = 'Contact Form';
    $email = trim($_POST['email']);
    $to = trim($_POST['to_email']);
    $message = stripslashes($_POST['message']);
    $error = '';

    // Check name

    if(!$name)
    {
    $error .= 'Please enter your name.';
    }

    if(!$phone)
    {
    $error .= 'Please enter a phone number.';
    }

    if(!$time)
    {
    $error .= 'Please select a time.';
    }

    // Check email

    if(!$email)
    {
    $error .= 'Please enter an e-mail address.';
    }

    if($email && !ValidateEmail($email))
    {
    $error .= 'Please enter a valid e-mail address.';
    }

    // Check message (length)

    if(!$message || strlen($message) < 15)
    {
    $error .= "Please enter your message. It should have at least 15 characters.";
    }

    if(!$error) // send email
    {
    $contents = "Name: $name \n\nEmail: $email \n\nSubject: $subject \n\nPhone: $phone \n\nTime: $time \n\nMessage:\n $message";
    $mail = mail($to, $subject, $contents,
    'From: '.$name.' \r\n'
    .'Reply-To: '.$email.'\r\n'
    .'X-Mailer: PHP/' . phpversion());

    if($mail)
    {
    echo 'OK';
    }

    }
    else
    {
    echo ''.$error.''; // set up error div for jQuery/Ajax
    }

    }
    ?>

    • Pippin

      Sorry for being slow. Could you post the code to pastebin.com then share the link?

  18. Natoshka

    Nice simple tutorial, worked right away so thanks very much

  19. Raymon Schouwenaar

    Hi Pipin, the sample plugin download link is broken. There apears an page with the text “Download does not exist!”. Could you fix it please, it would help me a lot!

  20. Phill

    Hi Pippin!

    Are you able to indicate where this code no longer meets best practices? What would we need to do to bring it up to scratch?

    Thank you!

Error: Please enter a valid email address

Error: Invalid email