How to Create a Contact Form in WordPress Without Plugins

There are numerous plugins available for WordPress that create forms for various purposes, including contact forms. However, I prefer not to use third-party add-ons that add extra load to the site, especially when WordPress has enough built-in capabilities to achieve this.

So, how do we create a contact form using only WordPress code?

First, you need to create a separate template for the page with the contact form. Copy, for example, the single.php template and rename it. You can name it anything you want (using Latin characters, of course), as WordPress will not automatically associate this template with any specific page type like it does with category.php, for example. Let’s name it contact.php.

Open your contact.php, delete all unnecessary code from the previous template, and insert the following at the very beginning:

<?php
/*
Template Name: Contact
*/
?>

This tells WordPress that this is a template for our contact page. Next, create the contact form itself:

<form action="<?php the_permalink(); ?>" id="contactForm" method="post">
    <ul>
        <li>
            <label for="contactName">Name:</label>
            <input type="text" name="contactName" id="contactName" value="" />
        </li>
        <li>
            <label for="email">E-mail:</label>
            <input type="text" name="email" id="email" value="" />
        </li>
        <li>
            <label for="commentsText">Message:</label>
            <textarea name="comments" id="commentsText" rows="20" cols="30"></textarea>
        </li>
        <li>
            <button type="submit">Send</button>
        </li>
    </ul>
    <input type="hidden" name="submitted" id="submitted" value="true" />
</form>

You can insert this anywhere in the template based on your design. This creates a basic form with fields for the name, email, and message, plus a “send” button. However, it won’t do anything yet—we need to add functionality:

<?php

if (isset($_POST['submitted'])) {
    if (trim($_POST['contactName']) === '') {
        $nameError = 'Please enter your name.';
        $hasError = true;
    } else {
        $name = trim($_POST['contactName']);
    }

    if (trim($_POST['email']) === '') {
        $emailError = 'Please enter your email address.';
        $hasError = true;
    } else if (!preg_match("/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i", trim($_POST['email']))) {
        $emailError = 'You entered an invalid email address.';
        $hasError = true;
    } else {
        $email = trim($_POST['email']);
    }

    if (trim($_POST['comments']) === '') {
        $commentError = 'Please enter a message.';
        $hasError = true;
    } else {
        $comments = stripslashes(trim($_POST['comments']));
    }

    if (!isset($hasError)) {
        $emailTo = get_option('admin_email');
        $subject = 'Contact Form Submission from ' . $name;
        $body = "Name: $name \n\nEmail: $email \n\nMessage: $comments";
        $headers = 'From: ' . $name . ' <' . $emailTo . '>' . "\r\n" . 'Reply-To: ' . $email;

        mail($emailTo, $subject, $body, $headers);
        $emailSent = true;
    }
}
?>

Insert this code between the template definition and the get_header() function. This is the main functionality of our contact form. It checks for errors and whether the fields are filled out. If something is wrong, it shows the user an error. But to display these errors, you need to add the corresponding code near each field. Here is the final version of the contact form with error messages:

<?php if (isset($emailSent) && $emailSent == true) { ?>
    <div class="thanks">
        <p>Thank you, your message has been sent successfully.</p>
    </div>
<?php } else { ?>
    <?php if (isset($hasError) || isset($captchaError)) { ?>
        <p class="error">Sorry, there was an error.</p>
    <?php } ?>
    <form action="<?php the_permalink(); ?>" id="contactForm" method="post">
        <ul class="contactform">
            <li>
                <label for="contactName">Name:</label>
                <input type="text" name="contactName" id="contactName" value="<?php if (isset($_POST['contactName'])) echo $_POST['contactName']; ?>" class="required requiredField" />
                <?php if ($nameError != '') { ?>
                    <span class="error"><?php echo $nameError; ?></span>
                <?php } ?>
            </li>
            <li>
                <label for="email">E-mail:</label>
                <input type="text" name="email" id="email" value="<?php if (isset($_POST['email'])) echo $_POST['email']; ?>" class="required requiredField email" />
                <?php if ($emailError != '') { ?>
                    <span class="error"><?php echo $emailError; ?></span>
                <?php } ?>
            </li>
            <li>
                <label for="commentsText">Message:</label>
                <textarea name="comments" id="commentsText" rows="20" cols="50" class="required requiredField"><?php if (isset($_POST['comments'])) { if (function_exists('stripslashes')) { echo stripslashes($_POST['comments']); } else { echo $_POST['comments']; } } ?></textarea>
                <?php if ($commentError != '') { ?>
                    <span class="error"><?php echo $commentError; ?></span>
                <?php } ?>
            </li>
            <li>
                <button type="submit">Send Message</button>
            </li>
        </ul>
        <input type="hidden" name="submitted" id="submitted" value="true" />
    </form>
<?php } ?>

Our contact form is now fully functional. All that’s left is to adjust the styles to your liking:

.thanks { /*-- Success message style --*/ }
.error { /*-- Error message style --*/ }
.contactform ul, .contactform li { /*-- Form list style --*/ }

Finally, create a page in the admin panel and select the “Contact” template from the right column.