What it does
Forms lets you build the contact, quote, callback and sign-up forms your clients’ sites need — in WPClientHub, published to each site through the WPClientHub One plugin — and collects every entry into one Forms inbox across all your sites. The form runs on the client’s site: the plugin renders it, checks every answer on the server, stores the entry there and sends the notification emails from there. WPClientHub decides what the form is and keeps the copy of the entries you work from.
It is available on Agency and Scale (the Agency trial includes it) and needs WPClientHub One 2.0 or newer on the site. Sites that already use Gravity Forms, WPForms, Fluent Forms, Contact Form 7 (with Flamingo) or Ninja Forms keep them — their entries are read into the same inbox, read-only.
Where to find it
- A site’s Forms tab lists the forms built for that site with their state on the site (live, pending, draft), entry counts, the shortcode to copy, and the other form plugins found on the site. New form opens the builder.
- Forms in the sidebar is the inbox: every entry from every site, with filters, search and export.
Building a form
Start from a template — Contact form, Quote request (two steps with a file upload), Request a callback (shows the date and time only when “a specific time” is picked), Newsletter sign-up — or a blank form. The builder has three columns: the field list on the left, the form in the middle, the settings of the selected field on the right.
- Add a field by clicking it in the list or dragging it into place. Reorder by dragging the handle, with the arrow buttons, or with the keyboard: a focused field moves with Alt + ↑/↓ and is removed with Delete. A removed field can be put back from the toast for a few seconds.
- Field types: short text, email, phone, website, number (min/max), paragraph (min/max characters), dropdown, radio buttons, checkboxes, date (earliest/latest), time, file upload, consent checkbox, hidden value, heading, text/HTML block and page break.
- Every field has a label, a help line, a placeholder, a default, a required switch, full or half width, and a merge tag key ({field:your_name}) for emails — generated from the label, editable.
- Hidden values carry a fixed value or a merge tag ({page_url}), or take a query parameter from the page address — ?utm_campaign=spring fills a hidden field set to utm_campaign.
- The draft saves itself as you work; the header says Draft saved, Saving… or Unsaved changes. Nothing reaches the site until you press Publish.
Conditional logic
Any field can be shown, hidden or required depending on other answers: pick the field, the comparison (is, is not, contains, does not contain, is empty, is filled in, greater than, less than) and the value — up to ten rules per field, all of them or any of them. For dropdowns, radios and checkboxes the value is picked from the options.
The rules run in the browser as the visitor types and on the server when the form is sent: a field the logic hides is never validated and never stored, and a field the logic requires is required even if someone edits the page. Chains work (B shows when A is “yes”, C shows when B is filled in) because a hidden field counts as empty for every rule that looks at it.
Multi-step forms
A page break starts a new step. Visitors see one step at a time with a progress indicator — numbered steps (named after the first heading on each step), a bar, or none — and Next checks the current step before moving on. Without JavaScript every step shows on one page and the server checks everything at once. A step whose fields are all hidden by logic is skipped.
Spam protection
Every form has three checks on by default, none of which the visitor sees: a honeypot field (a bot that fills it gets a quiet “thanks” and nothing is stored or sent), a signed time-to-submit check (a form sent faster than the minimum — 3 seconds by default — is refused; the token is signed with the site’s own keys, so it cannot be forged), and a rate limit per visitor and form (5 per 10 minutes by default). A form that asks for it can also show Cloudflare Turnstile, hCaptcha or Google reCAPTCHA: add the provider and its keys once on the site’s Forms tab (Spam protection → Change; the secret is stored encrypted and sent to that site only), then switch the captcha on per form under Settings → Spam. If the provider cannot be reached the other checks carry the form rather than refusing every visitor.
File uploads
A file field has an allowlist of types (images, PDF, Office and OpenDocument files, text, CSV, ZIP, MP3, MP4, MOV — PHP, HTML, SVG and scripts are never accepted), a size limit (up to 25 MB, within the host’s own limit) and a file count. Every upload is checked by the type read from its contents, not just its name, then stored under a random name in wp-content/uploads/wpclienthub-forms/, a folder denied to the web the same way the backup vault is. Files stay on the site: the inbox shows their names and sizes and fetches a one-time download link (valid 10 minutes) when you ask for one. Files travel with the notification email as attachments up to 10 MB in total.
Notifications and confirmations
- Notifications (up to five per form) go to the addresses you set — {admin_email} is the site’s admin address, {field:email} the visitor’s — with a subject and message that take merge tags: any field, {all_fields} (a table of every answer), {form_title}, {site_name}, {site_url}, {page_url}, {date}, {time}, {entry_id}. Reply-To is the visitor’s email address unless you set one. They are sent by the site with wp_mail(), so whatever mail setup the site has applies.
- Autoresponder: a confirmation to the visitor’s email field, with the same merge tags.
- Alert my team in WPClientHub (per form, off by default) sends one email per entry — with the answers — to everyone on your team who has the Form entries alert on, and to your Slack, webhook and extra-address notification routes.
- Confirmation: a message shown in place of the form (merge tags allowed), or a redirect to a thank-you page.
Publishing and embedding
Publish sends the form to the site as a signed instruction; the site confirms it and the form shows Live. Edits after that are Live · unpublished changes until you publish again — the site keeps serving the last published version meanwhile. Unpublish keeps the form on the site as a draft (pages that embed it show nothing in its place); Delete trashes it on the site and keeps its entries in the inbox.
On the site, add the form to any page with the shortcode shown on the Forms tab — [wpclienthub_form id="12"] — or with the Form block in the block editor, which lists the published forms. The form is a post of the hidden type wpch_form; administrators of the site see the forms and can download each one’s entries as CSV under Settings → WPClientHub.
On the page
The markup is plain, accessible HTML: a label for every control, choices in a fieldset with a legend, help text and errors tied to the control with aria-describedby, required fields marked for assistive technology, and an error summary at the top that takes focus and links to each field. The stylesheet is small and inherits the theme’s fonts and colours (buttons carry wp-element-button, so block themes style them like their own; a handful of custom properties tune the rest). The script has no dependencies — no jQuery — and the form works without it: it then posts to the page and the server answers with the same validation.
Entries and privacy
Each entry is stored on the site (in wp_wpch_form_entries) with the answers and the labels at the time, the page it was sent from and its UTM parameters, the browser, and the IP address only if the form asks for it (off by default). The site nudges WPClientHub, which pulls new entries in signed, chunked pages and keeps the cursor, so a pull that stops halfway carries on where it was and nothing is ever counted twice. A form can be set to don’t store entries: the emails still go out (files as attachments), nothing is kept on the site or in WPClientHub. Deleting an entry in the inbox deletes it on the site too, files included.
Other form plugins
If a site runs Gravity Forms, WPForms, Fluent Forms, Contact Form 7 or Ninja Forms, the Forms tab lists them with their forms and entry counts, and their entries are read into the inbox — never changed, never deleted from WPClientHub. Two honest notes: WPForms Lite keeps no entries on the site (only the paid edition does), and Contact Form 7 stores nothing on its own — install its companion plugin Flamingo and its messages are read. In both cases the tab says “Installed, entries unavailable” with the reason rather than guessing.
Plans, downgrades and uninstalling
- Below Agency the builder is read-only and the inbox stops collecting new entries. Published forms keep working on the sites and keep storing entries there — a plan change never breaks a live page. Back on Agency, the sync resumes from where it stopped.
- Deleting the plugin keeps the forms, entries and uploaded files on the site (they are the client’s leads); add define( 'WPCH_FORMS_DELETE_DATA', true ); to wp-config.php first to remove them.
On the public API
GET /api/v1/sites/{site}/forms lists a site’s forms (ours and the other plugins’) and GET /api/v1/sites/{site}/forms/{form}/entries their entries with the answers, under the new forms:read scope. The webhook event form.entry_received fires for every new entry (spam excluded). See the API docs.
Troubleshooting
- The form shows “Plugin update needed”
- The site runs a WPClientHub One plugin older than 2.0. Update it from the site’s page; the form is sent as soon as the site reports the new version.
- The form stays “Sending to site…”
- The site could not be reached when you published. The next status sync sends it again; Send again on the Forms tab tries right away and shows the site’s answer.
- Visitors see nothing where the form should be
- The form is unpublished or deleted — a visitor sees nothing, someone who can edit the page sees a note. Publish it again. Also check the shortcode id matches the one on the Forms tab.
- “That was quick!” on a legitimate send
- The minimum seconds to fill in (Settings → Spam) is higher than the form takes. Lower it, or set it to 0 for a one-field sign-up.
- Entries arrive on the site but not in the inbox
- Check the plan (Agency and above), that the site is connected, and press Check now on the Forms tab — it asks the site what it holds and pulls the difference. The tab shows the last error the site answered with.