Skip to main content

Add an add-on tab to one show’s settings

Free Advanced

Anything whose data belongs to a single show — a per-show import, a per-show API key, per-show mappings — belongs in that show’s settings rather than on the install-wide Benecaster Settings screen, where no show is in scope.

Declare the tab in PHP with benecaster_show_settings_pages, then fill its slot in JavaScript. The tab appears in the show’s settings navigation below Templates, with the puzzle-piece icon every add-on tab uses.

Install-Wide Page or Per-Show Tab

The two routes look alike and differ in every detail:

Install-wide Per show
Filter benecaster_settings_pages benecaster_show_settings_pages
Filter arguments 1 ($pages) 2 ($pages, $show_id)
Renders in Benecaster Settings one show’s settings
Slot BenecasterSettingsPage_{id} BenecasterShowSettingsPage_{id}
fillProps none { showId }

Prerequisites

Declare the Tab

add_filter( 'benecaster_show_settings_pages', function ( array $pages, int $show_id ): array {
    $pages[] = [
        'id'     => 'my-addon',            // slot suffix and URL segment
        'label'  => __( 'My Add-on', 'my-addon' ),
        'add_on' => 'my-addon',            // hides the tab where the add-on is off
    ];
    return $pages;
}, 10, 2 );

Notes

Register the filter with 10, 2. WordPress passes one argument by default. A callback that declares $show_id without the 2 raises an ArgumentCountError, and one that declares only $pages never sees the show.

Set add_on on a paid add-on. Purchase is license-wide but activation is per show, so a Multi-Show customer can own your add-on and switch it off for one show. With your entitlement slug in add_on, Benecaster hides the tab on those shows. Without it the tab appears on every show, which suits a free add-on only. The check runs on the server, so the fill does not need to repeat it.

Handle $show_id of 0. GET /admin/extensions is also fetched without a show, and the list then comes back unfiltered. Returning the page unconditionally is correct: the declaration says the page exists, and add_on says on which shows.

The tab is deep-linkable at #/shows/{id}/settings/my-addon.

Code

// my-addon/resources/js/admin.jsx — enqueued with 'benecaster-admin' as a dependency
// and built with Benecaster's React runtime mapped as externals.
import { useQuery } from '@tanstack/react-query';

const MySettingsTab = ( { showId } ) => {
    const { data } = useQuery( {
        queryKey: [ 'my-addon-settings', showId ],
        queryFn:  () => window.wp.apiFetch( { path: `/my-addon/v1/shows/${ showId }/settings` } ),
    } );
    return <div className="bc-space-y-4">{ /* … */ }</div>;
};

wp.domReady( () => {
    window.BenecasterExtensions?.registerFill( 'BenecasterShowSettingsPage_my-addon', MySettingsTab );
} );

View on GitHub →

Hooks Used

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