splitforms.com
WORDPRESS · CONTACT FORM

Contact form for WordPress websites

Skip Contact Form 7, WPForms, Gravity Forms, Forminator, and the rest of the bloated plugin economy. One `

` tag in your theme or a Custom HTML block sends submissions to your inbox plus the splitforms dashboard. No plugin, no `wp_options` clutter, no database table, no PHP cron job.

1,000 free submissions every month.·No credit card.
contact.phpphp25 lines
01<?php
02/**
03 * Drop this into a Custom HTML block, a page template, or any theme file.
04 * Works with Bedrock, Sage, classic themes, and the block editor.
05 */
06?>
07
08<form action="https://splitforms.com/api/submit" method="POST">
09 <input type="hidden" name="access_key" value="<?php echo esc_attr( YOUR_ACCESS_KEY ); ?>" />
10 <input type="hidden" name="redirect" value="<?php echo esc_url( home_url('/thanks') ); ?>" />
11
12 <p>
13 <label>Name <input name="name" type="text" required /></label>
14 </p>
15 <p>
16 <label>Email <input name="email" type="email" required /></label>
17 </p>
18 <p>
19 <label>Message <textarea name="message" required></textarea></label>
20 </p>
21
22 <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />
23
24 <p><button type="submit">Send</button></p>
25</form>
1,000
submissions / mo, free
14ms
median latency, edge
0
lines of backend code
17+
frameworks supported
✶ Live preview

What your WordPress contact form actually looks like.

Drop-in form backend with spam filtering, signed webhooks, and a real submissions dashboard. The same code in this preview is what you copy into your WordPress project — no SDK, no plugin, no PHP.

  • 1,000 submissions per month, free forever
  • Honeypot + AI spam classifier on every plan
  • Signed webhooks to Slack, Discord, your server
WordPress contact form on Splitforms — drop-in form backend with spam filtering and webhooks
§ 01Setup3 steps · 60 seconds · zero config

Ship a WordPress contact form without a backend.

No SDK, no PHP, no plugin. Your form posts standard FormData to one URL — submissions land in your inbox.

STEP 01GENERATE

Get your free access key

Verify your email and your access key is generated instantly. Free for 1,000 submissions per month, forever.

Create your form

By signing up, you agree to our terms and privacy policy.

STEP 02EMBED

Drop in the WordPress code

Copy the WordPress snippet on the right and paste it into your project. Replace YOUR_ACCESS_KEY with the key from step 1.

snippetphp
<?php
…
STEP 03RECEIVE

Submissions land in your inbox

Hits your dashboard and email in seconds. Forward to Slack, Discord, Sheets, Notion, or any signed webhook URL.

inbox · 1 newjust now
FROM contact@yoursite.com
New WordPress form submission
Maya Iyer maya@studio71.co
Loved the new pricing page — quick question about the 4-year plan. Are usage limits per project or account-wide?
§ 02Live demosandboxed · no key required · no submission sent

Try it now — no signup, no key.

This is a styled HTML preview of what your WordPress form will look like. Submitting opens a confirmation, no real request is sent.

preview · wordpresslocalhost:3000
✦ what just happened

Your WordPress form posts FormData to /api/submit. Splitforms validates the access key, runs the spam classifier, and forwards the parsed submission to your inbox plus the dashboard.

  • 14ms median round-trip from the edge.
  • Honeypot + classifier, no CAPTCHA.
  • Per-domain key locking out of the box.
REQUEST · POST /api/submit
{
  "access_key": "sk_live_4f9a_••••",
  "name":       "Maya Iyer",
  "email":      "maya@studio71.co",
  "message":    "…"
}
← 200 OK · { "success": true } · 14ms
§ 03Best practices5 rules · production-tested

How to ship this without regrets.

Five rules that make the difference between a form that works in the demo and a form that survives launch traffic.

  1. 01

    Define the access key as a constant in `wp-config.php` (above the 'stop editing' line). Keeps it out of your theme repo and works for both staging and production via environment.

  2. 02

    Use a Custom HTML block in the block editor for one-off contact pages — survives theme switches, no template editing required.

  3. 03

    For headless WordPress (with Next.js, Astro, etc.), there's no PHP involved — use the framework-specific snippet from the matching /forms/<framework> page.

  4. 04

    Skip every CAPTCHA plugin. WordPress sites are spam magnets, but splitforms's honeypot + classifier handles bot traffic without making humans solve puzzles.

  5. 05

    If you're on Bedrock or Sage, define the key in `.env`: `SPLITFORMS_KEY=sk_live_…` and read it via `env('SPLITFORMS_KEY')` in your blade/twig template.

§ 04Common gotchas in WordPress6 edge cases worth knowing

What bites people who skip the docs.

Worth a 60-second skim before you ship to production. Each one has caused a WordPress support ticket at least once.

⚠ gotcha

WordPress wpautop() mangles your form HTML in posts

