Skip to main content

Admin Extension Points

Required add-on: Core

Benecaster exposes a structured set of extension surfaces for add-ons to add UI, configuration, and behavior to the admin — without editing Benecaster’s own files or fighting with WordPress hooks. There are two tiers: a PHP-only tier for field-based configuration, and a React SlotFill tier for interactive components.


Two Tiers of Admin Extension

Tier 1 — PHP Filter (Fields Only)

Declare tabs, settings pages, and dashboard cards using PHP arrays. No JavaScript required. Benecaster renders the UI automatically from the declaration.

Use Tier 1 when your add-on needs to collect structured configuration data (toggles, text inputs, selects) that stores as episode meta or show options. It’s the right starting point for most add-ons.

Tier 2 — React SlotFill (Interactive Components)

Fill a named slot with a React component compiled into your add-on’s JavaScript bundle. Use Tier 2 when your UI needs state, effects, third-party widget embeds, live previews, or custom pickers that can’t be expressed as field declarations.

The two tiers are complementary. A common pattern: declare a tab shell with a Tier 1 PHP filter (so the tab appears in the sidebar nav), then fill its content with a Tier 2 React component.


PHP Extension Filters

Episode Editor Tabs

Filter: benecaster_episode_editor_tabs

Adds tabs to the episode editor sidebar. Each tab declaration includes an id, label, optional icon, and a sections array of field declarations. Fields with meta: true are stored as episode post meta automatically.

Full spec, field types, and example: benecaster_episode_editor_tabs · add-episode-editor-tab-via-php


Custom Settings Pages

Filter: benecaster_settings_pages

Adds a page to the left navigation of the Benecaster Settings screen, which is install-wide, not per show. Benecaster renders no fields for it: the page’s content is whatever React component you register for its BenecasterSettingsPage_{id} slot (Tier 2). The fill receives no props, because no show is in scope there.

Full spec and example: benecaster_settings_pages


Per-Show Settings Tabs

Filter: benecaster_show_settings_pages

Adds a tab to one show’s settings navigation, below Templates. Use it for anything whose data belongs to a single show. As with settings pages, Benecaster renders no fields: the tab’s content is the React component you register for its BenecasterShowSettingsPage_{id} slot, and the fill receives { showId }.

The filter takes two arguments ($pages, $show_id), so register it with 10, 2. Put your entitlement slug in the add_on key and Benecaster hides the tab on any show where your add-on is switched off.

Full spec and example: benecaster_show_settings_pages · add-a-tab-to-a-shows-settings


Settings Sections

Filter: benecaster_settings_sections

A data-only extension point. Declarations reach the GET /admin/extensions response, but no settings screen renders them, so the fields are not shown and nothing saves them. For an add-on tab in a show’s settings, use benecaster_show_settings_pages; for a few fields below the show editor’s own, use the BenecasterShowEditorAfterFields slot.

Full spec: benecaster_settings_sections


Dashboard Cards

Filter: benecaster_dashboard_cards

Adds cards to the Benecaster dashboard after the built-in stat cards. Cards render via the BenecasterDashboardCards SlotFill slot.

Full spec and example: benecaster_dashboard_cards · inject-react-component-into-slot


Email Types

Filter: benecaster_managed_email_types

Registers a new email type with Benecaster’s email system. Every type returned by this filter appears as an editable template in the Email Editor add-on’s template manager. Benecaster registers welcome, token_reset, and token_revoked at boot.

Full spec and example: benecaster_managed_email_types · register-email-type


Add-on Setup Checks

Filter: benecaster_addon_setup_checks

Registers persistent admin setup notices for add-ons that require external configuration before functioning — API keys, OAuth connections, platform links. The notice appears on all wp-admin screens until all registered requirements pass. Dismissed notices re-surface after 7 days if requirements remain unmet.

Each requirement specifies: key (unique string), check (callable returning true when met), message (label shown while incomplete), action_label and action_url (CTA link in the notice), and optional requires (key of a prerequisite requirement within the same add-on — prevents cascading “incomplete” items when step B depends on step A).

Dismiss state is stored per-user in user meta (_benecaster_setup_notice_dismissed_{addon_slug}). The state auto-clears when all requirements pass — the notice stops appearing without the admin having to re-dismiss it.

