Skip to main content

benecaster_feed_enclosure_url

Filter Free

Filters the audio or video URL placed in the RSS enclosure tag for each episode. Use to route downloads through a custom proxy, or append tracking parameters where you need $show_id. Fires after benecaster_episode_audio_url — prefer that hook for URL substitution; use this one for proxy-routing or parameter-appending.

Benecaster registers two callbacks at priority 10. Analytics\ProxyUrlRewriter swaps in the download proxy (/benecaster-download/{id}/?token={TOKEN}) on non-public tiers when download tracking is on for the episode. Feed\EnclosureUrlPrefixer joins the show’s Enclosure URL prefix (Show Settings → Feeds), dropping the URL’s leading https:// and keeping http://, and passes an already-proxied URL through untouched. Their result does not depend on which runs first: if the prefixer runs first, the rewriter replaces the prefixed URL wholesale with the proxy URL; if the rewriter runs first, the prefixer recognises the result as a proxy URL and leaves it alone. A callback registered at priority > 10 sees the final URL — prefixed, proxied, or both in whichever combination Benecaster produced.

Never wrap a proxy URL in a third-party prefix. Its ?token={TOKEN} is the subscriber’s private-feed credential; wrapping it would put that token in the tracking service’s own logs. Check for home_url( '/benecaster-download/' ) before prefixing, the way Benecaster’s own prefixer does.

The same value is also accessible through benecaster_feed_episode_data as the enclosure_url key — use this dedicated filter when you only need the URL and want to avoid receiving the full episode data array. The returned URL must always be a valid, non-empty URL.

It fires in two places, not one. Per item, where the result goes into enclosure url="..."; and again when building each channel-level <podcast:trailer>, with that trailer episode’s ID. Both of Benecaster’s own callbacks run in both places.

Two practical consequences. A prefix or proxy sees the trailer URL rewritten too, which is usually what you want. And a callback that counts its own invocations fires once per item plus once per trailer, not once per item.

For routing every enclosure through a measurement or CDN prefix service (Podtrac, OP3, Podscribe), use Show Settings → Feeds → Enclosure URL prefix instead of this filter — no code needed for that case.

Parameters

Name Type Default Description
$url string — The enclosure URL
$episode_id int — ID of the episode
$show_id int — ID of the show
$tier_slug string — Tier slug for this feed compilation pass

Returns: string

Examples

Append UTM source parameter to track feed traffic

add_filter( 'benecaster_feed_enclosure_url', function ( string $url, int $episode_id, int $show_id, string $tier_slug ): string {
    if ( str_starts_with( $url, home_url( '/benecaster-download/' ) ) ) {
        return $url;
    }
    return add_query_arg( 'utm_source', 'rss_feed', $url );
}, 10, 4 );

Serve preview audio URL for free tier

add_filter( 'benecaster_feed_enclosure_url', function ( string $url, int $episode_id, int $show_id, string $tier_slug ): string {
    if ( 'free' === $tier_slug ) {
        $preview_url = get_post_meta( $episode_id, '_preview_audio_url', true );
        if ( $preview_url ) {
            return $preview_url;
        }
    }
    return $url;
}, 10, 4 );

Notes

The returned URL is placed directly in enclosure url="...". An invalid or empty return value produces a malformed feed item that podcast apps may reject.

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