If you paste a <form> directly into a Classic Editor post, WordPress's wpautop filter wraps random <p> tags around your inputs and breaks the markup. Use a Custom HTML block (block editor) or a theme template file instead — wpautop doesn't touch those.

⚠ gotcha

Caching plugins (WP Rocket, W3 Total Cache) cache the form page itself

Page caching is fine — your form posts to splitforms.com directly, not a WordPress endpoint, so the cached HTML still works. But if you ever switch to a WP-side handler (e.g. wp_ajax), exclude /contact/ from the page cache or submissions will hit a stale page.

⚠ gotcha

Theme-injected JavaScript can hijack form submission

Some themes (Astra, OceanWP, GeneratePress 'Premium') auto-attach AJAX handlers to every form on the page. Add data-no-ajax="true" or a custom class your theme excludes — or use a Custom HTML block which most themes leave alone.

⚠ gotcha

Cloudflare Bot Fight Mode blocks splitforms responses

If you proxy your WP site through Cloudflare with Bot Fight Mode on, the redirect from splitforms.com → /thanks may be flagged. Whitelist your domain in splitforms's allowed-domains list AND ensure /thanks is reachable without a Cloudflare challenge.

⚠ gotcha

Hardcoded YOUR_ACCESS_KEY in the PHP example needs escaping

The snippet shows <?php echo esc_attr( YOUR_ACCESS_KEY ); ?> as a placeholder. In real code, define your key as a constant in wp-config.php: define('SPLITFORMS_KEY', 'sk_live_…'); then echo esc_attr(SPLITFORMS_KEY). Don't paste the literal string into theme files.

⚠ gotcha

Wordfence and other security plugins block external form POSTs as 'leaving WordPress'

Wordfence's Live Traffic and 'Block fake Google crawlers' rules flag form submissions to non-WordPress domains as suspicious outbound activity from a logged-out user. The submission still goes through (the browser POSTs directly, bypassing PHP), but Wordfence may rate-limit or temporarily IP-ban the visitor's session, breaking subsequent page loads. Whitelist splitforms.com under Wordfence → Firewall → Allowlisted Services, or move to iThemes Security / Solid Security which handles outbound endpoints more gracefully.

§ 04bNative WordPress forms…and where they break down

How WordPress handles forms without splitforms.

The shape of the problem before splitforms enters the picture — and the gap it fills for WordPress specifically.

WordPress core has no contact-form feature — every contact form on a WP site is either a plugin (Contact Form 7, WPForms, Gravity Forms, Forminator, Fluent Forms, Ninja Forms) or a custom theme template. Plugins add 3-7 database tables, increase TTFB by 50-300ms, and most require a paid SMTP plugin (WP Mail SMTP) on top because shared-host PHP mail() lands in spam. CF7 alone is 1.2MB of JS/CSS loaded on every page. Anti-spam is a separate Akismet subscription ($10/mo for commercial use) or a paid CAPTCHA plugin. Splitforms replaces the plugin: a <form> tag in a Custom HTML block, pointing at our endpoint, with a hidden access_key field. No plugin, no extra DB tables, no SMTP gymnastics.

§ 04cAlternative integration patterns2 ways to wire it

Two ways to ship splitforms on WordPress.

Pick the pattern that matches your constraints — JS budget, key-exposure tolerance, server-side opacity. Both produce the same result.

PATTERN A

Pattern A — Custom HTML block (Block Editor / Gutenberg)

Drop a Custom HTML block on any page or post. Survives theme switches and plugin updates. No PHP required, no theme file editing. Reusable Patterns let you save the form once and drop it on every page.

pattern-a.phpphp9 lines
01<form action="https://splitforms.com/api/submit" method="POST">
02 <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
03 <input type="hidden" name="redirect" value="/thanks/" />
04 <p><label>Name <input name="name" required /></label></p>
05 <p><label>Email <input name="email" type="email" required /></label></p>
06 <p><label>Message <textarea name="message" required></textarea></label></p>
07 <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />
08 <p><button type="submit">Send</button></p>
09</form>
PATTERN B

Pattern B — theme template with key from wp-config constant

For developer-managed themes (Bedrock/Sage/classic), define SPLITFORMS_KEY as a constant in wp-config.php and echo it via esc_attr(). Keeps the key out of the theme repo, lets staging and production read different keys via environment.

pattern-b.phpphp8 lines
01<?php // page-contact.php in your theme ?>
02<form action="https://splitforms.com/api/submit" method="POST">
03 <input type="hidden" name="access_key" value="<?php echo esc_attr( SPLITFORMS_KEY ); ?>" />
04 <input type="hidden" name="redirect" value="<?php echo esc_url( home_url('/thanks') ); ?>" />
05 <input name="email" type="email" required />
06 <textarea name="message" required></textarea>
07 <button type="submit">Send</button>
08</form>
§ 04dDeployment notes for WordPresshosting · env vars · CSP

Shipping WordPress + splitforms to production.

Host-specific gotchas, env-var conventions, and the boring-but-load-bearing details for putting this on the public internet.

WordPress runs on shared hosts (Bluehost, Hostinger), managed WP hosts (Kinsta, WP Engine, Pressable), or self-hosted Apache/nginx. The form's POST is cross-origin to splitforms.com, so the host doesn't matter for delivery. Caching plugins (WP Rocket, W3 Total Cache, LiteSpeed Cache) cache the page that hosts the form — that's fine, the form action URL is static. Don't proxy through WP's admin-ajax.php or wp_remote_post — adds latency and re-introduces the SMTP problem. For Multisite, use one access key per site or a shared key with form-name to disambiguate. Headless WP (Next.js/Astro front) doesn't involve PHP at all — use the matching framework's snippet.

§ 05Comparisonvs native wordpress

splitforms vs native wordpress.

What you get for free vs what you build, pay for, or do without.

FeatureNative WordPresssplitforms
Setup timeInstall plugin + configure SMTP + add reCAPTCHAPaste one form tag
Database tables added3-7 (Contact Form 7, WPForms)0
PHP code in your repoPlugin lives in /wp-content/pluginsOptional 1-line constant in wp-config.php
Spam filterAkismet ($10/mo for commercial)Built-in (free)
Email deliverabilityNeed WP Mail SMTP plugin + providerSplitforms sends from a configured domain
Submission storagePlugin's own DB tablesSplitforms dashboard, exportable
§ 06Alternative patternphp · 31 lines
ALTERNATIVE

Block editor (Gutenberg) variant — Custom HTML block

If you prefer not to touch theme files, paste this directly into a Custom HTML block on any page or post. Survives theme switches and plugin updates.

alternative.phpphp31 lines
01<!-- Paste into a Custom HTML block in the block editor -->
02<form action="https://splitforms.com/api/submit" method="POST" class="splitforms-contact">
03 <input type="hidden" name="access_key" value="REPLACE_WITH_YOUR_KEY" />
04 <input type="hidden" name="redirect" value="https://yoursite.com/thanks/" />
05 <input type="hidden" name="form-name" value="wordpress-contact" />
06
07 <p>
08 <label for="sf-name">Your name</label>
09 <input id="sf-name" name="name" type="text" required />
10 </p>
11 <p>
12 <label for="sf-email">Email</label>
13 <input id="sf-email" name="email" type="email" required />
14 </p>
15 <p>
16 <label for="sf-message">Message</label>
17 <textarea id="sf-message" name="message" required rows="5"></textarea>
18 </p>
19
20 <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />
21
22 <p><button type="submit">Send message</button></p>
23</form>
24
25<style>
26 /* Optional: minimal styling so the form doesn't look unstyled */
27 .splitforms-contact label { display: block; margin-bottom: 4px; font-weight: 600; }
28 .splitforms-contact input,
29 .splitforms-contact textarea { width: 100%; padding: 8px; box-sizing: border-box; }
30 .splitforms-contact button { padding: 10px 18px; cursor: pointer; }
31</style>
§ 07Questions6 answered

Things developers ask before they integrate.

Direct answers, no marketing fluff. Missing one? Email hello@splitforms.com.

01How do I add a contact form to WordPress without a plugin?
Two options. (1) Block editor: add a Custom HTML block, paste the form snippet, replace YOUR_ACCESS_KEY. (2) Theme file: paste the PHP/HTML snippet from this page into your page-contact.php template. Both work without installing anything.
02Does splitforms work with WordPress block editor (Gutenberg)?
Yes — use a Custom HTML block. The form survives Gutenberg's wpautop processing because Custom HTML blocks render verbatim. Reusable Patterns work too — save the form as a Pattern and drop it on any page.
03How do I handle form errors in WordPress?
If you use the redirect-style form (no JavaScript), splitforms 302s to a URL you specify on success and returns an error page on failure. For inline error handling, wrap the form in a small JS snippet that fetches splitforms.com and renders the error from data.message. See the AJAX page for the JS pattern.
04Can I use splitforms with WordPress Multisite or headless WordPress?
Yes — both. For Multisite, use one access key per site (or one shared key with a form-name field to disambiguate). For headless WP (with Next.js, Astro, etc.), the form lives in your frontend framework — see the matching framework page.
05How do I customize the success / redirect behavior?
Set <input type="hidden" name="redirect" value="https://yoursite.com/thanks/">. Build the /thanks/ page in WordPress as you normally would. Splitforms 302s on success.
06Will splitforms work with Elementor / Divi / Bricks form widgets?
The form widgets in those page builders all let you set a custom action URL. Set Action to https://splitforms.com/api/submit, Method to POST, add a hidden access_key field. Each builder hides this in a slightly different settings panel.
✻ ✻ ✻

Ship your WordPress contact form in 60 seconds.

1,000 free submissions per month. No credit card. Lock the access key to your domains, paste the snippet, watch submissions land in your inbox.

Get free access key →Read the docs
v0.1 · founders pricing locked in · early access open