add_filter( 'benecaster_addon_setup_checks', function ( array $checks ): array {
    $checks[] = [
        'addon_slug'   => 'my-addon',
        'requirements' => [
            [
                'key'          => 'api_key',
                'check'        => fn() => ! empty( get_option( 'my_addon_api_key' ) ),
                'message'      => 'Enter your My Service API key in My Addon settings.',
                'action_label' => 'Go to settings',
                'action_url'   => admin_url( 'admin.php?page=benecaster&tab=my-addon' ),
            ],
        ],
    ];
    return $checks;
} );

React SlotFill Slots

All slots are rendered unconditionally — they are simply empty when no add-on has registered a fill. Register fills after wp.domReady fires using window.BenecasterExtensions?.registerFill( slotName, Component ).

Build your bundle against Benecaster’s React. A fill renders inside Benecaster’s React tree, so it must share Benecaster’s copy of React to use hooks. Benecaster publishes its runtime on window.BenecasterExtensions for this. Your add-on needs two things:

  1. Enqueue your script with benecaster-admin as a dependency, so Benecaster’s runtime is published before your bundle is parsed.
  2. Map react, react-dom, react-dom/client, react/jsx-runtime, @wordpress/i18n and @tanstack/react-query as externals pointing at window.BenecasterExtensions.

Without both, a component that calls useState or useEffect throws Invalid hook call at runtime, and nothing in the admin explains why. The key names, a bundler config and the setup-wizard exceptions are in inject-react-component-into-slot.

Slot name Location fillProps
BenecasterEpisodePrePublish Pre-publish panel in the episode editor (fires before Publish is confirmed) { episode_id, show_id }
BenecasterEpisodeEditorTab_{id} Episode editor tab panel (where {id} matches the tab’s id in benecaster_episode_editor_tabs) { episodeId, showId }
BenecasterEpisodeEditorAfterFields Below all fields in the episode editor { episodeId, showId }
BenecasterShowEditorAfterFields Below all fields in the show editor General section { showId }
BenecasterDashboardCards After built-in stat cards on the dashboard { showId }
BenecasterSettingsPage_{id} An add-on page on the install-wide Benecaster Settings screen none
BenecasterShowSettingsPage_{id} An add-on tab inside one show’s settings (declared with benecaster_show_settings_pages) { showId }
BenecasterSubscriberDetailAfter Below the token section in the subscriber detail slide-in panel { subscriberId, showId }

BenecasterEpisodePrePublish uses underscore-separated prop names (episode_id, show_id) unlike most other slots which use camelCase. This matches the PHP-side convention for episode and show IDs throughout the REST API.

The two settings-page slots are easy to confuse. A fill registered under the wrong name never renders, and a fill on BenecasterSettingsPage_{id} that reads showId gets undefined. Neither raises an error, so the symptom is a blank tab.

BenecasterSubscriberDetailAfter’s subscriberId is the WordPress user ID — not the subscriber row ID the /subscribers/{id} REST routes take. Look up the subscriber row by user ID if your fill needs to call those routes.

For a complete SlotFill example covering tab injection and dashboard cards, see inject-react-component-into-slot.


Front-End Extension

Account Page Sections

Filter: benecaster_account_sections

Fires at the end of the [benecaster_account] shortcode output, after all built-in subscriber account sections (feed URL, QR code, app deep links). Hook here to append HTML sections to the subscriber-facing account page.

Full spec: benecaster_account_sections


Quick Reference

Surface Mechanism Where it appears
Episode editor sidebar tab benecaster_episode_editor_tabs filter Episode editor
Episode editor interactive tab BenecasterEpisodeEditorTab_{id} SlotFill Episode editor
Episode editor extra fields BenecasterEpisodeEditorAfterFields SlotFill Episode editor
Pre-publish panel BenecasterEpisodePrePublish SlotFill Episode editor
Show editor extra fields BenecasterShowEditorAfterFields SlotFill Show editor
Dashboard card benecaster_dashboard_cards filter + BenecasterDashboardCards SlotFill Dashboard
Add-on settings page benecaster_settings_pages filter + BenecasterSettingsPage_{id} SlotFill Benecaster Settings (install-wide)
Add-on tab in a show’s settings benecaster_show_settings_pages filter + BenecasterShowSettingsPage_{id} SlotFill One show’s settings
Settings section declarations benecaster_settings_sections filter Nowhere (data-only)
Subscriber detail panel section BenecasterSubscriberDetailAfter SlotFill Subscriber list
Subscriber account page section benecaster_account_sections action Front-end account page
Email type registration benecaster_managed_email_types filter Email Editor
Add-on setup notices benecaster_addon_setup_checks filter All wp-admin screens (until configured)

See Also

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