Form Builder Plugin for SynaptikCMS

Custom form builder: create forms with text, long text, email, phone, number, dropdown, and checkbox fields through a drag-and-drop admin editor. Every form gets its own shortcode. Submissions are always saved on the server and can optionally be emailed as a PDF recap.

The PDF generator is fully self-contained — no third-party library (Dompdf, TCPDF, etc.) is bundled or required. It writes a valid PDF 1.4 document directly using the standard Helvetica base font, which every PDF viewer already has built in.


Features

  • Field types: short text, long text (textarea), email, phone, number, dropdown (with custom options), and checkbox.
  • Per-field settings: label, internal key (used in the PDF and as the form field name), required/optional toggle. Checkbox fields are always optional — an unchecked box already carries meaning.
  • Drag-and-drop field reordering in the editor — grab the handle on the left of a field row and drop it above or below another row. No need to delete and recreate fields to insert one in the middle.
  • One shortcode per form: [form id="your-form-id"], insertable in any article, page, or project, and reusable across as many pages as needed.
  • Every submission is saved on the server, regardless of email settings — browsable and searchable from the admin's Submissions tab, filterable by form.
  • Optional email notification per form — a checkbox on the form editor ("Receive submissions by email") controls whether a notification is sent at all. When enabled, each submission is emailed as a PDF recap to either a per-form recipient address or the site's default contact email.
  • PDF recap — title (form name), submission date, and every field as a "Label: value" block, with automatic word-wrap and pagination for long forms. Re-downloadable at any time from the Submissions tab, even for submissions to forms where email notification is off.
  • Custom success message per form, shown inline once the visitor submits (no page reload — the form is replaced with the message and its fields are cleared).
  • Security: honeypot field, minimum-delay check, same-origin referrer check, CSRF token (2-hour TTL), and per-IP rate limiting (5 submissions/hour) — all independent from the core contact form's own state.

Using it day to day

Creating a form

  1. Form Builder → Forms tab → New form.
  2. Give it a name (shown in the admin list and used as the PDF title and email subject).
  3. Receive submissions by email — checked by default. Uncheck it if you only want submissions archived on the server without any email going out (e.g. a form you check manually from time to time).
  4. Recipient email (only relevant while the checkbox above is on) — leave empty to send to the site's default contact email (Settings → Contact in the core admin), or set a specific address for this form.
  5. Success message — shown to the visitor once they submit. Leave empty to use the default "Thank you, your submission has been received."
  6. Fields — click Add field for each field you need:
    • Label — shown to visitors.
    • Key — internal identifier (lowercase letters, numbers, underscores). Used as the PDF row label fallback and the submitted form field name. Two fields can't share the same key — a duplicate is silently dropped on save.
    • Type — Text, Long text, Email, Phone, Number, Dropdown, or Checkbox.
    • Dropdown options — only shown for the Dropdown type, one option per line.
    • Required — disabled automatically for Checkbox fields.
    • Drag the handle (⠿) on the left of a row to reorder it.
  7. Save form. You'll land back on the Forms list, where the new shortcode is shown — click it to copy.

Publishing the form

Paste [form id="your-form-id"] anywhere in an article, page, or project's content. The form renders automatically at that spot on the public page — CSS and JS are only loaded on pages that actually contain the shortcode.

Reviewing submissions

Form Builder → Submissions tab:

  • Filter by form using the dropdown, or view all forms at once.
  • Each row shows the date, form name, and a short summary (first two text values).
  • Download PDF regenerates and downloads the recap on demand — the PDF itself is never stored on disk, only the raw submitted values are, so this works even for a form with email notification turned off.
  • Delete permanently removes a submission's stored record. This does not affect any email already sent.

Editing or deleting a form

Form Builder → Forms tab → Edit to change name, recipient, fields, or field order at any time — existing submissions already on disk keep their original recorded values regardless of later field changes. Delete removes the form definition itself; past submissions to that form are kept and remain browsable from the Submissions tab (filterable by selecting "All forms" once the form itself no longer appears in the per-form filter).


Deleting the plugin

From Extensions, a plugin can only be deleted while inactive — deactivate it first. Deleting removes /plugins/formbuilder/ entirely, including every form definition, every stored submission, and secrets. This is permanent; there is no undo.


PDF generation without a third-party library

formbuilder-pdf.php writes the PDF byte structure by hand: catalog, page tree, font resources (standard Helvetica, no font file needed), one content stream per page, cross-reference table, and trailer. Scope is deliberately narrow — a title, a submission date, and a list of label/value rows with word-wrap and automatic pagination. This is enough for a form recap; it is not a general-purpose PDF layout engine, and there is no support for images, tables, or custom fonts.


Maintenance notes

  • Field keys should stay stable once a form is live. The key is what a submission's stored values object is keyed by, and what appears as the label fallback in the PDF. Renaming the label is always safe; changing the key only affects future submissions — past ones keep the old key in their stored record.
  • notify_by_email is opt-out, not opt-in, for backward compatibility. A form saved before this setting existed has no such key in its stored JSON; fb_notify_submission() treats a missing key as "send" so no existing form silently stops notifying after an update.
  • Rate limiting and CSRF are independent from the core contact form. 5 submissions per IP per hour, 2-hour CSRF token TTL, stored separately in plugins/formbuilder/private/ — never shared with the core's own contact-form state.
  • Adding a language: copy lang/en.jsonlang/{locale}.json and lang/admin/en.jsonlang/admin/{locale}.json, translate the values. The plugin automatically follows the core's active_language (front) and admin_language (admin) settings — no extra configuration needed.
  • Distribution. This plugin is excluded from the core CMS's public release export (export-release.sh excludes /plugins/ and plugins.json) — it ships and updates independently of core releases.