WP Manifestindependent plugin directory
manifest / forms / gravityforms-response-management

Gravity Forms Response Management

Utility functions to manage and aggregate form entries for groups of respondents and forms.

by RAV · github.com/hughc/gravityforms-response-management

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/hughc/gravityforms-response-management/archive/refs/heads/master.zip

Aggregate, browse and export Gravity Forms entries as a single workshop/survey dataset.

Gravity Forms is oriented towards anonymous collection — contact forms, questionnaires — and exports one form at a time. On a workshop or survey site the model is different: a user moves through a sequence of screens, answers several forms along the way, and those answers together constitute one response. This plugin treats a set of forms as one dataset and a set of respondents as one cohort.

Each output row is one known respondent's answers across all forms in a group; each column is a field from one of those forms. Respondents are identified by WordPress user ID — anonymous submissions are not handled.

Requirements

Component Requirement
WordPress 6+ (uses parse_blocks())
Gravity Forms Required — all entry access goes through GFAPI, tested against 3.0
Groups plugin Optional — enables Groups-backed respondent cohorts

No custom database tables. All configuration lives in two WordPress options.

Installation

Drop the folder into wp-content/plugins/ and activate. Nothing to configure on activation.

Usage

The UI is a single tabbed screen at Forms → Response Management. Every tab, AJAX endpoint and export requires the manage_options capability — this is an admin-only tool.

Setup

Define the two axes of a dataset:

Form groups — the forms that make up one dataset.

  • Manual selection: pick forms from a list.
  • Pattern: point at a parent page and the plugin discovers every gravityforms/form block in its child pages. Blocks are parsed recursively, so forms nested inside wrapper blocks (page builders, the Show Response wrapper) are found, and [gravityforms id=N] shortcodes are picked up as a fallback. Child pages are read in menu_order, which fixes the linear screen sequence and therefore the order of columns in the export.

Respondent groups — the cohort of users.

  • Manual selection: pick users; the ID list is stored as saved.
  • Groups plugin: pick a Groups group; membership is resolved fresh on every read, so later joins and leaves are picked up automatically.

Browse Responses

Pick a form group and a respondent group, then navigate respondent by respondent with < prev | (x/y) | next >.

  • Simple mode — choose one form; each step shows that user's complete submission to it.
  • Advanced mode — tick individual fields from any form in the group; each step shows just those fields, so you can compare one question across a cohort or skim a shortlist of answers across several forms.

Export Responses

Choose a form group, a respondent scope, and download a CSV.

Scope Rows exported
A respondent group Members of that group
All users Every logged-in user who has submitted to the selected form group

"All users" is a built-in scope, not a group you create — no Setup entry needed, and it works even with zero respondent groups defined. It resolves respondents from the entry table itself (DISTINCT created_by, scoped to the group's forms), so it means everyone who actually responded, not every WordPress user, and it picks up participants who were never assigned to a group. Anonymous submissions are excluded.

Entry status is not filtered — entries in any state, including trashed, are read.

Utilities

  • Clear user responses — delete every entry created by a user, across all forms or a selected subset.
  • Clear form responses — delete all entries for one form, in batches of 100.

Both delete permanently; there is no undo.

CSV layout

Row Contents
1 Form title, repeated across that form's columns (User over the first column)
2 Field label — the column header (user_login value sits under the first column)
3 … One row per respondent

Per respondent and per form, the most recent entry wins — the same rule as browse and aggregation, so repeated submissions don't duplicate rows. Checkbox and multi-select values are comma-joined, and field values are rendered through Gravity Forms' export logic, so Likert scales and custom field types resolve to readable text rather than stored IDs. A UTF-8 BOM is written for Excel.

Downloads are named responses-<form-group>-<respondent-scope>-<YYYY-MM-DD>.csv, e.g. responses-vacypa-all-users-2026-08-28.csv.

Data storage

Option Holds
gfrm_form_groups Form groups: name, type, resolved form_ids, parent page ID
gfrm_respondent_groups Respondent groups: name, type, user_ids, Groups group ID

Serialized arrays keyed by fg_<uniqid> / rg_<uniqid>. The all respondent scope is not stored here — it is a pseudo group, resolved at export time.

Architecture

Flat, static-only classes, no inheritance:

gravityforms-response-management.php   Bootstrap, admin menu, export handler, 4 AJAX endpoints
includes/class-form-groups.php         Form group CRUD + pattern discovery
includes/class-respondent-groups.php   Respondent group CRUD + Groups sync
includes/class-response-aggregator.php Aggregation, browse, CSV generation
includes/class-utils.php               Clear user / form responses
admin/class-admin-page.php             4-tab admin screen
admin/js/admin.js                      Toggles, field loading, browse navigation

Full design notes, decisions and known trade-offs: docs/implementation.md. Original requirements: docs/spec.md.

Notes and limitations

  • Destructive utilities delete entries outright, rather than blanking their field values.
  • Browse loads every respondent's entries for the selected scope, so very large cohorts are worth exporting instead of browsing.
  • A saved form group's form list is a snapshot of the pattern at save time; re-save to pick up forms added to the page tree afterwards.
  • Only respondents with a live WordPress user account appear in an export — entries belonging to a deleted account are skipped, though they stay in the database.