
How to Create a Form in WordPress
Forms are the unsung heroes of user interaction on the web. Whether you’re collecting feedback, generating leads, or allowing users to submit content, knowing how to create forms in WordPress will help bridge the gap between your audience and your website’s goals. From a simple “Contact Us” page to a multi-step survey, the right form can transform passive visitors into engaged participants.
Creating forms in WordPress doesn’t have to mean settling for a one-size-fits-all solution. Thanks to WordPress’s flexibility, you can create anything from a basic email capture to a sophisticated front end submission system, with no coding expertise required (unless you want to dive into the deep end).
In this guide, we’ll walk through practical methods to build forms in WordPress:
- Plugins for drag-and-drop simplicity
- Advanced Custom Fields (ACF)
- Custom code for developers craving full control
Common use cases for WordPress forms
Forms serve as versatile tools for both site owners and visitors. Identifying your goal will help you choose the right method and avoid overcomplicating your setup. Below are some of the most common scenarios.
- Contact forms
- The bread and butter of business websites. Let users ask questions, request quotes, or report issues without sharing your email publicly.
- Surveys and feedback
- Gather opinions, conduct market research, or improve customer experience with multi-field forms (ratings, dropdowns, checkboxes).
- Registrations and sign-ups
- Event tickets, newsletter subscriptions, or membership sites. Integrate with tools like WooCommerce or LearnDash for paid access.
- Lead generation
- Capture potential clients with landing page forms (e.g., “Download Our Free Guide”). Connect to email marketing platforms like Mailchimp or HubSpot.
- User-generated content
- Allow visitors to submit listings (e.g., job boards, directories), testimonials, or blog posts.
- Payment and donations
- Sell products, collect donations, or accept bookings with payment gateway integrations.
3 ways to create forms in WordPress
In this section, we’ll look at how to build forms using a dedicated plugin, how to create forms in WordPress using ACF, and how to build them from the ground up with HTML, CSS, and PHP.
Form plugins
Plugins are your best bet if you’re looking for the simplest way to create forms. They eliminate the need for coding and offer ready-to-use solutions packed with features like spam protection, email integrations, and even payment processing. We’ve assembled a few of the most popular form plugins below, but this is by no means an exhaustive list.
WPForms (free and premium versions) is a popular choice, with over 6 million active installations. Its drag-and-drop interface and 1,500+ templates simplify the process of building contact forms, surveys, and payment forms in minutes. For example, a small business owner could use WPForms to create a contact form with a file upload option, while an online store might leverage its Stripe integration for checkout forms.
Contact Form 7 (free) is a great choice for those who prefer lightweight, no-frills solutions. While it does require some manual setup using HTML shortcodes, it’s highly customizable. Developers often favor it for basic contact pages where extra features aren’t needed.
For advanced needs, Gravity Forms (premium) stands out. It supports conditional logic, multi-page forms, and CRM integrations, making it a fit for complex projects. A nonprofit, for instance, could use Gravity Forms to create a donation form with recurring payments or connect it to Zapier for automated workflows.
Formidable Forms (free and premium) excels at data-driven forms. If you need to build calculators, directories, or detailed surveys, its front end display tools and integrations with payment services simplify the process.
Building forms with Advanced Custom Fields (ACF)
Advanced Custom Fields (ACF) is a powerful WordPress plugin widely used to extend content management by adding custom fields to posts, pages, or user profiles. While ACF is often employed for structured editing, it can also be used to create forms in WordPress, making it a valuable tool for developers building custom submission workflows. This method is particularly useful for scenarios like user-generated content (e.g., directory listings, event submissions) or front end profile editing, where form data directly integrates with WordPress’s database structure.
ACF shines when your form needs to interact seamlessly with custom post types, taxonomies, or user meta data. For example, it allows users to submit blog drafts, update their profiles, or contribute listings to a directory—all without accessing the admin dashboard. Its built-in validation ensures fields like emails or required inputs are handled properly, and forms naturally inherit your theme’s styling for consistent design.
If you have experience using ACF, you can use their tutorial on how to create a front end form to get started. For those new to ACF, check out our free ebook, Getting Started With ACF.
Creating custom-coded forms in WordPress
For developers comfortable with PHP and HTML, building a custom contact form in WordPress offers complete control over functionality and design. This method avoids plugin dependencies and minimizes bloat, but requires attention to security and validation. Below is a step-by-step guide to creating a simple contact form.
Step 1: Create the form’s HTML
This HTML creates a user-facing contact form. Submissions will be sent to WordPress’s secure form handler. Add this to a custom page template (e.g., `page-contact.php`), a theme file, or use the shortcode provided in Step 4.
xml
<form id="custom-contact-form" method="POST" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<input type="hidden" name="action" value="custom_contact_form">
<?php wp_nonce_field('custom_contact_form', 'cf_nonce'); ?>
<div class="form-group">
<label for="name">Your Name*</label>
<input type="text" name="cf_name" id="name" required>
</div>
<div class="form-group">
<label for="email">Your Email*</label>
<input type="email" name="cf_email" id="email" required>
</div>
<div class="form-group">
<label for="message">Message*</label>
<textarea name="cf_message" id="message" rows="6" required></textarea>
</div>
<!-- Honeypot anti-spam field (hidden) -->
<div style="position: absolute; left: -9999px;">
<input type="text" name="cf_honeypot" tabindex="-1">
</div>
<input type="submit" name="cf_submit" value="Send Message">
</form>
Step 2: Process form submissions
The PHP code below handles sanitization, validation, email sending, and error management. This can be added to your theme’s `functions.php`, or included in a custom plugin. In general, you should avoid editing `functions.php` directly unless you’re using a child theme. Create a child theme first to prevent losing changes during theme updates.
php
// Handle form submission
add_action('admin_post_custom_contact_form', 'handle_custom_contact_form');
add_action('admin_post_nopriv_custom_contact_form', 'handle_custom_contact_form');
function handle_custom_contact_form() {
// Verify nonce
if (!isset($_POST['cf_nonce']) || !wp_verify_nonce($_POST['cf_nonce'], 'custom_contact_form')) {
wp_safe_redirect(home_url('/?form_error=security'));
exit;
}
// Honeypot spam check
if (!empty($_POST['cf_honeypot'])) {
wp_safe_redirect(home_url('/?form_error=spam'));
exit;
}
// Sanitize inputs
$name = sanitize_text_field($_POST['cf_name'] ?? '');
$email = sanitize_email($_POST['cf_email'] ?? '');
$message = sanitize_textarea_field($_POST['cf_message'] ?? '');
// Validate
$errors = [];
if (empty($name)) $errors[] = 'name';
if (empty($email) || !is_email($email)) $errors[] = 'email';
if (empty($message)) $errors[] = 'message';
if (!empty($errors)) {
wp_safe_redirect(home_url('/?form_errors=' . implode(',', $errors)));
exit;
}
// Send email (secure headers)
$to = get_option('admin_email');
$subject = 'New message from ' . esc_html($name);
$headers = [
'Content-Type: text/html; charset=UTF-8',
'From: ' . get_option('blogname') . ' <' . get_option('admin_email') . '>',
'Reply-To: ' . esc_html($name) . ' <' . sanitize_email($email) . '>'
];
$message_body = sprintf(
'<p><strong>Name:</strong> %s<br><strong>Email:</strong> %s<br><strong>Message:</strong></p>%s',
esc_html($name),
sanitize_email($email),
wp_kses_post(wpautop($message))
);
wp_mail($to, $subject, $message_body, $headers);
// Redirect to success page
wp_safe_redirect(home_url('/thank-you/'));
exit;
}
Step 3: Display errors and success
There are a few steps we should take to ensure your form handles feedback gracefully while staying secure.
A nonce (“number used once”) acts like a temporary security pass. Generated via wp_nonce_field(), it ensures submissions come from your form—not a forged request. It’s worth noting that caching the nonce could cause it to expire and block legitimate submissions. If you’re using a caching plugin, making sure to exclude the contact form’s page to prevent this.
Caching provided by your host may already have some rules set up to exclude certain pages from being cached. If you’re hosting with WP Engine, you may need to reach out to support to set up custom cache exclusions.
If caching must stay enabled on your contact page, you can use AJAX to fetch a fresh nonce dynamically via JavaScript on page load:
php
// In your form template, fetch a nonce via AJAX
<script>
document.addEventListener('DOMContentLoaded', function() {
fetch('/wp-admin/admin-ajax.php?action=generate_nonce')
.then(response => response.text())
.then(nonce => {
document.getElementById('nonce-field').value = nonce;
});
});
</script>
// In functions.php
add_action('wp_ajax_generate_nonce', 'generate_nonce_ajax');
add_action('wp_ajax_nopriv_generate_nonce', 'generate_nonce_ajax');
function generate_nonce_ajax() {
wp_send_json_success(wp_create_nonce('custom_contact_form'));
}
Next up: sanitization, where we scrub user inputs clean. Functions like `sanitize_text_field()` or `sanitize_email()` remove harmful code from form data, turning potential security risks into harmless plain text.
Finally, the honeypot is a hidden field added to your form with CSS tricks. Humans won’t see it, but spam bots often blindly fill it out. In your PHP code, a simple check like if (!empty($_POST[‘cf_honeypot’])) flags these submissions as spam.
These layers work silently in the background, keeping your form secure while staying invisible to real users.
php
<?php
if (isset($_GET['form_errors'])) {
$errors = explode(',', $_GET['form_errors']);
echo '<div class="form-error">';
if (in_array('name', $errors)) echo '<p>Please enter a valid name.</p>';
if (in_array('email', $errors)) echo '<p>Please enter a valid email.</p>';
if (in_array('message', $errors)) echo '<p>Message cannot be empty.</p>';
echo '</div>';
}
if (isset($_GET['form_error'])) {
echo '<div class="form-error">';
if ($_GET['form_error'] === 'security') echo '<p>Security check failed. Please try again.</p>';
if ($_GET['form_error'] === 'spam') echo '<p>Spam detected.</p>';
echo '</div>';
}
?>
Step 4: Shortcode integration
Allow embedding the form in posts/pages using [custom_contact_form]. Add to your child theme’s functions.php:
php
function custom_contact_form_shortcode() {
ob_start();
?>
<form id="custom-contact-form" method="POST" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<input type="hidden" name="action" value="custom_contact_form">
<?php wp_nonce_field('custom_contact_form', 'cf_nonce'); ?>
<div class="form-group">
<label for="name">Your Name*</label>
<input type="text" name="cf_name" id="name" required>
</div>
<!-- Rest of your form HTML from Step 1 -->
</form>
<?php
return ob_get_clean();
}
add_shortcode('custom_contact_form', 'custom_contact_form_shortcode');
Step 5: CSS styling
Finally, we add some CSS to make the form more visually appealing.
css
#custom-contact-form {
max-width: 600px;
margin: 2rem auto;
padding: 2rem;
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
font-weight: 600;
margin-bottom: 0.5rem;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 0.8rem;
border: 1px solid #ddd;
border-radius: 4px;
}
.form-error {
background: #ffecec;
padding: 1rem;
margin-bottom: 1.5rem;
border: 1px solid #ffb3b3;
border-radius: 4px;
}
Conclusion
In WordPress, creating forms hinges on balancing simplicity, functionality, and security. For most users, plugins provide the fastest, most reliable solution, offering drag-and-drop builders, spam protection, and integrations without requiring coding skills.
For developers or projects demanding deeper integration with WordPress data—such as front end post submissions or user profile edits— ACF bridges the gap between structured content management and user interaction. Meanwhile, custom-coded forms remain a powerful choice for tailored solutions, though they demand rigorous attention to security and validation.
By leveraging the right tools and best practices, you can build forms that not only serve their functional purpose but also enhance engagement, trust, and conversions. Whether you’re crafting a simple contact page or a dynamic submission portal, WordPress’s flexibility ensures you’re equipped to meet any challenge.
WP Engine is known for fast and reliable hosting services. If you’re struggling to implement forms on your site, we also offer WordPress support with our managed hosting plans.