Inject a React component into a named slot
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 slots via window.BenecasterExtensions.registerFill(). The add-on must ship compiled JavaScript. The PHP filter approach and SlotFills are complementary: use the PHP filter to declare the tab shell, SlotFills to fill it with complex interactive content.
When to Use This
Use Tier 2 (SlotFill) when you need:
-
React components with their own state and effects
-
Third-party library embeds (charts, calendars, rich editors)
-
Live previews that update as other fields change
-
Custom pickers that fetch data from external APIs
-
Interactive UI that doesn’t map to the standard field types
For collecting simple structured data (toggles, text fields, selects) as episode meta, Tier 1 (PHP filter) is simpler and requires no JavaScript.
The two tiers are complementary. A common pattern: use Tier 1 to declare the tab shell (so the tab appears in the sidebar nav), then use Tier 2 to fill the tab’s content panel with a React component.
Prerequisites
-
Benecaster installed with a valid license
-
Your add-on ships compiled JavaScript (React + WordPress
wp.*globals available) -
Script enqueued on
admin_enqueue_scripts(only on Benecaster admin pages)
How It Works
Three pieces, and all three are needed for an editor tab:
-
Enqueue your compiled script on
admin_enqueue_scripts, guarded so it only loads on Benecaster admin pages. Declarewp-elementandwp-dom-readyas dependencies, pluswp-api-fetchif your component talks to a REST endpoint. -
Register the component as a fill. Inside
wp.domReady, callwindow.BenecasterExtensions?.registerFill( slotName, Component ). Your component receives the slot’sfillProps— see the table below for what each slot passes. -
Declare the tab shell in PHP via
benecaster_episode_editor_tabs, with an emptysectionsarray. Without this the tab never appears in the sidebar and your fill has nowhere to render. Slots that already exist in Benecaster — dashboard cards, the pre-publish panel — need only steps 1 and 2.
Named Slots
| 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 key) |
{ episodeId, showId } |
BenecasterEpisodeEditorAfterFields |
Below all episode editor fields in any tab | { episodeId, showId } |
BenecasterShowEditorAfterFields |
Below all show editor fields in the General section | { showId } |
BenecasterDashboardCards |
After built-in stat cards on the Benecaster dashboard | { showId } |
BenecasterSettingsPage_{id} |
Full add-on page in the show settings nav | { showId } |
BenecasterSubscriberDetailAfter |
Below the token section in the subscriber detail slide-in panel | { subscriberId, showId } |
BenecasterEpisodePrePublishuses underscore-separated prop names (episode_id,show_id) — not camelCase. This is intentional and matches the PHP-side REST API convention for these IDs.
Notes
window.BenecasterExtensions is the global registration object provided by Benecaster Benecaster. It is available after wp.domReady fires. Use optional chaining (?.) to guard against the case where Benecaster isn’t loaded on the current page.
JSX vs. createElement: The recipe uses wp.element.createElement so it runs without a build step. In practice most add-ons compile with @wordpress/scripts and write JSX, which compiles to React.createElement (aliased from wp.element).
wp.apiFetch handles WordPress nonce authentication automatically. Use it for any REST requests rather than raw fetch.
Script dependencies: Always list wp-element and wp-dom-ready in your script’s dependency array. Add wp-api-fetch if your component makes REST requests. This ensures WordPress loads them before your script runs.
Dashboard Cards
The recipe includes a second worked example filling BenecasterDashboardCards. It is the same shape as the editor tab — fetch on mount keyed to the showId prop, render a loading state until the data arrives — but with no PHP declaration step, because the dashboard slot already exists in Benecaster.
Code
<?php
// my-addon/resources/js/admin.js (compiled)
const MyDashboardCard = ({ showId }) => (
<div className="p-4 border rounded">
<h3>My Add-on Stats</h3>
<p>Show ID: {showId}</p>
</div>
);
wp.domReady( () => {
window.BenecasterExtensions?.registerFill(
'BenecasterDashboardCards',
MyDashboardCard
);
} );
// Named slots and their fillProps:
// BenecasterEpisodePrePublish — { episode_id, show_id }
// BenecasterEpisodeEditorTab_{id} — { episodeId, showId }
// BenecasterEpisodeEditorAfterFields — { episodeId, showId }
// BenecasterShowEditorAfterFields — { showId }
// BenecasterDashboardCards — { showId }
// BenecasterSettingsPage_{id} — { showId }
// BenecasterSubscriberDetailAfter — { subscriberId, showId }
Need this built rather than just documented? See our services →