Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Statamic Lead Magnets Laravel Package

goldnead/statamic-lead-magnets

A Statamic addon for creating lead magnets—gated downloads, checklists, and resources that collect visitor details before delivery. Define magnets in the control panel, embed capture forms in your templates, and manage leads without leaving Statamic.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a lead-magnet / gated-delivery package: a visitor submits a form, a LeadMagnetResource decides how the thing is delivered (file, link, or — as of v3.12 — account access), and the package sends the confirmation and delivery mails from a template with placeholders.

Minimal path:

  1. composer require the package, then publish config and migrations and run php artisan migrate. v3.12 adds one migration only — access_product, access_path, delivery_series on lead_magnet_resources, all nullable — so existing resources are untouched.
  2. Look at the config first, not the code. The keys you will actually touch are notifications.webhook_url (new) and entitlements.access_source (new). Everything else is defaults that work.
  3. Create a resource in the admin/filament side (or via seeder) and open its delivery template. That template is the whole product surface for most users — placeholders like {{ access_url }} and whatever DeliveryVariables listeners add.
  4. First use case: ship a plain gated PDF. Delivery method = file, one placeholder in the template, submit the form, confirm the mail arrives. Once that round-trips you understand the flow and can add complexity.

Where to look when something is wrong: the delivery template first (90% of "the mail is wrong" is a template issue), then DeliveryService, then the resource row itself.

Implementation Patterns

Treat the delivery method as a strategy, not a branch. File and link deliveries are self-contained; the new Access method inverts the model — instead of handing over a file, the reader is granted a product on an account. That means your host app owns identity. Bind Contracts\AccessSubjectResolver in a service provider:

$this->app->bind(AccessSubjectResolver::class, function () {
    return new class implements AccessSubjectResolver {
        public function resolve(LeadMagnetResource $resource, array $data): AccessSubject
        {
            $user = User::firstOrCreate(['email' => $data['email']]);
            return new AccessSubject($user, URL::signedRoute('login', ['user' => $user->id]));
        }
    };
}

The resolver must find or create the account and return a sign-in link — the addon creates no users. Then set product slug + landing path on the resource and put {{ access_url }} in the delivery template.

Use DeliveryVariables instead of subclassing DeliveryService. This is the cleanest extension point in the release: register a listener that appends placeholders to both confirmation and delivery mails. Keep listeners pure — return variables, don't send mail, don't mutate the resource.

Wire the mail series when you have the automations addon. delivery_series holds an automation handle whose first mail replaces the delivery mail for a first-time reader. Let the series trigger from entitlements.granted on the product, so access grant and mail sequence are driven by one event rather than two code paths. Design for the fallback: without the addon, with the automation toggled off, or for a returning reader, the normal delivery mail must still be correct on its own. Don't put series-only content in the delivery template.

Route operational visibility through the webhook. notifications.webhook_url posts every request to a Discord-compatible endpoint. Point it at a per-environment channel — a #leads-staging and a #leads-prod — and use it as your smoke test: if the webhook fires, the funnel works end to end.

Gotchas and Tips

  • Access resources deliberately 404 on a signed download link. Do not reuse a download URL pattern for an access product; the reader gets a sign-in link, not a file. If you migrated a resource from file to access, old signed links now 404 by design — check your outbound emails and any cached links.
  • Resolver idempotency. It runs per delivery, so firstOrCreate on email, and make the sign-in link short-lived and route-signed. If you throw from the resolver, the reader gets nothing and the failure surfaces only in logs — wrap in try/catch and fall back to a support message.
  • Series fallback is silent. No automations addon, automation off, or a reader who already had the series all quietly fall back to the delivery mail. That's the right behaviour but it makes "why didn't the series send?" hard to debug — check the automation's run history in the automations addon, not in this package.
  • Toggling a series on for an existing resource will re-mail previous readers unless their run history is recognised. Test with an email that already has history before enabling in prod.
  • Webhook noise and PII. Every request is posted, including tests and bots. Redact or disable the URL in local/staging if the endpoint is shared, and expect rate limits on a busy form.
  • DeliveryVariables fires for both mails. Distinguish confirmation vs delivery in the payload; returning a heavy or slow value (a DB query per placeholder) runs on both. Cache within the request.
  • Nullable migration means no backfill. Existing resources behave exactly as before — but delivery_series and access_* are empty, so nothing infers them. You must opt in per resource.
  • Run config:clear after adding notifications.* / entitlements.access_source. Cached config is the usual reason a new key "does nothing".
  • The addon boundary is real. Access and mail series both lean on other addons (automations, entitlements). Read entitlements.access_source before assuming access grants are attributed correctly in reporting.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels