These five hooks cover the HappenBoard admin surface: the submenu manifest that feeds both the WordPress menu and the in-app sidebar rail, the bootstrap payload handed to the React app, and the filters around the plugin’s custom capability model.
The two role-default filters behave differently from everything else here. They run inside the capability installer, not on every request, so editing a mapping changes nothing until that installer runs again.
happenboard_capabilities_role_defaults
Changes which WordPress roles receive which HappenBoard capabilities when the capability installer runs. It is applied inside Capabilities::install(), which fires on plugin activation and on the versioned backfill, not on every request.
Signature
apply_filters( 'happenboard_capabilities_role_defaults', array<string,array<int,string>> $mapping )
Parameters
-
$mappingarray<string,array<int,string>> - The defaults:
administratorgets all ten free capabilities,editorgets seven of them (everything excepthappenboard_export_attendeesandhappenboard_manage_integrations).happenboard_hostis granted to no role by default and is meant to be assigned per user.
Return value
array<string,array<int,string>>
A map of role slug to a list of capability slugs. Each entry is written with WP_Role::add_cap().
Example
add_filter(
// Put this in an mu-plugin so it is registered before init:1, then
// deactivate and reactivate HappenBoard once to apply it.
'happenboard_capabilities_role_defaults',
function ( $mapping ) {
$mapping['shop_manager'] = array(
'happenboard_view_bookings',
'happenboard_manage_availability',
);
// Stop granting bulk attendee export to administrators.
$mapping['administrator'] = array_values(
array_diff( $mapping['administrator'], array( 'happenboard_export_attendees' ) )
);
return $mapping;
}
);
Notes
- It does not run on every request, so changing the mapping grants nothing retroactively.
Capabilities::install()is reached fromPlugin::activate()(the activation hook) and fromPlugin::maybe_install_capabilities(), hooked oninitat priority 1, which returns early unless thehappenboard_caps_versionoption is below the code’sCAPS_VERSION(currently 3). On an up-to-date install neither path runs again. To apply a change, deactivate and reactivate HappenBoard, or delete thehappenboard_caps_versionoption (and the legacyhappenboard_caps_installedflag). - Register the callback before
initpriority 1: an mu-plugin, a plugin file body, orplugins_loaded. A callback added oninitat the default priority 10 is too late for the backfill path. - Additive only.
install()callsWP_Role::add_cap()and neverremove_cap(), so taking a capability out of the mapping does not revoke it from roles that already have it: callWP_Role::remove_cap()yourself. Role slugs that do not exist are skipped silently. - Uninstall does not see your changes.
Capabilities::uninstall()builds its removal list from the hard-codedROLE_DEFAULTSconstant rather than the filtered mapping, so capabilities you added through this filter survive removal of the plugin. - The class docblock says Pro extends this list through the same filter. It does not: HappenBoard Pro ships its own
happenboard_pro_capabilities_role_defaultsfilter and its own installer, and registers no callback here.
happenboard_me_capabilities
Adds to or overrides the capability map returned by GET /happenboard/v1/me/capabilities. The admin app and headless front ends read that response to decide which controls to render.
Signature
apply_filters( 'happenboard_me_capabilities', array<string,bool> $caps, \WP_User $user )
Parameters
-
$capsarray<string,bool> - Seven free capability slugs mapped to their
current_user_can()result: manage events, manage venues, manage organizers, view attendees, export attendees, manage settings, manage integrations. The three booking capabilities andhappenboard_hostare not in the base map even though the free plugin defines them. -
$user\WP_User - The result of
wp_get_current_user()for this request. Always a logged-in user: the route’s permission callback isis_user_logged_in().
Return value
array<string,bool>
A map of capability slug to boolean, serialized as-is into the capabilities key of the response.
Example
add_filter(
'happenboard_me_capabilities',
function ( $caps, $user ) {
// The booking capabilities are missing from the base matrix.
$caps['happenboard_view_bookings'] = user_can( $user, 'happenboard_view_bookings' );
$caps['happenboard_manage_booking_types'] = user_can( $user, 'happenboard_manage_booking_types' );
$caps['happenboard_manage_availability'] = user_can( $user, 'happenboard_manage_availability' );
$caps['happenboard_host'] = user_can( $user, 'happenboard_host' );
return $caps;
},
10,
2
);
Notes
- Two arguments: register with
add_filter( ..., 10, 2 ). - This is a reporting surface, not an authorization one. The endpoint reflects what
current_user_can()says; flipping a value totrueonly makes the interface show a control whose own REST permission callback will still answer 403. - HappenBoard Pro already hooks it at priority 10 with 2 arguments and adds its six capabilities (
manage_tickets,view_orders,export_orders,refund_orders,run_checkin,manage_resources). Append to the array you receive: returning a fresh one wipes both the free and the Pro entries. - The filtered array is used with no cast and no type check. Non-boolean values go straight into the JSON, so a client doing a strict comparison against
trueand one doing a truthy check will disagree. Keep the values boolean. - Any logged-in user, down to a Subscriber, can call this route. Do not key the map on anything you would not expose to every account on the site; the handler deliberately omits the user’s email address for the same reason.
happenboard_pro_capabilities_role_defaults
The Pro counterpart of happenboard_capabilities_role_defaults, covering the six ticketing and resource capabilities. It is applied inside HappenBoard\Pro\Capabilities\Capabilities::install().
Signature
apply_filters( 'happenboard_pro_capabilities_role_defaults', array<string,array<int,string>> $mapping )
Parameters
-
$mappingarray<string,array<int,string>> - The defaults:
administratorgets all six (happenboard_manage_tickets,happenboard_view_orders,happenboard_export_orders,happenboard_refund_orders,happenboard_run_checkin,happenboard_manage_resources),editorgets four (no export, no refund).
Return value
array<string,array<int,string>>
A map of role slug to a list of capability slugs, written with WP_Role::add_cap().
Example
add_filter(
// mu-plugin, registered before init:1. Takes effect on the next Pro
// activation or CAPS_VERSION bump.
'happenboard_pro_capabilities_role_defaults',
function ( $mapping ) {
$mapping['accountant'] = array(
'happenboard_view_orders',
'happenboard_export_orders',
'happenboard_refund_orders',
);
return $mapping;
}
);
Notes
- Same timing rule as the free filter.
install()is reached from Pro’s activation hook (Pro\Plugin::activate()) and fromPro\Plugin::maybe_install_capabilities()oninitat priority 1, which returns early unless thehappenboard_pro_caps_versionoption is below Pro’sCAPS_VERSION(currently 3). Editing the mapping on a running site changes nothing until one of those paths runs. - Register the callback before
initpriority 1, in an mu-plugin or onplugins_loaded. - Additive only:
install()callsWP_Role::add_cap()and never removes anything, and role slugs that do not exist are skipped without warning. happenboard_manage_integrationsis deliberately absent from Pro’s mapping because it belongs to the free plugin’s capability class, which Pro reuses in its REST permission callbacks. Grant it throughhappenboard_capabilities_role_defaultsinstead.Pro\Capabilities\Capabilities::uninstall()removes only the capabilities listed in the hard-codedROLE_DEFAULTSconstant, so anything you add through this filter stays on the roles after Pro is uninstalled.
happenboard_screen_context
The bootstrap payload handed to the admin React app as window.happenBoardVars. Add your own configuration keys here, or repoint the built-in ones such as the sidebar footer links.
Signature
apply_filters( 'happenboard_screen_context', array<string,mixed> $context )
Parameters
-
$contextarray<string,mixed> - The assembled payload:
pluginVersion,nonce(awp_restnonce),restBase,wpRestBase,siteUrl,siteName,adminEmail,adminUrl,pluginUrl,nav,links,currentUser,locale,timezone,dateFormat,timeFormat,startOfWeek,integrations,onboarded,generalandcolorPresets.
Return value
array<string,mixed>
The context array, passed straight to wp_localize_script().
Example
add_filter(
'happenboard_screen_context',
function ( $context ) {
// Repoint the sidebar footer links at an internal helpdesk.
$context['links']['support'] = 'https://example.com/helpdesk';
// Own namespace, nested so the booleans stay booleans in JS.
$context['myPlugin'] = array(
'enabled' => true,
'endpoint' => rest_url( 'my-plugin/v1/' ),
);
return $context;
},
20
);
Notes
- It only runs on HappenBoard admin screens.
ScreenContext::build()is called fromAdmin\Assets::enqueue(), which returns early unless the current screen ID containshappenboard. The block editor receives a different, unfiltered blob that also happens to be namedhappenBoardVars, built inAdmin\PostEditor, so this filter never reaches it. - Merge, do not replace. HappenBoard Pro hooks it at priority 10 to set
pro.active,pro.licenseStatusandpro.version; a callback returning a fresh array removes them and the admin app stops rendering its Pro routes. - The result goes through
wp_localize_script(), which JSON-encodes it, so no escaping is needed on your side. It also casts top-level scalars to strings, so a boolean added at the top level reaches JavaScript as"1"or"". Nest flags inside an array, the wayintegrationsdoes, to keep real booleans. - The payload is printed inline on every HappenBoard admin page for every user who can reach one, and
context['general']is already the full General settings array. Do not add API secrets, license keys or webhook signing secrets. - There is no
prokey in the base context, despite Pro’s own docblock saying the free plugin declares one. Pro creates it defensively with$context['pro'] ?? null; do the same if you read it. Note also thatnavis built fromhappenboard_admin_submenus, so building this context fires that filter too.