Overview
This skill covers all Formidable Forms work through the Formidable MCP adapter. It is self-contained and portable: everything needed to do the work correctly is in this file and the references/ directory. Site-specific access details (credentials, URLs, local paths) intentionally live outside this skill — they belong in a local scripts/frm-mcp.env file, so the skill stays portable across sites.
Not connected yet? Start here
If the site has never been connected from this machine — no scripts/frm-mcp.env, no working MCP tool, or the first call fails on auth — read references/getting-started.md and walk the user through it. It is a four-step setup with the exact commands to run, and scripts/frm-mcp-setup diagnoses each step automatically.
Never ask the user for credentials. Not in chat, not as a command to run, not "just paste it and I'll write the file". The application password goes from WP Admin straight into frm-mcp.env, typed by the user in an editor; you only ever confirm the file exists and run calls that read it. A password pasted into a conversation is in the transcript and must be rotated — so don't create that situation. Full reasoning in references/mcp-protocol.md § "Connecting".
Routing: which reference to read
Read the reference file(s) for the task at hand BEFORE making MCP calls. Do not work from recall — these documents encode hard-won corrections; skipping them repeats solved mistakes.
| Task | Read |
|---|---|
| First-time setup / "how do I connect this?" / auth failures on the first call | references/getting-started.md |
| Create/edit forms, add fields, field types & options, form settings | references/forms-and-fields.md |
| Repeaters (repeatable sections) or nested/embedded forms | references/repeaters.md — always, this is the most error-prone area |
| Entries (submissions), views, field statistics | references/entries-and-views.md |
| Choosing a view type, styling a view, or laying one out — tables, card grids, column counts, view Custom CSS | references/entries-and-views.md § "Styling views", § "Grid views" and § "Table views" — read before writing any view content, see rule 9 |
| Nested views — showing a second form's related entries inside a view (parent/child, shared field) | references/shortcodes.md §7 [display-frm-data] → "Nested Views", plus view filters in references/entries-and-views.md |
| Styles / appearance / themes | references/styles.md |
| Email notifications, confirmations, webhooks | references/actions.md |
| Gated content — restrict private pages/posts/files/PDFs/Views behind a form submission, access tokens/links | references/actions.md (action + tokens) and references/shortcodes.md §5 ([frm_gated_content]) |
| Writing shortcodes — email/confirmation bodies, View content, form HTML, field defaults, conditionals, stats/graphs | references/shortcodes.md |
| Applications (Pro) | references/applications.md |
PDF downloads — [frm-pdf] links in views/pages/emails, entry/View PDFs, email PDF attachments, Dompdf rendering constraints |
references/pdfs.md |
Graphs/charts ([frm-graph]), stats, search — full treatment is in the shortcodes reference |
references/shortcodes.md §8 |
| MCP setup, session protocol, abilities catalog, auth, errors | references/mcp-protocol.md |
| Form template XML import/export | references/templates.md |
| Something behaves wrong / MCP call fails unexpectedly | references/gotchas.md |
Universal rules (apply to every task)
- MCP exclusively. All creates/updates/deletes go through Formidable MCP abilities. Never fall back to the REST API, and never write to the database directly.
- Every field gets a label (accessibility requirement — no label-less fields).
- Use specialized field types —
name,email,phone,url— not generictext, whenever the data has a specialized type. - Option fields have minimums: radio buttons ≥ 2 options, dropdowns ≥ 2, checkboxes ≥ 1. Always provide options at creation.
- If the form has a
submitfield, it must keep the highestfield_orderso it renders last — re-check when appending fields. Notesubmitis not acreate-fieldtype (the enum rejects it): forms created via MCP have no submit field, and their button text comes fromupdate-formoptions.submit_value. Older forms often do have one. form_selectis never empty on divider (repeater) and dynamic (data) fields — seereferences/repeaters.mdandreferences/forms-and-fields.md.- Verify after writing. After creating or changing anything, verify via MCP reads (and browser inspection for rendering) before declaring success.
- Cache: if fields don't appear in the form editor after API changes, it's almost always browser cache — hard refresh first; server caches are cleared automatically by the API (see
references/forms-and-fields.mdfor the manual wp-cli cache clear if needed). - Never inline-style a view, and never hand-roll a CSS grid. Put semantic class names in the view content and the rules in the View Custom CSS setting (
options.listing_page_custom_css, auto-scoped to the view) — neverstyle=attributes repeated per entry, never a<style>block insidecontent. For tabular data create the view astype: "table"(columns are boxes in thecontentarray — headers, responsive collapse, zebra striping and an editable column list come with it) rather than hand-writing<table>markup in a classic view; fall back to classic only for what a table view genuinely cannot express (colspan/rowspan, grouped headers, a<tfoot>totals row). For card/column layouts create the view astype: "grid"and setoptions.grid_column_count; do not builddisplay:gridin a classic view'sbefore_content, and do not try to set the column count from Custom CSS (Views writes it inline, so your rule silently loses). Frame styling — background, border, radius, padding, font size — belongs in a box'sstyleobject, not CSS: box 0 styles every card, a content box styles just that cell (the editor's "Cell Settings"). Both render inline, so Custom CSS cannot override them. Readreferences/entries-and-views.md§ "Styling views", § "Grid views" and § "Table views" before writing view content; this is the single most commonly skipped rule here. - Write markup like a person. View content and form HTML get newlines and indentation — block tags on their own lines, nesting indented. Never emit one unbroken line of HTML. Keep inline runs unbroken though: a newline between inline elements becomes a
<br>. Seereferences/entries-and-views.md§ "Write view content as readable HTML". - Lay form fields out in rows. Short related fields belong side by side via
field_options.classes(frm_first frm6+frm6, thirds withfrm4, etc.) — not stacked one per line. Long text, textareas, and uploads stay full width. Seereferences/forms-and-fields.md§ "Field layout". - Keys in content, numeric IDs in settings. Use field/form/view KEYS in shortcodes and entry payloads (
[preferred-shift],[formidable id=my-form]), and numeric field IDs in stored settings — conditional logic (hide_field),calc,form_select,in_section, lookup fields, vieworder_by/where/date_field_id, and action settings like quizenable. A key in a setting is silently ignored, not rejected. IDs in settings are import-safe (Formidable remaps them), so portability is not a reason to avoid them. Details and the full list inreferences/repeaters.md§ "Keys in CONTENT, Numeric IDs in SETTINGS". Entry payloads accept either form at every level; the one structural rule there is that repeater ROWS must be keyedi0,i1, … (see § "Writing Entry Data for Repeaters").