WebBlocks Forms

Requirements

Documented package version: 0.7.0. WebBlocks CMS ^1.57.0; PHP >=8.3.

Build your own forms with the fields you need, and collect the submissions on your own site.

WebBlocks CMS ships a native contact_form block with a fixed field set — name, email, subject, message. It works well and this plugin does not replace it. What it adds is the thing that block cannot do: a form whose fields the site owner decides.

Install

Build the artifact, then upload it through System → Plugins in the CMS as a super admin:

composer plugin:build

Installed plugins are disabled by default. Enable it, then run the plugin setup action from the plugin detail screen to create the tables. Until setup runs, the plugin's screens say Plugin migrations pending rather than failing.

Using it

  1. Forms → Add form. Give it a name and a handle. The handle is what a block stores to point at this form, so changing it later detaches every page that already placed it.
  2. Place it. Add the Form block to a page and choose the form. That is the block's only setting — fields, copy and delivery all live on the form, so the same form can sit on five pages and a copy change happens once.
  3. Submissions. Everything visitors send arrives under Forms → Submissions, filterable by form and status, exportable as CSV per form.
  4. Notification. Each form emails you when a submission arrives. Leave the recipient empty and it falls back to this site's default under Form Settings, then the site's Contact recipient, then the environment — an empty box is a working setting, not a missing one.

Beyond that, per field: give fields the same step number to ask them on one page, or number them 1, 2, 3 to ask a page at a time. Set when to show this field to reveal it only when another answer on the same step matches. Add a file upload field for attachments. And per form: a reply to the sender, outbound webhooks, and a newsletter subscription through WebBlocks Campaigns.

If notification reports Not configured, the install has no real outbound mailer: log, array and null mailers are reported honestly rather than as sent. Submissions are stored either way — storage and delivery are separate concerns, and a misconfigured mailer never costs you the message.

Conditional fields

A field can be shown only when another answer on the same step matches. The browser hides and shows as the visitor types, but that is a convenience: the server decides. A field whose condition was not met is neither validated nor stored.

Both halves matter. Validating one would tell a visitor to fill in a box that is not on the page. Storing one would record an answer nobody gave — a crafted request can carry a value for any input, and the inbox would read as though it was given.

With JavaScript off nothing is hidden, every field is shown, and the same server-side answer still decides what counted. The degraded experience is more questions on screen, never a form that cannot be submitted.

The script is published to /cms/plugins/webblocks-forms/ by the CMS, which is why this release needs ^1.57.0.

Importing an existing Contact Form

Forms → Import Contact Form lists the native Contact Form blocks on the current site's pages. Importing one creates a form here with the same four fields, the same labels a visitor saw, and the block's heading, intro, success message and consent wording in every language it had them — plus its notification recipient.

The block is left exactly as it is and keeps working, and the messages already in Contact Messages stay there. Swapping the block on the page is yours to do when you are ready. Nothing about the import is reversible-by-undo, but nothing about it is destructive either: the worst case is a form you delete.

A few things the import cannot carry across unchanged, and it says so on screen when they apply:

  • A block with no recipient imports with none, so the form keeps inheriting the fallback rather than freezing today's answer into an explicit setting.
  • Notification switched off imports as an action that is present and disabled.
  • Consent wording missing in one language is filled in from the default language. Core only showed its consent box where wording existed, so visitors in that language were not being asked at all — check the wording before you publish.
  • store submissions switched off is reported, not obeyed. The CMS stored every message regardless, so honouring it would be importing a bug.

Retention

Retention is per form and off by default, because silently deleting a site's data is worse than keeping it. When a window is set, the host's scheduler runs:

php artisan webblocks-forms:prune-submissions

Add --dry-run to see what would go without deleting anything.

Two inboxes

An install using both this plugin and the native Contact Form has two places to read messages: /webadmin/contact-messages for the native block, and Forms → Submissions here. That is a deliberate cost. The alternative is a plugin writing into a core table it does not own, which the plugin boundary forbids — and which would not fit anyway, since contact_messages has columns for a fixed four-field message and nowhere to put a schema snapshot, a file, or a per-action delivery status.

Uploads

Submission attachments do not go to the CMS media library. The library stores everything on the public disk with no way to ask for anything else, and its usage check cannot see a plugin's reference — so a file attached to a submission reports as unused and an editor deletes it from the Media screen without a warning. Both are correct for site assets and wrong for a visitor's document, so uploads use the plugin's own private disk, configured in config/webblocks-forms.php. Attachments download through a short-lived signed link, always as an attachment and never inline — an SVG or HTML upload rendered inline would run its script on the admin's own origin.