Formboard for Gravity Forms
Server-rendered charts, KPIs, pivot tables, and dashboards — for Gravity Forms, or for a CSV/Excel/Google Sheet, no forms plugin required.
Formboard turns Gravity Forms entries — or an imported CSV, Excel file, or public Google Sheet — into a proper analytics dashboard: bar/line/pie/combo/stacked charts, PowerBI-style KPI cards, pivot tables, and searchable data tables, all computed server-side in a single SQL query per widget and rendered directly into the page.
The whole app runs in wp-admin, or entirely on the front end via [formboard_dashboard]. Every screen is a normal page load — adding a widget, changing a filter, or importing a file submits a plain form and reloads the page, rather than fetching anything in the background. The one narrow, deliberate exception is the chunked-import progress bar, which polls a small endpoint so a large import updates live — and even that falls back cleanly to a page-reload mechanism with JavaScript off.
No background requests
Every mutation is a full page load by design — nothing to silently fail from a misconfigured cache or security plugin.
Works without Gravity Forms
Import a CSV, Excel file, or public Google Sheet as a dataset and build the exact same widgets against it.
Everything bundled locally
Bootstrap, Chart.js, and fonts all ship with the plugin — no CDN, nothing fetched from a third party on page load.
Requirements
| WordPress | 5.8 or newer |
|---|---|
| PHP | 7.4 or newer |
| Gravity Forms | Optional — only required if you want to report on Gravity Forms entries. Not needed at all if you only use imported datasets (CSV/Excel/Google Sheets). |
| License | An active Formboard license, activated through the bundled Freemius licensing screen on first activation. |
Installation
- If you're reporting on Gravity Forms data, make sure Gravity Forms is active first — skip this if you're only importing CSV/Excel/Google Sheets data.
- Upload the
gf-reportsfolder to/wp-content/plugins/, then activate the plugin from the Plugins screen. - Activate your license on the screen that appears after activation.
- The setup wizard opens automatically on your next page load — pick who's allowed to use it and your default look, and it's ready to use.
- Go to Formboard in the wp-admin menu, create a report, and add your first widget.
Quick start
- In wp-admin, open Formboard and click + New report.
- Click + Add widget, choose a type (Chart, KPI, Pivot table, or Table), and pick a Gravity Forms form — or an imported dataset — from the form picker.
- Choose a dimension (for a chart) and a measure — a single field, a two-field calculation, or an advanced formula — and save.
- Drag the widget's title bar to reorder it, or its corner/edge handles to resize it.
- When it's ready, use Share for a link, Export PDF, or Export Excel — or add
[formboard_report id="…"]to a page to publish it read-only on the front end.
Reports & widgets
A report is a named collection of widgets, laid out on a resizable, reorderable grid. A widget is one chart, KPI, pivot table, or table, always backed by exactly one data source — a Gravity Forms form, or an imported dataset — plus its own dimension/measure, filters, and styling.
Every widget can be dragged to reorder (by its title bar) and resized (by its corner or edge handles), duplicated with every setting intact, and edited from its own slide-over builder panel without leaving the report view.
Data sources
Every widget type works identically against two kinds of source, and you can mix both freely across widgets in the same report:
| Gravity Forms form | Any active form on the site. Aggregation runs directly against Gravity Forms' own entry tables — entries are never loaded into PHP just to be summarized. |
|---|---|
| Imported dataset | A CSV file, an .xlsx file, or a public Google Sheet, imported once through the Imports tab. Shows up in the widget builder's form picker under its own "Imported datasets" group, right alongside your Gravity Forms forms. See Importing. |
Chart
Bar, column, horizontal bar, line, area, pie, doughnut, and radar charts, plus combo charts (mixed bar+line series, each with its own optional secondary axis) and stacked bar/area charts.
- Top N / sort — sort bars/slices/lines by value (either direction) or label, and cap how many render, both computed in the same query as the chart's data.
- Additional series (up to 3) — only for Combo, Stacked bar, and Stacked area chart types; each series is its own field + aggregation.
- Data labels — an optional "show values on chart" toggle, printing each bar/point/slice's value directly on the chart rather than only on hover.
KPI
A single stat tile — one number for the whole form (or dataset), with no dimension. Filters don't apply to KPI widgets by design; a KPI is meant to always read as "the current total," which is what distinguishes it from a filtered chart.
KPI comparison card
A PowerBI/Looker-style card: the number, an optional colored delta chip comparing against the previous period (any length in days) or a fixed target, a configurable "which direction is good" (so a metric like open tickets isn't reflexively colored green when it rises), and an optional 12-point trend sparkline.
KPI style
An icon (18 built-in, self-contained icons — nothing fetched from an icon font or CDN), an accent color, a card background (none, a soft tint, or a solid fill), and left or center alignment.
Pivot table
Multiple row fields, optional column fields, and up to several Value columns (each its own field/calculation/formula and aggregation), with subtotals and a grand total on by default. Subtotal rows stay visible when you collapse their own group; the grand total is always visible.
Opt in to heatmap shading per Value column — a light-to-dark color scale computed once across the whole table, so it stays meaningful even with column groups.
Table
A plain grid of entries, one row per entry, in the spirit of datatables.net or Airtable rather than a spreadsheet pivot. Check which fields become columns, set a row cap, and the result is a global search box, click-to-sort columns, and pagination — all computed client-side against the rows already on the page, no background requests.
Supports up to 5 conditional-formatting rules (color a matching row or cell) and an optional heatmap per numeric column, plus the same Table design theming (Light, Dark, Minimal, Bold header, Striped, or fully custom colors) that Pivot tables also use.
[formboard_report], that raw data is public by default; restrict the shortcode with cap or logged_in if it shouldn't be.Fields & measures
A widget's measure — the value it computes — is one of three things, chosen with a radio button in the "Fields & measure" panel (and, separately, per Value column on a Pivot table):
| Single field | One field plus an aggregation — Sum, Average, Count, Min, or Max. |
|---|---|
| Calculated (two fields) | Simple arithmetic between exactly two fields — + - * /. |
| Advanced formula | Any number of fields, combined with operators and functions — see Advanced formulas below. |
Advanced formulas
An advanced formula references fields by their actual name, wrapped in curly braces — not a Gravity Forms merge tag and not a field id. Type the field's exact label as shown in the "Field names on this form" list right below the formula box:
({Revenue} - {Cost}) / {Cost} * 100
Combine fields with + - * / ^ and parentheses, and use any of these built-in functions:
| Function | What it does |
|---|---|
ROUND(x [, n]) | Rounds x to n decimals (default 0). |
ABS(x) | Absolute value. |
SQRT(x) | Square root. |
CEIL(x) | Rounds up to the nearest whole number. |
FLOOR(x) | Rounds down to the nearest whole number. |
MIN(a, b, …) | Smallest of two or more values. |
MAX(a, b, …) | Largest of two or more values. |
Referencing a linked form's fields
Once a relationship is configured, the linked form's fields show up in the same field list, already prefixed with its name — reference them exactly as shown, no special syntax needed:
ROUND({Customers: Lifetime Value} / {Units Sold}, 2)
{A} / {B} shows blank rather than erroring when {B} is zero), and an unrecognized field name, function, or wrong argument count makes that measure compute to nothing rather than showing a broken query.{5}) still keeps working unchanged.Filters
Up to 5 rules per widget, ANDed together, on Chart, Pivot table, and Table widgets (not KPI): is / is not / contains / greater than / less than / is empty / is not empty. A field with fixed choices (Dropdown, Radio Button, Checkbox) gets a checkbox list instead of free text for "is"/"is not".
Every configured filter also shows up as a live filter bar directly on the widget itself — pre-filled with its current value, with Apply and Reset — so a viewer can adjust it without opening the builder. The override lives entirely in the URL and is bookmarkable/shareable; nothing is written back to the widget's saved configuration.
Relationships
Link a second form (or dataset) to any Chart, KPI, Pivot table, or Table widget, BI-style: pick a linked source, then which field on this widget's own source matches which field on the linked one — or, when no single field is reliable enough alone, up to 3 matching-field pairs ANDed together as a composite key.
Once linked, every field picker in that widget — dimension, measure, filters, pivot rows/columns/values, table columns, formulas — also offers the linked source's fields, prefixed with its name (e.g. Customers: Email).
Appearance & table design
Number formatting — Number, Currency (configurable symbol), or Percent, with a configurable decimal count, applied consistently across the KPI tile, pivot cells, and CSV export.
Table design — a color theme (Light, Dark, Minimal, Bold header, Striped, or a fully custom set of pickers) shared by Table and Pivot table widgets. Table widgets additionally get an optional thousand separator and up to 5 conditional-formatting rules.
Dark mode — a viewer-side toggle in the app header; the choice lives in that browser's own storage, never written to the server, and never affects what anyone else sees.
Creating & managing reports
Click + New report from the reports rail. Each report can be renamed, deleted, shared, exported, and has its own "Report settings" popover — see below.
Report settings
Open a report and click Report settings to change its name, and:
- Force same height in rows — stretches every widget sharing a grid row to match the tallest one there, instead of each keeping its own intrinsic height. Off by default.
- Report header — see below.
Report header since 2.48.0
An optional title and subtitle banner shown above a report's widgets, set from the same "Report settings" popover:
- Title and Subtitle — plain text fields; leave the title blank and no header shows at all.
- Custom background color / Custom text color — two independent, off-by-default overrides. Left off, the header uses your theme's usual panel and ink colors automatically.
Shown identically in wp-admin and on the read-only [formboard_report] front-end embed.
Importing CSV / Excel / Google Sheets
- Open the Imports tab and click + Import data.
- Bring in a CSV file, an Excel (.xlsx) file, or a public Google Sheet link — the sheet must be shared as "Anyone with the link can view."
- Map each column to a name and a type (Text, Number, or Date), optionally marking one column as the row's own date (used for KPI trend/comparison and date filters).
- Rows import in the background of a page you can leave open — the progress bar updates itself live as chunks finish. With JavaScript off, it falls back to the same page reloading itself automatically, chunk by chunk.
Once imported, the dataset appears in the widget builder's form picker right alongside your Gravity Forms forms — pick it and build a widget exactly the same way.
Re-import: append & replace since 2.47.0
From Imports, each dataset has its own Re-import link — bring in a fresh CSV/Excel/Sheet and choose:
| Append | Adds the new rows to what's already there. Column mapping is matched automatically to the dataset's existing columns, in order, rather than asked again from scratch. |
|---|---|
| Replace | Swaps in the new rows for the old ones entirely — a safe swap: the dataset (and everything built from it) keeps working on its old data right up until the new file has fully, successfully finished importing, only switching over in one step at the very end. |
There's no scheduled or automatic re-sync from a Google Sheet or anywhere else — Append and Replace are both a deliberate click, the same "every mutation is something you did" design as the rest of the plugin.
Shortcodes
[formboard_dashboard] | The full app — report list, create/edit/duplicate/remove widgets, drag/resize, the widget builder. Identical to wp-admin. Defaults to requiring manage_options. Only place one per page. |
|---|---|
[formboard_report id="12"] | One report, read-only. Add title="0" to hide the report name/header. |
[formboard_widget report_id="12" widget_id="w_ab12cd34"] | A single widget on its own, at its configured width. Find a widget's id in its "Edit" link in wp-admin. |
[formboard_forms] | A directory of every active Gravity Forms form, each linking to a "fill it out" view. Defaults to logged_in="1". |
[formboard_report] / [formboard_widget] are public by default (aggregated numbers only — a Table widget is the one exception, see Table). [formboard_dashboard] and [formboard_forms] are restricted by default, since they can create data.
Restricting access
Any of the four shortcodes accepts:
logged_in="1" | Only visible to a logged-in visitor. |
cap="some_capability" | Only visible to a visitor with that WordPress capability. |
For [formboard_dashboard], what actually saves is governed separately (and more safely) by a filter in a theme's functions.php or a small site plugin:
add_filter( 'gfr_required_capability', function () {
return 'edit_others_posts';
} );
This also changes who sees the wp-admin menu, and is what [formboard_dashboard]'s own cap attribute defaults to, so the two stay in sync automatically.
Settings
Formboard → Settings in wp-admin holds the same options the setup wizard walks through, changeable anytime without redoing the wizard:
| Who's allowed to use it | Admins only, or every registered user (each gets their own reports, and can share individual ones with specific people). Full site admins can always see and manage every report regardless of this setting. |
|---|---|
| Layout & look | Classic or Nova (sidebar) layout, light or dark default theme, accent color, custom header/side navigation background colors since 2.50.0, and the company name/logo used on exported PDF reports. |
| Data & uninstall | See below. |
Data & uninstall since 2.49.0
Deactivating Formboard never touches your data, ever. This setting only controls what happens if you additionally choose Delete from the Plugins screen afterward:
| Off (default) | Deleting the plugin removes only its own lightweight settings (layout, theme, access policy, and similar). Every report, widget, share, and imported dataset is left completely alone. |
|---|---|
| On | An explicit, save-it-yourself opt-in — deleting the plugin also drops its own database tables and its private uploads folder, for a genuinely clean uninstall. |
Security & privacy
- Nothing loaded from a CDN. Bootstrap, Chart.js, chartjs-plugin-datalabels, and the Inter/Roboto Mono fonts are all bundled inside the plugin and served from your own site.
- No background tracking. The only outbound request Formboard ever makes on its own is fetching a Google Sheet's CSV export, and only at the moment you paste that link into the import wizard and confirm.
- Parameterized SQL throughout. Every query that includes a variable value binds it as a query parameter — never string-concatenated into the SQL text.
- Licensing is separate and clearly labeled. Freemius, the service this plugin is sold and activated through, handles license activation and its own optional, explicitly opt-in usage tracking — see Freemius's privacy policy.
Frequently asked questions
Do I need Gravity Forms installed to use this?
No, not since version 2.46.0. Import a CSV, Excel file, or public Google Sheet from the Imports tab and build widgets against that instead. Gravity Forms is only needed if you want to report on entries actually submitted through it.
Does this plugin slow down my site or make background requests?
No. Every screen is a normal, full page load computed server-side — the one narrow exception is the chunked-import progress bar, which polls a small endpoint purely so a large import's progress updates live, and even that falls back to a plain page-reload mechanism with JavaScript off.
What happens to my reports if I uninstall the plugin?
Nothing, by default — see Data & uninstall. Deleting the plugin only removes its own settings unless you've explicitly turned on full data deletion.
Can I use my own field names in formulas, or do I need field ids?
Use actual field names, wrapped in curly braces — see Advanced formulas. A formula saved before version 2.48.0 using a field id still works unchanged; opening it for editing now shows it with real names in place of ids automatically.
Is this plugin translation-ready?
Not yet in this version — every string is currently hardcoded English. This is a known, tracked item for a future release, not an oversight.
Can I restrict who sees a specific report?
Yes — see Restricting access for shortcode-level restriction, and each report's own Manage access / Share controls for per-report sharing with specific people.
Changelog
Recent releases — see readme.txt inside the plugin for the complete version history back to 1.0.0.
2.50.2
- Fixed: on the Nova (sidebar) layout, the "Reports"/"Pages" flyout submenu stayed unreadable against a custom side navigation color — its text and icons now correctly keep the theme's normal colors regardless of the rail's custom color.
2.50.1
- Fixed: a custom side navigation color on the Nova (sidebar) layout left non-active items' icons unreadable — white-on-near-white. Icon chips now track the custom color too.
2.50.0
- New: custom header and side navigation background colors, from Settings → "Layout & look" — see Settings. Off by default; text and icons auto-switch between black and white for readability.
2.49.1
- Attributed the plugin to its maker, Awareness Partners, in the plugin header, license.txt, and readme.txt.
- Added a small "Powered by Awareness Partners" credit at the end of the app's own rail/sidebar.
2.49.0
- Chart.js, chartjs-plugin-datalabels, and Inter/Roboto Mono are now bundled locally instead of loaded from a CDN.
- New "Data & uninstall" setting, off by default, plus a proper
uninstall.php. - Added
license.txt, a trademark disclaimer, and standard readme fields (Tested up to, License URI, FAQ, Upgrade Notice).
2.48.0
- Advanced formulas now use actual field names instead of field ids.
- New optional report header — a title/subtitle banner with custom background/text color.
2.47.0
- Re-import: Append and Replace (safe swap) for any existing dataset.
2.46.0 – 2.46.3
- Datasets — import a CSV, Excel file, or public Google Sheet as a first-class alternative to a Gravity Forms form.
- A dedicated "Imports" tab, and a live-updating import progress bar.