Download the PHP package goldnead/statamic-lead-magnets without Composer

On this page you can find all versions of the php package goldnead/statamic-lead-magnets. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package statamic-lead-magnets

Lead Magnets for Statamic 6

Gated resources with confirm-first delivery. A visitor asks for a file, confirms the address, and gets a signed download link that expires, can be capped, can be revoked, and leaves an audit row every time it is used.

Statamic 6 only. Laravel 12.40+ / 13.


What it does

What it does not do

Account-based access instead of a download (that needs identity decisions this package does not make), follow-up sequences (they belong in goldnead/statamic-marketing), segments, and analytics conversion events.


Requirements

PHP 8.2+
Laravel 12.40+ or 13
Statamic 6.0+
Hard dependencies goldnead/statamic-brand-context, goldnead/statamic-entitlements

Everything else is optional. The addon is fully functional with no optional sibling installed: it sends its own confirmation mail and serves its own downloads. The test suite runs with none of them present, which is what makes that a claim rather than a hope.

Entitlements is the exception and it is a hard requirement, not a bridge. Access state is not something this addon can half-have — an install where it was absent would have no way to answer "may this person download this file".

Optional addon What it adds
goldnead/statamic-leadhub Creates the contact and writes the resource's tags onto it
goldnead/statamic-marketing Subscribes the confirmed address to a named mailing list
goldnead/statamic-email-templates Lets an editor author the two mails in the CP
goldnead/statamic-suppression Blocks delivery to bounced or complaining addresses
goldnead/statamic-activity Records all four events on the shared ledger

Installation

Optionally publish the config and the public views:

Grant the view lead magnets permission to the roles that need the CP screen.


Usage

1. Create a resource

Tools → Lead Magnets → Create resource. Give it a title, pick File or Link, and set the handle — the handle is what your form names, and it must be unique across every brand (see Multi-brand below).

File gives you Statamic's asset browser, over a container of this addon's own that is created the first time you open the form. Upload there, or pick a file already in it. The container is not one of the site's existing ones and that is deliberate — see Where the files live below.

Link forwards the visitor to a URL you hold elsewhere. Both go through the same signed route, so both are counted, capped and audited identically; the listing names which of the two applies and what it points at.

2. Point a form at it

POST with an Accept: application/json header answers {"ok": true, "data": {"state": "pending"}} instead of redirecting.

3. What happens next

With double opt-in on: a confirmation mail goes out, the grant is pending, and the download link follows only once the address is confirmed. With it off: the delivery mail goes out immediately.

From your own code

Listening to events


Routes

Method URL Name
POST /!/lead-magnets/request lead-magnets.request
GET /!/lead-magnets/confirm/{token} lead-magnets.confirm
GET /!/lead-magnets/download/{grant} lead-magnets.download (signed)

The prefix is configurable under lead-magnets.routes.prefix.


Grant state lives in goldnead/statamic-entitlements

Version 1.x carried its own four-state lifecycle — pending, active, revoked, expired — because the platform's entitlements package did not exist yet. It does now, and 2.0 gives the state back.

The six states, and which of them this addon writes

Entitlements has six. This addon writes three and reads all six.

State Written by lead-magnets What it means here
pending yes a request is parked, waiting for the double opt-in
active yes the address is proven and the file may be fetched
revoked yes an editor withdrew access, with a recorded reason
expired no derived from expires_at by the resolver, never stored
scheduled no a start date in the future; grants nothing yet
grace_period no past the expiry, still allowed

expired is not written by anybody, and that is a fix rather than an omission. In 1.x it was a column somebody had to set — a request, a download attempt, the hourly sweep — so a grant could sit past its date still saying active until something noticed. The resolver reads the clock, so there is nothing to sweep and nothing that can be stale. The sweep command survives with a much smaller job: clearing confirmation tokens whose window has closed.

scheduled and grace_period have no writer here either, because nothing in a lead-magnet flow produces them. They are read all the same, because an operator can produce both from the entitlements Control Panel, and a download gate that did not understand them would be wrong in both directions — serving a grant that has not started, refusing one inside its grace period. Both are covered by tests.

What crossed over and what did not

Only the access state. Signed links, the download cap, the audit rows, the confirmation secret and both mails stayed here. Entitlements sends nothing at all, by design: it decides access and announces it, and the delivery mail hangs off EntitlementGranted in src/Listeners/DeliverConfirmedResource.php.

How a grant appears in entitlements

Column Value
subject_type lead-magnet-contact (configurable)
subject_id SHA-256 of the normalised address
product_slug the resource handle
source lead_magnet (configurable)
source_ref the access period number, starting at 1

