Repository navigation
[6.x] Forms 2: Unique Instances - #15255
Open
duncanmcclean wants to merge 216 commits into
Open
duncanmcclean wants to merge 216 commits into
duncanmcclean wants to merge 216 commits into
Conversation
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.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A connector is the integration (Email, Webhook, Log…) and a connection is one configured instance of a connector on a form. The base class, repository, facade, addon/extension registration, CP controller props and route params, Vue components and public JS exports now use that vocabulary, and "row" naming in the base-class hooks and the list components is replaced with "connection". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # tests/Forms/EmailTest.php
Connector gains a public blueprint() method. When it returns a blueprint, the base class pre-processes and processes each connection through its fields and merges the top-level fields' validation rules into rules(). connectionFields(), connectionMeta() and blueprintProps() let connectors adjust values and meta per connection and build the blueprint, meta and defaults props for their Vue component. Email and Webhook use the new hooks instead of hand-building them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fields ConnectionList now accepts the connector's blueprint and meta. Without a default slot it renders the logic builder and the connection's fields, so connector components only need a header. The new ConnectionFields component renders one connection's fields and is exported for custom layouts. ConnectionList also keeps a copy of each connection's meta, so new and duplicated connections no longer share and mutate the default meta, and validation errors keep their full path so nested fields like grids show them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Laravel only compiles rules like Rule::forEach() per item when they're a key's entire value. Wrapping them in an array made them validate against the whole data set, so they silently stopped failing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Connectors now hold their form and connections, set with setForm() and setConnections() (or forForm() for a form's stored connections), so render(), blueprint(), count(), rules() and the per-connection hooks no longer take the form as an argument. render() and count() use the connections they were given instead of reading the form's stored ones, so callers like entry-level overrides can pass their own. setConfig() and config() are replaced by setConnections() and connections(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l pipeline Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jasonvarga
added a commit
that referenced
this pull request
Oct 12, 2026
Internal submission keys are now prefixed with an underscore (_partial, _site, _spam), and form field handles can't start with one, so the entry, partial, site and spam handles no longer need reserving. entry was reserved ahead of #15255, which should store _entry instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports this branch's connection code to the connector rename: ConnectionsListing is now ConnectorsListing, the form_connections fieldtype uses FormConnector, and Submission::connectionJobs() resolves connections through the entry's form instance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Connections (#15063) was squash-merged into forms-2, so this branch's copy of its history conflicted everywhere. The merge result is forms-2 plus this branch's own changes since the final Connections head. forms-2's honeypot behavior and config section positioning now live in ConfigFields, and instance submission limits count finalized submissions only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
forms-2 now prefixes internal submission keys with an underscore (_partial, _site, _marked_spam_at), so entry follows suit and is no longer a reserved form field handle. The entry key is still exposed in toArray(), augmentation and emails, but only when the form doesn't have its own field named entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Queries filter on the _entry data key, so the entry index was never used and only ever held nulls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Presets were disabled unconditionally to protect the stack's auto-applied submission_entry filter. Only disable them when viewing in a stack. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Restrictions were computed from the raw context id while _entry was only rendered when the entry referenced the form. Resolve the submittable entry once and use it for both. With no submittable entry, form-level restrictions apply. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
It re-read and decoded composer.lock on every call, including per-row paths. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ittable entry Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…pdate The connections fieldtype now posts to a dedicated endpoint that validates and processes a connector's config without saving. The connector update endpoint always saves again. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Users who can edit an entry but not the form get no Configure stack, no stored config sent to the client, and keep the entry's stored config on save, at any nesting depth. The stored config lookup is shared with Instance. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tances Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
rsvpform.Like multi-page forms, everything lives in core but is only available when the
statamic/forms-proaddon is installed.Enabling unique instances
Toggle on "Unique Instances" in the form's configure screen, then attach the form to entries using the
formfieldtype.The frontend
When
{{ form:create }}is rendered in an entry's context, it outputs a hidden_entryinput, 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:
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.
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
formandconfigkeys.Restriction logic lives on a new
Instanceclass, since "is this form open?" becomes a per-entry question when unique instances is enabled:Depends on: