Headless WordPress

Forms and Search in a Headless WordPress Site

Two features a WordPress theme gave you free that a headless frontend has to rebuild — with the spam, deliverability and relevance problems that come with them.

By 6 min read
WordPress admin panel connected by an API to a separate frontend app

Going headless trades a lot of built-in functionality for control. Two things people consistently underestimate are forms and search, because both are invisible infrastructure in a normal WordPress site.

Here's what actually has to be rebuilt and the decisions involved.

Why forms break

A WordPress form plugin does three things: renders HTML into a theme, runs its own JavaScript for validation and submission, and handles the submission server-side — storing it, emailing it, and running spam checks.

In a headless setup the first two are gone, because there's no theme to render into. The third still works, which means the usual approach is to build the form in your frontend and post to something that handles the submission.

That something can be WordPress — a custom REST endpoint, or a form plugin's own API if it has one — or a third-party form service. Both are legitimate.

Posting to WordPress

A custom REST endpoint is straightforward and keeps everything in one system: submissions are stored in WordPress, visible in the admin, and exportable alongside your other data.

  • Register the route with a permission callback of __return_true, deliberately, because the caller is an anonymous visitor.
  • Validate and sanitise every field through the args definition, so the handler can trust its input.
  • Store the submission first, then attempt notification. A failed email must never mean a lost enquiry.
  • Rate limit the endpoint. A public write endpoint without rate limiting is a spam endpoint the day someone finds it.
  • Return specific validation errors so the frontend can highlight the right field.
  • Configure CORS for your frontend's origin, since the browser is calling WordPress cross-origin.

Using a form service instead

A dedicated form service handles storage, notification, spam filtering and often a submissions dashboard, with no backend work at all.

It's a reasonable choice when the form is simple and the submissions don't need to live in WordPress. The trade-offs are a subscription, another system to check, and your submission data sitting with a third party — which matters for a contact form collecting personal details.

If the submissions need to reach a CRM anyway, a service that integrates directly may be less work than building the same path yourself.

Spam, which will find you

A public form endpoint attracts automated submissions within days of going live. Plan for it before launch rather than after the first hundred.

  • A honeypot field, hidden from people and from assistive technology, that bots fill in. Cheap and catches a surprising amount.
  • A time check: a form submitted under a couple of seconds after the page loaded wasn't filled in by a person.
  • A CAPTCHA or proof-of-work challenge, ideally invisible to legitimate users.
  • Rate limiting per IP at the endpoint or the edge.
  • Server-side content heuristics — a message that's a wall of links, or a name containing a URL.
  • Answer spam submissions with a success response so a bot learns nothing about what was filtered.

Email deliverability

This catches people out in every headless build, and in plenty of normal ones. Email sent by PHP from a web server frequently lands in spam or is rejected outright, because the server isn't an authorised sender for your domain.

Send through a transactional email service with proper SPF, DKIM and DMARC records on your domain. That's the difference between notifications arriving and notifications silently not arriving.

Also consider an acknowledgement email to the person who submitted. It confirms the message arrived, which reduces duplicate submissions and support queries — and it exercises the email path often enough that you notice when it breaks.

Monitor it. A form that stops delivering looks exactly like a form nobody is using, and the gap is usually discovered weeks later.

Search: why the built-in one is weak

WordPress's core search does a LIKE query against post titles and content. It has no relevance ranking beyond date, no typo tolerance, no stemming, no weighting and no faceting. It also doesn't search custom fields or taxonomies unless you make it.

In a theme, people live with it. Going headless is a good moment to reconsider, because you're rebuilding the interface anyway and the REST API's search parameter inherits all the same limitations.

Search options for a headless site

  • The REST API's search parameter — free, no dependencies, and adequate for a small site where people mostly know what they're looking for.
  • A custom endpoint with a better query: search titles, excerpts, selected meta fields and taxonomy terms, with weighting so a title match ranks above a body match. A decent middle ground.
  • A hosted search service — index your content on publish, query it from the frontend. Typo tolerance, instant results, faceting and analytics, at the cost of a subscription and an index to keep in sync.
  • A self-hosted search engine, for when the data can't leave your infrastructure. Most capable, most operational work.
  • Client-side search over a prebuilt index, which works well for a site with a few hundred pages and no server-side search at all.

Keeping a search index in sync

Any external search means a second copy of your content that can drift. Index on publish and on update, and remove on delete or unpublish — a search result linking to a deleted post is a bad look.

Use a webhook from WordPress rather than a scheduled full reindex, so changes appear immediately. Keep a full reindex available as a repair mechanism, because indexes do get out of step.

Handle the failure case: if indexing fails, the content still needs to publish. Queue the index update rather than blocking the save.

Search that's actually useful

  • Show results as the person types, if the backend can keep up.
  • Handle no results properly — suggest alternatives, show popular content, offer the contact page.
  • Highlight the matched terms in the results.
  • Log what people search for. It's the clearest signal you have about what your content is missing.
  • Make sure results are keyboard navigable and announced to screen readers.
  • Noindex the search results pages themselves; they're infinite and thin.

Frequently asked questions

How do forms work on a headless WordPress site?

You build the form in the frontend and post it somewhere that handles the submission — a custom WordPress REST endpoint, a form plugin's API, or a third-party form service. The plugin's own HTML and JavaScript are gone, because there's no theme for them to render into.

Why are my form notification emails going to spam?

Because they're being sent by PHP from a web server that isn't an authorised sender for your domain. Send through a transactional email service and set up SPF, DKIM and DMARC records. This is the single most common cause of 'the contact form doesn't work' on any WordPress site, headless or not.

How do I stop spam on a headless form endpoint?

Layer several cheap checks: a honeypot field, a time check rejecting submissions made seconds after page load, rate limiting per IP, and an invisible CAPTCHA. Answer spam with a success response so bots learn nothing. Expect automated submissions within days of going live.

Is WordPress search good enough for a headless site?

Only for small sites where visitors mostly know what they're looking for. Core search is a LIKE query with no relevance ranking, typo tolerance or field weighting, and the REST API's search parameter inherits all of it. Rebuilding the frontend is a good moment to replace it properly.

Should I use a hosted search service for headless WordPress?

If search matters to how people use the site, yes — you get typo tolerance, instant results, faceting and analytics for far less work than building equivalents. The costs are a subscription and an index to keep in sync, which means indexing on publish via a webhook and keeping a full reindex available for repairs.

Topics

  • headless WordPress forms
  • headless search
  • WordPress API forms
  • headless CMS search