Skip to main content

Recipes

Drop-in code examples for extending the Benecaster plugin.

Tier:

Route all enclosure URLs through Podtrac

Free Beginner

Podtrac is a podcast download measurement prefix service. By routing every enclosure URL through Podtrac’s prefix, you gain cross-platform download attribution without changing your audio host. This recipe…

Redirect feed URLs to pretty permalink format

Free Beginner

By default Benecaster builds token URLs using a query parameter format. Use this recipe to rewrite them to a pretty permalink structure — e.g. /podcast/feed/abc123xyz — that looks…

Post-process a multi-tier assembled feed as a whole

Free Intermediate

benecaster_feed_xml fires at two call sites: once per tier inside FeedCompiler::compile() and once in FeedAssembler::assemble() after all tiers are merged. This recipe demonstrates how to target only the…

Add a custom field to the RSS feed

Free Intermediate

Two hooks work in combination here: benecaster_episode_custom_fields exposes a custom field’s value through the episode data layer, and benecaster_rss_extra_item_tags appends the corresponding XML to each RSS item. Use…

Measure and log feed render time

Free Beginner

Slow feed compilations are hard to notice until listeners start complaining. This multi-hook pattern timestamps the start of each feed render, then computes elapsed time and compiled size…

Add Podlove chapter markers to RSS

Free Beginner

Shows the manual filter approach for adding podcast:chapters to RSS items by appending the tag directly via benecaster_rss_extra_item_tags. With the Chapter Markers add-on the data is managed via…

Show a 60-second preview player to non-subscribers

Free Beginner

Instead of showing a blank locked-content placeholder, give visitors a taste of the episode with a 60-second preview. This recipe hooks into the episode player render to conditionally…

Override locked content message per tier

Free Beginner

The default locked-content message is generic. This recipe customizes the message based on the tier required to access the episode — showing “Upgrade to Premium” for paid-only content…

Grant access based on WooCommerce product purchase

Free Intermediate

Benecaster’s bridge system handles subscription-based access, but sometimes access should be granted based on a one-time product purchase rather than a recurring membership. This recipe uses benecaster_episode_is_accessible to…

Detect and log invalid feed token attempts

Free Beginner

Invalid token attempts — wrong hash, revoked token, or unknown prefix — signal token sharing, credential stuffing, or misconfigured apps. This recipe logs each attempt with the token…

React to subscription events from any bridge

Free Beginner

SubscriptionListener relays bridge events as WordPress actions, making the same code work regardless of whether the site uses MemberPress, WooCommerce Subscriptions, Restrict Content Pro, or a custom bridge.…

Log admin-initiated revocations to an external audit service

Free Beginner

benecaster_subscriber_access_revoked fires only for explicit human-initiated revocations (via the admin dashboard), distinct from benecaster_token_revoked which fires for all revocations including programmatic ones. Use for compliance audit trails, CRM…

Sync changed episode fields to an external system

Free Intermediate

Fires on every episode save that is not the first creation. $changed_fields lists only the post-table columns that actually changed (title, content, post_status, post_date) — it is empty…

Assign episode numbers based on a custom sequence

Free Beginner

Benecaster assigns max + 1 across all published episodes by default. Use this filter to suppress auto-numbering for trailers and bonus episodes, restart numbering per season, or skip…

Sync show creation to external CRM

Free Intermediate

Three show lifecycle hooks cover the full CRUD lifecycle. benecaster_show_created fires once on first save; benecaster_show_updated fires on every subsequent save with a $changed_fields array listing post-level changes;…

Add custom merge tags to all emails

Free Intermediate

Custom merge tags registered via benecaster_email_merge_tags are available in all Benecaster emails. With the Email Editor add-on active, these tags are also available in the drag-and-drop template builder…

Sync email opt-outs to Mailchimp

Free Beginner

When a subscriber opts out of Benecaster emails via the unsubscribe link, propagate the opt-out to your Mailchimp audience so the preference is consistent across systems. benecaster_email_resubscribed fires…

Add SendGrid category tracking to all emails

Free Beginner

