Appearance
Form Submissions
The built-in Contact form and Newsletter sections store every submission and list it in an Inbox in your panel. Nothing to wire up: drop the section on a page, publish, and messages start arriving.
Upgrading from 1.40 or earlier
The inbox needs the filamentcraft_submissions table. Run php artisan filamentcraft:upgrade to publish and run the new migration. Until you do, submissions are reported and dropped, and filamentcraft:doctor fails the Form submissions check.
What happens on submit
- The section checks the honeypot and the per-visitor rate limit.
- It validates the fields and fires
ContactFormSubmittedorNewsletterSubscribed. - The package's listener writes a row to
filamentcraft_submissions(whenforms.storeis on) and mails the addresses informs.notify(when set). - The visitor sees the section's success message.
Storage and mail failures are reported through report() and never reach the visitor: the success state does not depend on your mail server being up.
Each row keeps the site, the published page the section sits on (when it sits on one), the section id, the type (contact or newsletter), the submitted fields, the visitor's IP address and browser, and when it was read.
The inbox
Inbox sits in the FilamentCraft navigation group, with a badge counting unread submissions.
- Filter by type, by read state, and by site when you run more than one.
- Open a submission to read it in full. Opening it marks it read.
- Mark rows read or unread, or delete them, one at a time or in bulk.
The inbox follows the same tenancy rules as the rest of the panel: an operator only ever sees submissions of the sites they can access, and a URL pointing at another tenant's submission 404s. Deleting a site deletes its submissions.
To hide the inbox, or rename it:
php
FilamentCraftPlugin::make()
->withSubmissionsInbox(false) // or config('filamentcraft.forms.inbox')
->submissionsNavigationLabel('Messages');Mail notifications
Set forms.notify to get a plain email per submission. It takes one address, a comma-separated list, or an array:
dotenv
FILAMENTCRAFT_FORMS_NOTIFY="owner@example.com,sales@example.com"The mail is a queued notification sent on demand, so it goes through your queue when one is configured and sends inline otherwise. Contact messages set Reply-To to the visitor, so replying from your mail client answers them directly.
Spam defence
Both forms ship with two cheap defences, on by default:
- Honeypot. A hidden field people never see and bots fill in. A filled one gets the success message and is dropped: no row, no mail, no event.
- Throttle. Each visitor (by IP address) may send
forms.throttlesubmissions per minute per form type. The next one shows a "try again in N seconds" error on the form.
php
'forms' => [
'throttle' => 5, // null or 0 turns the limit off
'honeypot' => true,
],Using your own destination
The events always fire, so a listener of your own works alongside the inbox:
php
use FilamentCraft\Events\ContactFormSubmitted;
use Illuminate\Support\Facades\Event;
Event::listen(ContactFormSubmitted::class, function (ContactFormSubmitted $event): void {
Crm::createLead($event->name, $event->email, $event->message);
});When your listener is the only destination you want, turn storage off:
php
'forms' => [
'store' => false, // FILAMENTCRAFT_FORMS_STORE=false
],With storage off and no listener bound, visitors would be told their message was sent while it goes nowhere. filamentcraft:doctor warns about exactly that: Form submissions are discarded, naming each published page that carries an affected section.
Configuration
| Key | Default | Effect |
|---|---|---|
forms.store | true | Write submissions to filamentcraft_submissions and the inbox. |
forms.notify | null | Address, comma-separated list or array to mail per submission. |
forms.throttle | 5 | Submissions per visitor per minute, per form type. null/0 = off. |
forms.honeypot | true | Render the hidden field and drop submissions that fill it. |
forms.inbox | true | Register the Inbox resource in the panel. |
The Submission model can be swapped like any other through filamentcraft.models.submission (see Models & Keys), and its keys follow filamentcraft.database.key_type.