The address is hashed rather than stored. subject_id is 64 characters and an email may be 254, so storing it raw would truncate — and two addresses sharing a long prefix would then collide on an index that decides access. The readable list is this addon's own screen, which has the address; the entitlements listing shows an opaque key for these rows.

source_ref counts access periods rather than being empty. A reader whose year of access ran out and who asks again gets a second entitlement, not a rewrite of the first: the expired row is a true record of a period that happened, and entitlements answers over all of a subject's grants as an OR, so a second row is exactly the shape it expects.

Upgrading from 1.x

Two steps, in this order, because the second migration refuses to destroy state that has not been carried across yet:

The command is idempotent, brand-aware and mails nobody: historical rows are written straight to their final state, so EntitlementGranted carries no previous state and the delivery listener stays quiet. A fresh install never sees any of this — there are no rows, and both migrations run inside one migrate.

Entitlements' own entitlements:announce fires EntitlementExpired for grants whose window has closed. Scheduling it is the host application's job: it is shared by every consumer of the package, not owned by this addon.


Security model

The download route carries signed middleware. The signature covers the whole URL including its expiry, so an expired link, a link whose grant id was edited and a link with an added parameter are all rejected with 403 before the controller runs.

The signature proves the link was issued. Whether the access still stands is a separate question the controller asks: a revoked grant holds links that verify perfectly and must not serve. Both are tested.

Confirmation tokens are minted with random_bytes(32), stored only as a SHA-256 hash, and cleared the moment they are used. A leaked database row is not a working confirmation link.

Where the files live

An uploaded resource goes into the addon's own asset container, lead_magnets, on the addon's own disk, lead-magnets. That disk is defined by the addon — storage/app/lead-magnets, with no url, no serve and no public visibility — so it sits outside the document root and Laravel registers no route against it. The signed download route is the only way to the file.

This is the reason the addon does not simply use a container that is already there. Statamic's default asset container is on public/assets: a URL, public visibility, and files the web server hands over before Laravel sees the request. A resource put there is a public download whatever the grant says, and the assets fieldtype would have picked exactly that container by default.

If you point assets.disk at a disk of your own that turns out to be web-accessible — a url, public visibility, or a root inside public/ — the resource form says so in red rather than letting it pass. AssetContainer::private() does not catch all three cases, so the addon asks the wider question itself.

Both halves of that claim are tested: the file is refused over every public address it could plausibly have, and delivered over the signed route in the same test.


Multi-brand

Under goldnead/statamic-brand-context multi-brand mode, resources, grants and download rows are brand-scoped. The three public routes carry no session, so the brand is derived from the value the visitor already holds — the resource handle, the confirmation token, the grant id. Each of those addresses exactly one record across all brands, which is what makes that derivation safe.

That is also why resource handles are unique globally, not per brand. Two brands cannot both own a resource called warm_up.


Configuration

See config/lead-magnets.php. The settings worth knowing:

Key Default Meaning
delivery.link_ttl 10080 (7 days) Signed-link lifetime in minutes
delivery.max_downloads null Redemptions per grant; null = uncapped
delivery.grant_ttl_days null Access lifetime; null = forever
requests.confirmation_ttl_hours 72 How long a confirmation link lives
requests.honeypot website Field name a bot fills and a human never does
requests.throttle 10,1 Requests per minute per client
entitlements.source lead_magnet Marks an entitlement as this addon's
entitlements.subject_type lead-magnet-contact Morph type of a lead-magnet contact
assets.container lead_magnets The asset container uploads go into
assets.disk lead-magnets Its disk. Defined by the addon unless the host already defines one under that name — and it must not be web-accessible
integrations.* true Turn an installed sibling's bridge off

Most of these can be overridden per resource in the Control Panel. The two entitlements keys cannot, and are install-time settings: both are part of the entitlements unique key, so changing either after grants exist orphans every row written under the old value.

delivery.grant_ttl_days and requests.confirmation_ttl_hours look alike and are not. The first is how long access lasts once the address is proven; the second is how long the visitor has to prove it. They are stored in two different columns on two different rows for exactly that reason.


Testing

The MySQL leg is not optional in CI. SQLite has no InnoDB key limit and no utf8mb4 byte arithmetic, and this addon carries a three-column unique that ends in an email address.


Licence

Commercial license. See LICENSE.


All versions of statamic-lead-magnets with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
goldnead/statamic-brand-context Version ^1.13
goldnead/statamic-entitlements Version ^1.0
laravel/framework Version ^12.40|^13.0
pixelfear/composer-dist-plugin Version ^0.1
statamic/cms Version ^6.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package goldnead/statamic-lead-magnets contains the following files

Loading the files please wait ...