Sends Benecaster emails with SendGrid category tags for segmenting analytics by email type in the SendGrid dashboard. This approach requires SMTP delivery — WordPress must be sending email…

Register a custom email type with the Email Editor

Free Intermediate

Any email type registered via benecaster_managed_email_types appears as an editable template in the Email Editor UI. Add-ons that send their own email types — episode notifications, community alerts,…

Auto-populate custom fields from imported RSS data

Free Beginner

When the Migration Wizard or Feed Sync imports episodes, benecaster_feed_sync_import_data lets you reshape the raw RSS item data before it’s written, and benecaster_episode_imported fires after each episode is…

Skip importing trailer episodes during feed sync

Free Beginner

Feed sync imports every episode it finds by default. Return false from benecaster_feed_sync_should_import to skip specific episodes — trailers, bonus content, or episodes from dates before the migration…

Register an add-on CPT with the custom field system

Free Intermediate

Core registers benecaster_episode with the field system automatically. Add-ons that introduce their own CPTs (e.g. Guest Manager’s benecaster_guest) must call benecaster_register_field_cpt() inside a benecaster_boot callback so the CPT…

React to episode custom field changes from an add-on

Free Beginner

Fires after POST /benecaster/v1/field-values/benecaster_episode/{id} when at least one field value actually changed (before/after snapshot diff). $changed_field_ids is an array of benecaster_fields.id values. Use to sync episode content to…

Inject a dynamically generated field group

Free Intermediate

Prepend or append field groups generated at runtime — from external data, plugin state, or computed summaries — without storing them in the database. Synthetic groups (non-integer IDs)…

Transform a stored field value before display

Free Beginner

benecaster_field_value fires on every read — including inside the episode editor UI and REST API responses. Use it to format raw stored values: convert a date string to…

Inject a React component into a named slot (Tier 2)

Free Advanced

For interactive UI that can’t be expressed as a field declaration — custom pickers, live previews, embedded third-party widgets — add-ons register React components directly into named extension…

Add a custom REST endpoint from your add-on

Free Intermediate

Extend Benecaster\REST\RestController in your add-on and register it via benecaster_boot. Your routes live under benecaster/v1/ with the same permission callbacks used by core. Use permission_callback_admin() for admin-only routes…

Inject a synthetic reference group from an add-on

Free Intermediate

Prepend or append reference groups managed outside the database — for example, the Outlinks add-on can inject a “Tracked Links” group without storing it in benecaster_reference_groups. Synthetic groups…

Integrate with a membership plugin not in the core bridge set

Free Advanced

Implement BridgeInterface for a custom membership plugin, register it via benecaster_boot, and activate it for a show with BridgeManager::set_active_bridge(). Covers all nine required methods, the NullBridge fallback pattern,…

Read or override the active bridge for a show from an add-on

Free Intermediate

BridgeManager is available from the container via $container->make(). Use get_active_bridge() to read the configured bridge for a show (returns NullBridge when nothing is configured), and set_active_bridge() to programmatically…

Integrate a community platform not in the core set

Free Advanced

Implement CommunityPlatformInterface in your add-on and register it via benecaster_boot. The Community Integrations add-on routes all subscription events to every registered platform automatically — including Discord and Circle…

Perform a community action on episode publish

Free Intermediate

CommunityPlatformRegistry calls onEpisodePublished() on every registered, configured platform when benecaster_episode_published fires. Implement this method to create a discussion thread, post an announcement, pin a notification, or update a…

Build a custom subscriber dashboard with template functions

Free Intermediate

Build a fully custom subscriber account page using benecaster_get_template_part(), benecaster_get_feed_url(), and benecaster_get_subscriber_count() directly in a theme template. This is an alternative to the built-in Blocks & Widgets account…

Inject a step into the setup wizard from an add-on

Free Intermediate

Add-ons inject additional wizard steps by appending entries to the steps array. Each step entry must include id, component (React component registered on window.BenecasterExtensions), required, and condition (a…

Add a custom bridge card to the wizard Subscription step

Free Intermediate

Add-ons that provide a non-core subscription bridge inject their card into the wizard’s Subscription step. The slug must match the bridge’s get_plugin_slug() return value so POST /bridge/activate can…

Add a Custom Section to the Analytics Digest

Free Intermediate

Add your add-on’s data to any Benecaster Analytics Digest (daily, weekly, or monthly) by injecting a data payload via benecaster_analytics_digest_data and registering a custom section via benecaster_analytics_digest_sections. This…

Trigger a Feed Cache Clear from External Code

Free Beginner

Trigger a Benecaster feed cache clear from any plugin, mu-plugin, or WP-CLI cron job using the benecaster_clear_feed_cache action. Supports global, show-scoped, and tier-scoped clears. benecaster_feed_cache_cleared fires after any…

Customize the Upgrade Prompt for a Specific Show

Free Beginner

Use the benecaster_upgrade_prompt_html filter to change copy or add a link to the upgrade prompt shown to logged-in subscribers at the wrong tier. Scope changes to a single…

Add a Custom Section to the Show Page

Free Beginner

Use benecaster_after_show_episode_list to inject HTML below the episode listing without overriding a template file. Each show page action hook fires with $show_id as its only argument. Swap to…

Inject Podcasting 2.0 Episode Tags from an Add-on

Free Intermediate

Fires before per-episode podcast: namespace tags are rendered to XML. The initial array is pre-populated from episode meta (transcript, soundbites, feed_credits, season, images). Add-ons receive the populated array…

Auto-populate Feed Credits from Guest Manager

Free Intermediate

Inject read-only Podcasting 2.0 credits into an episode’s Feed Credits section without writing to post meta. Benecaster calls benecaster_podcast2_episode_auto_feed_credits after loading meta-stored credits, merges the returned array into…

Customize [benecaster_current_tier] output

Free Beginner

benecaster_current_tier_output fires immediately before the shortcode returns. $tier_slug and $user are null on the fallback path (guest, no token, non-active token). Use the filter to greet the subscriber…

Redirect episode navigation links

Free Intermediate

Use these filters to change which episode “prev” or “next” points to — for example, skipping bonus episodes, enforcing season boundaries in the Episode Page block, or implementing…

Register a custom related-episodes query strategy

Free Advanced

Use benecaster_related_episodes_query_types to add a custom query strategy to the [benecaster_related_episodes] shortcode and the related_episodes Episode Page block. Any add-on can register one or more strategies; they appear…

Override the related-episodes list per-episode

Free Beginner

Filter the resolved episode list before the shortcode or Episode Page block renders it. Return a modified array to inject specific episodes, enforce premium-only results, or suppress the…

Inject or reorder social links programmatically

Free Beginner

Filter the resolved social links array before [benecaster_social_links] or the episode page social block renders them. Each item is ['platform' => string, 'url' => string, 'label' => string].…

Replace the social links HTML entirely

Free Beginner

Filter the final HTML string produced by [benecaster_social_links] or the episode page social block. Use to swap in a custom icon set, wrap the list in additional markup,…

Replace or suppress the RSS link output

Free Beginner

Filter the final output of [benecaster_rss_link]. Use to wrap the link in additional markup, swap in a custom SVG icon, conditionally suppress the link on certain pages, or…

Replace or suppress the platform links output

Free Beginner

Filter the final output of [benecaster_platform_links]. Use to wrap in additional markup, inject custom badge HTML for a specific platform, suppress the block on certain pages, or replace…

Exclude an episode from all search results

Free Beginner

Return false to remove an episode from every search response regardless of tier or query term. Useful when an episode is published but should not be discoverable —…

Augment search result excerpts

Free Beginner

Override the per-result excerpt returned by the search endpoint. Useful to substitute transcript snippets, chapter titles, or custom-formatted highlights. The Transcription Service add-on uses this pattern to surface…

Tell the Add-ons screen that this add-on plugin is loaded

Free Beginner

Benecaster fires benecaster_installed_addons during admin bootstrapping to build the list of loaded add-ons. Each add-on plugin should hook this filter inside its benecaster_boot callback and append its fully-qualified…

Register a fully custom XML namespace handler from an add-on

Free Advanced

Implement FeedNamespaceInterface and append your instance inside a benecaster_feed_namespaces callback. The registry handles xmlns injection, channel-level merging, and per-episode merging automatically — no FeedCompiler changes needed. Required methods:…

Count paying subscribers correctly from benecaster_tokens

Free Intermediate

The tokens table mixes three populations: paying subscribers, free-tier bridge members, and direct followers. Counting paying subscribers accurately requires excluding both non-paying populations simultaneously — one filter targets…

React to a free follower signup

Free Intermediate

[benecaster_follower_signup] creates a WordPress user and inserts a token_type = 'follower' row, then fires benecaster_follower_signed_up( int $user_id, int $show_id, string $tier_slug ) before the welcome email is dispatched.…

Redirect the account page URL to a custom path

Free Beginner

benecaster_account_page_url( int $show_id = 0 ) returns the permalink of the plugin-created /podcast-account/ page. Use this filter when a podcaster places [benecaster_account] on a differently-named page and wants…

Fire add-on side effects when a show is archived or restored

Free Beginner

ShowsController::archive_show() fires benecaster_show_archived( int $show_id ) immediately after the _benecaster_show_archived meta flips to '1'; unarchive_show() fires benecaster_show_unarchived( int $show_id ) symmetrically. The feed returns HTTP 410 for archived…

Invalidate derived caches when the license server publishes new pricing

Free Beginner

LicensePricingFetcher::refresh() fires benecaster_pricing_data_changed( array $pricing, ?string $previous_updated_at, string $new_updated_at ) whenever the freshly-fetched updated_at differs from the cached value. Use this to invalidate any pricing-derived cache (UI snapshots,…

Mutate or block outgoing webhook payloads per event

Free Intermediate

The outbound webhook system POSTs subscription/token events with a sha256= HMAC header. benecaster_webhook_payload runs once per event after the dispatcher assembles the payload, before signing. Add custom keys,…

Run custom logic after the Promote-to-Bridge wizard finishes

Free Intermediate

PromotionService::run() fires benecaster_bridge_promote_complete( int $show_id, string $target_bridge_slug, int $promoted, int $skipped, int $errors ) after the migration loop completes and the active bridge has been switched — regardless…

Show or hide a show's public episode pages from add-on code

Free Intermediate

ShowMeta exposes set_episode_single_pages_disabled( bool ), set_episode_archive_disabled( bool ), and their read counterparts. Use them programmatically to gate a show’s public visibility — useful for time-locked launches, paywall integrations,…

Add a custom icon to the per-tier badge picker

Free Beginner

BadgeIconRegistry::get_icons() runs benecaster_badge_icons to merge add-on icons into the built-in set. Each entry is [ 'slug' => string, 'label' => string, 'svg' => string ]; the SVG must…

React to a badge definition being deleted

Free Beginner

benecaster_badge_definition_deleted fires after a badge definition row is removed. The hook passes the badge ID, its parent tier ID, and the full pre-delete badge data — label, icon,…

Drop a user's badge chips into a custom theme template

Free Beginner

benecaster_render_user_badges( int $user_id = 0, ?int $show_id = null ): string looks up the user’s badges via benecaster_get_user_badges() (so the benecaster_user_badges filter applies) and returns the chip HTML.…

Mirror Supporter Wall opt-in changes to an external CRM or audit log

Free Beginner

SupporterWallManager::set_subscriber_visible() fires benecaster_subscriber_wall_visible( int $user_id, bool $visible ) after every write — including same-value writes (the action fires on every save so add-ons can observe explicit re-confirmation events,…

Replace or wrap the assembled Supporter Wall HTML

Free Intermediate

Fires after the default markup is assembled for both the populated and empty branches of [benecaster_supporter_wall]. $html is the complete rendered output. $subscribers is the raw row array…

Use a non-USD currency for buy-ups in a specific market

Free Beginner

StripeBuyupProvisioner runs apply_filters( 'benecaster_buyup_currency', 'usd', $buyup_id ) when minting Stripe Prices. Return a different ISO-4217 currency code to provision in that currency instead. The same Price is reused…

Invalidate locale-keyed caches when the operator changes supported languages

Free Beginner

LanguageSettingsController::update_settings() fires benecaster_supported_locales_updated( array $supported, string $primary, array $previous_supported, string $previous_primary ) after a successful save. Use to invalidate template-sync notices, refresh locale-keyed transient caches, or run a…

Add a new payment processor alongside Stripe

Free Advanced

Implement PodcastPaymentGateway and register your gateway with PaymentGatewayRegistry during benecaster_boot. is_test_mode(): bool is mandatory — a class missing it raises a PHP fatal at load (the interface declares…

Register an add-on handler on the shared Stripe webhook endpoint

Free Intermediate

StripeWebhookController is a single shared endpoint at POST /benecaster/v1/stripe-webhook that verifies the Stripe-Signature header once and dispatches to per-event handlers. Add-ons register additional handlers via benecaster_stripe_webhook_handlers rather than…

Mirror right-to-erasure/retention purges to external systems

Free Intermediate

benecaster_after_gdpr_purge( string $source, array $result ) fires after every successful purge, whether operator-driven ($source = 'manual') or retention-sweep-driven ($source = 'cron'). $result contains user_id and email (one may…

Register a custom export sheet from an add-on

Free Advanced

The sheets filter fires twice per export request: once when the React UI renders checkboxes and once when the XLSX file is generated (only checked sheets are written).…

Load a custom template part from an add-on

Free Intermediate

Add-ons that render HTML can use benecaster_get_template_part() to load their own template files and automatically allow theme developers to override them. Pass the add-on’s own templates directory path…

Override teaser content with a chapter preview

Free Beginner

Use benecaster_teaser_content to replace the default word-count or description teaser with any custom preview — for example the first chapter heading from the Chapter Markers add-on. The filter…

Check episode access in a shortcode or widget

Free Beginner

Use the public access-check functions to conditionally render premium content in any PHP context. benecaster_user_can_access_episode() returns true for public episodes regardless of subscription status. benecaster_get_user_tier_for_show() returns the tier…

Replace the episode share links with a custom share card

Free Beginner

The default episode/share.php renders X, Facebook, and LinkedIn share links. Replace the whole set or inject additional platforms via benecaster_episode_share_links. Each entry is an associative array with label…

Hide the sort controls on the episode archive

Free Beginner

Return false from benecaster_archive_show_filters to suppress the sort/filter bar entirely. Useful when the archive is embedded in a page layout where external filtering is handled by JavaScript or…

Register a custom Member Thanks query type

Free Advanced

Push a key→object pair onto benecaster_member_thanks_query_types where the value implements BenecasterMemberThanksQueryInterface. Required methods: get_label(): string, get_description(): string, and get_results( int $show_id, int $episode_id, array $args ): array. The…

Tune or bypass the per-IP REST rate limiter

Free Intermediate

RateLimiter short-circuits over-quota requests on /benecaster/v1/ routes with 429 + Retry-After before any controller runs. benecaster_rest_rate_limit_buckets lets add-ons raise the catch-all bucket or add a custom bucket for…

Auto-select a credit template based on episode type

Free Intermediate

Use benecaster_credit_options to reorder or mark a specific credit template as default based on episode metadata — for example, always pre-select the guest interview credit template when the…

Log credit applications to an external system

Free Beginner

Use benecaster_credit_applied to send a record to an external system — a webhook, Slack notification, analytics endpoint, or spreadsheet — each time a credit template is stamped onto…

Programmatically stamp a credit on episode save

Free Advanced

Auto-apply the default credit template when a new episode is created so the podcaster never has to click Apply manually. Uses benecaster_apply_default_credit() — the public helper that resolves…

Moderate or audit-log every Supporter Wall message

Free Intermediate

SupporterWallManager::set_subscriber_message() fires benecaster_subscriber_wall_message after every write of the subscriber’s “Why I support” message — including empty-value clears. Use to auto-moderate flagged content, mirror the message to an external…