Skip to content

[6.x] Forms 2: Unique Instances - #15255

Open
duncanmcclean wants to merge 172 commits into
forms-2from
forms-2-unique-instances
Open

duncanmcclean wants to merge 172 commits into
forms-2from
forms-2-unique-instances

Conversation

@duncanmcclean

@duncanmcclean duncanmcclean commented Aug 24, 2026 •

Copy link
Copy Markdown
Member

This pull request implements "unique instances" for forms: a Forms Pro feature which lets a form be treated as its own instance per entry, with submissions tracked against the entry they were submitted from, rather than in aggregate.

The classic use case is an Events collection where every event has its own RSVP form — each event gets its own submissions, its own capacity and its own close date, all from a single rsvp form.

Like multi-page forms, everything lives in core but is only available when the statamic/forms-pro addon is installed.

Enabling unique instances

Toggle on "Unique Instances" in the form's configure screen, then attach the form to entries using the form fieldtype.

CleanShot 2026-08-24 at 21 43 53

The frontend

When {{ form:create }} is rendered in an entry's context, it outputs a hidden _entry input, and the submission is tracked against that entry.

Per-entry restrictions & overrides

When unique instances is enabled, the form's Access settings are evaluated per entry:

  • Submission limits count only the entry's submissions (eg. "100 spots per event").
  • Each entry can override the Access settings (close date, submission limit & period, closed message, require login & message) via the form fieldtype's "Configure" option. Fields are synced with the form's settings by default — editing a field desyncs it and stores an override, while synced fields keep following the form.

Connections are overridable in the same way, so each entry can have its own notifications. A warning banner is visible when configuring connections on a form with "unique instances" enabled.

CleanShot.2026-08-24.at.21.42.58.mp4

In the Control Panel

The submissions listing shows which entry each submission came from, and can be filtered down to a single entry.

On the entry's publish form, the form fieldtype has a "View Submissions" option which opens the entry's submissions in a stack, with individual submissions opening in a nested stack. The fieldtype's index view links to the pre-filtered submissions listing, and the submission page links back to the entry.

CleanShot 2026-08-24 at 21 12 42

PHP API

The form fieldtype's value is stored as a plain handle until an entry has overrides, at which point it becomes an array with form and config keys.

Restriction logic lives on a new Instance class, since "is this form open?" becomes a per-entry question when unique instances is enabled:

$form->instance($entryId)->status(); // open, closed, limit_reached
$form->instance($entryId)->restricted();
$form->instance($entryId)->restrictionMessage();
$form->instance($entryId)->config('submission_limit'); // entry override, falling back to the form
$form->instance($entryId)->connections(); // entry override, falling back to the form's own connections

// Every form has a "default" instance, which these delegate to:
$form->status();
$form->restricted();
$form->restrictionMessage();

Depends on:

duncanmcclean and others added 30 commits July 21, 2026 12:33
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…need to use antlers

Using Antlers in email address fields is still supported, but this is a slightly easier approach for end-users.
duncanmcclean and others added 29 commits September 1, 2026 15:45
the `connections()` setter now backfills row ids, which this assertion (merged in after that change) didn't account for.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199zXuG4CtZsGqCy5Gm65io
these two tests were deleted on purpose in 29d7e78 when the
`DeleteTemporaryFiles` job moved out of `SendEmails` and into the
job chain built by `Submission::finalize()`. they were only added
back by a bad merge conflict resolution when merging `forms-2` into
`forms-2-connections` (72b9e33).

the behaviour is already covered by `SubmissionTest` and
`DeleteTemporaryFilesTest`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qe1g6yd25kh7oTxtWfzB95
Co-authored-by: Duncan McClean <duncan@duncanmcclean.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts:
#	resources/js/bootstrap/fieldtypes.js
#	src/Providers/ExtensionServiceProvider.php
…tances

# Conflicts:
#	resources/js/bootstrap/fieldtypes.js
#	resources/js/pages/forms/submissions/Show.vue
#	src/Providers/ExtensionServiceProvider.php
…2-unique-instances

# Conflicts:
#	resources/js/bootstrap/fieldtypes.js
#	src/Providers/ExtensionServiceProvider.php
Base automatically changed from forms-2-connections to forms-2 October 8, 2026 22:19

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants