Skip to main content

benecaster_register_addon()

Free
benecaster_register_addon( string $slug, callable $bootstrap, ?array $requires_core = null, string $scope = 'show' ): void

Registers an add-on’s boot-time bootstrap with Benecaster’s system-level entitlement gate, replacing the manual any_show_addon_is_active() check an add-on would otherwise write inline. Call it once from your own benecaster_boot handler.

Benecaster invokes every registered $bootstrap on a late plugins_loaded pass (priority 20 — after benecaster_boot and after any add-on’s own plugins_loaded registration), but only for a slug entitled on at least one connected show (benecaster_addon_is_active_for_any_show() answers the same underlying question). An unregistered slug, or one registered but not currently entitled, is silently skipped — no bootstrap runs, so none of that add-on’s filters, actions, or REST routes ever register. Add-ons that have not migrated to this function and still use the manual inline check keep working, but sit outside this gate’s protection.

Backed by \Benecaster\Addons\AddonRegistrationManager.

Parameters

Name Type Default Required Description
slug string — Yes The add-on's entitlement slug, e.g. 'benecaster-addon-guest-manager'.
bootstrap callable(Container): void — Yes Callback invoked with the plugin's DI Container once the slug is confirmed entitled and (if declared) compatible.
requires_core array{version?: string, capabilities?: string[]}|null null No Optional compatibility requirements, checked only after the entitlement gate passes. version is a minimum BENECASTER_VERSION, checked with version_compare( ..., '>=' ). capabilities is a list of function or class names that must exist (function_exists() / class_exists()). Both keys are independent — declare only what you actually depend on. Omit the argument, or pass null, to skip the compatibility check entirely.
scope string 'show' No 'show' (the default) or 'site'. 'site' makes the add-on site-wide: it boots when any connected show's license grants it, ignores the per-show switch, and has no Active on list on the Add-ons screen. Honoured only for an add-on every license is granted free — otherwise 'site' quietly means 'show'. See the notes.

Return Value

Type: void

Nothing — registration only records the callback. It does not run it, and does not indicate whether the slug is currently entitled.

Example

add_action( 'benecaster_boot', function ( \Benecaster\Container $container ) {
    benecaster_register_addon(
        'benecaster-addon-guest-manager',
        function ( \Benecaster\Container $container ) {
            $container->make( \GuestManager\GuestManagerPlugin::class )->register();
        },
        [
            'version'      => '1.60.0',                        // minimum Benecaster version
            'capabilities' => [ 'benecaster_addon_is_active' ], // function/class names that must exist
        ]
    );
} );

Notes

Registration and invocation are two different moments. benecaster_register_addon() only records the callback — nothing runs until Benecaster's own late plugins_loaded pass walks every registered slug. Don't rely on side effects from your bootstrap having happened by the time your own benecaster_boot handler returns.

**The third argument, $requires_core, is a compatibility check, never a tamper check — the distinction is load-bearing.** It answers "is the thing I need here?", never "has anything changed?" A fail-closed gate here was deliberately rejected: a false positive from a host security patch, a partial upload, or an asset optimiser would switch off a paid feature for a customer who did nothing, which is fail-closed behaviour pointed at subscribers and contradicts the plugin's fail-open licensing promise. Never repurpose this parameter to detect or react to modification of Benecaster's files.

Two failure modes, two different visibilities, and that is deliberate. An unentitled slug is skipped silently — most customers do not own most add-ons, and that is a normal, expected state, surfaced instead via the "Installed — no license" status row on Settings → Add-ons. An add-on that is entitled but declares a requires_core requirement this version of Benecaster does not meet gets a visible admin_notices warning naming the add-on and what it needs, and its bootstrap is skipped — not fatal, and not silent, because an entitled, installed add-on doing nothing due to a version mismatch is exactly the kind of failure a customer needs to be told about.

$requires_core is optional — the default is null, so a two-argument call is valid.

The fourth argument, $scope, is for an add-on whose per-show switch means nothing — a block library, where one page can carry blocks for several shows. With 'site', the add-on boots when any connected show's license grants it, ignores the per-show on/off switch, makes benecaster_addon_is_active() true for every show whose license grants it, and shows no Active on list on the Add-ons screen. A request to switch it off on one show is refused with addon_site_wide.

``php benecaster_register_addon( 'benecaster-addon-my-blocks', function ( \Benecaster\Container $container ) { $container->make( \MyBlocks\Plugin::class )->register(); }, null, 'site' ); ``

'site' is honoured only for an add-on every Benecaster license is granted free, as the license server's pricing data says. For any other add-on — and on a site that has not fetched that list yet, or whose license server predates it — 'site' quietly means 'show': no error, no notice, ordinary per-show behaviour. That is deliberate: a paid add-on is granted show by show, so there is no filter to make one site-wide. Any value other than 'show' or 'site' triggers _doing_it_wrong() and is treated as 'show'.

Pass $scope positionally if your add-on may meet an older Benecaster. On a version without the parameter, a named scope: argument is a fatal Unknown named parameter error, thrown before any $requires_core check can run. A positional fourth argument is silently ignored there, so the add-on simply runs per show.

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