Skip to main content

benecaster_signed_link_ttl

Filter Free

Filters how long an emailed signed link stays valid, in seconds. Default WEEK_IN_SECONDS — long enough to survive a weekend and a spam folder, short enough that a link sitting in an abandoned mailbox is not a standing credential. An episode magic link (purpose episode_access, from benecaster_get_episode_access_url()) defaults to 30 days instead. The cookie such a link sets runs a fixed 30 days from the click and does not go through this filter.

Shorter is safer, but it is not free. The link lives in a mailbox. Someone who submits the follow form on a Friday evening and reads their mail on Monday must still be able to click it. An expired link costs you the signup, not just the click — do not go below a day without a reason.

A very long TTL has the opposite problem: it turns an emailed link into a standing credential in an abandoned mailbox.

Returning 0 or less makes SignedLink::issue() return an empty string, so no link is minted at all. The mail still sends; it just arrives without a link.

This filter does not run when a caller passes an explicit $ttl to issue().

Parameters

Name Type Default Description
$ttl int — Lifetime in seconds. `WEEK_IN_SECONDS`, or 30 days for `episode_access`, unless already filtered.
$purpose string — One of the `SignedLink::PURPOSE_*` constants.
$user_id int — Recipient of the link.
$show_id int — Show context, `0` when the link is not show-scoped.

Returns: int

Examples

Shorten emailed account links to 48 hours

add_filter( 'benecaster_signed_link_ttl', function ( int $ttl, string $purpose ): int {
    return \Benecaster\Support\SignedLink::PURPOSE_ACCOUNT_ACCESS === $purpose
        ? 2 * DAY_IN_SECONDS
        : $ttl;
}, 10, 2 );

Notes

Expiry is carried inside the signed payload, not as a separate query argument, so a recipient cannot extend a link by editing the URL. Changing this filter affects only links minted after the change — links already in mailboxes keep the lifetime they were issued with.

Rotating the site's salts revokes every outstanding link regardless of TTL, because SignedLink signs with wp_salt( 'auth' ) rather than a stored secret.

Need this built rather than just documented? See our services →