These hooks sit on the output side: the four blocks that run an occurrence query, the venue map, the weather panel, the term color swatches, and the Event JSON-LD printed in wp_head.
Most of them run on every front-end render, so keep callbacks cheap and avoid extra queries inside them. Where HappenBoard Pro already listens, the note on the hook says so and gives its priority.
happenboard_favorite_frontend_global_printed
Fires in wp_footer right after the Favorite Toggle block prints the inline script that defines window.happenBoardFrontend.isLoggedIn. Hook it to print further inline JavaScript that depends on that global, exactly once per page.
Signature
do_action( 'happenboard_favorite_frontend_global_printed' )
Example
add_action(
'happenboard_favorite_frontend_global_printed',
function () {
wp_print_inline_script_tag(
'window.happenBoardFrontend.myLocale = '
. wp_json_encode( get_locale() ) . ';'
);
}
);
Notes
- No arguments. A plain
add_action( 'happenboard_favorite_frontend_global_printed', $cb )is enough. - It fires on
wp_footerat priority 5, and only once per request: the printing callback is guarded bydid_action(), so additional Favorite Toggle blocks on the same page print nothing and fire nothing. - It only fires when at least one Favorite Toggle block actually renders, and the block itself bails unless the resolved post is an
hboard_event. Pages without the block never reach it. - By the time it fires,
wp_enqueue_script()is only useful for footer scripts. Print inline JavaScript withwp_print_inline_script_tag()instead. - Firing the action yourself earlier in the request suppresses the built-in output: the guard is
! did_action( 'happenboard_favorite_frontend_global_printed' ), sowindow.happenBoardFrontend.isLoggedInis never defined and the toggle’s view script loses its auth state.
happenboard_query_attributes
Rewrites the attributes of the four blocks that run an occurrence query, at the very top of their render callback and before any value is read. $context tells you which block is asking, so a single callback can serve all four.
Signature
apply_filters( 'happenboard_query_attributes', array<string,mixed> $attributes, string $context )
Parameters
-
$attributesarray<string,mixed> - Block attributes as saved in the editor, plus whatever earlier callbacks changed. Keys left out fall back to per-block defaults after the filter.
-
$contextstring - One of
event-query-loop,events-grid,events-list,upcoming-events.
Return value
array<string,mixed>
The attribute array the block will read. Cast with (array): a non-array return becomes an empty array and every attribute falls back to its per-block default.
Example
add_filter(
'happenboard_query_attributes',
function ( $attributes, $context ) {
if ( 'event-query-loop' !== $context ) {
return $attributes;
}
// Members-only events (term 12) stay hidden from logged-out visitors.
if ( ! is_user_logged_in() ) {
$attributes['categoryIds'] = array( 12 );
}
return $attributes;
},
10,
2
);
Notes
- Two arguments. Without
add_filter( ..., 10, 2 )you cannot tell the four blocks apart. - The four call sites are
Block\EventQueryLoop,Block\EventsGrid,Block\EventsListandBlock\UpcomingEvents. No other block or admin screen uses this seam. - The blocks do not share a vocabulary.
dateRange,organizerId,layoutandorderare read only byevent-query-loop;events-listandevents-gridreadcategoryIds,tagIds,venueIdandcountbut ignoreorganizerId;upcoming-eventsreads onlycount. A key the block does not read is silently ignored. - Values are clamped after the filter, so you cannot raise a limit here:
countis capped at 50 forevent-query-loop,events-listandupcoming-events, and at 24 forevents-grid. - Pro registers
Service\Filtering\QueryArgsResolver::filter_attributesat priority 10 with 2 args to project the FilterBar’s URL parameters. Its class docblock lists?hboard_venue=and?hboard_organizer=, but the code readshappenboard_venueandhappenboard_organizerbecause every parameter goes through thehappenboard_prefix constant. It also parseshappenboard_from,happenboard_toandhappenboard_qand then never projects them onto any attribute, and it early-returns forupcoming-events.
happenboard_schema_disable
Suppresses HappenBoard’s Event JSON-LD for a given post. It is the first thing EventSchemaPrinter::maybe_print() evaluates, before any part of the schema is built, so returning true costs nothing.
Signature
apply_filters( 'happenboard_schema_disable', bool $disabled, int $post_id )
Parameters
-
$disabledbool - Default
false. -
$post_idint - The queried single event, from
get_queried_object_id().
Return value
bool
Truthy to skip the output entirely. The value is cast with (bool).
Example
add_filter(
'happenboard_schema_disable',
function ( $disabled, $post_id ) {
return $disabled || (bool) get_post_meta( $post_id, '_my_no_event_schema', true );
},
10,
2
);
Notes
- Two arguments. Register with
add_filter( ..., 10, 2 )to receive$post_id, otherwise you can only switch the whole site off. - It runs from a
wp_headcallback at priority 30 and only onis_singular( 'hboard_event' )views. It has no effect on schema emitted anywhere else, including Pro’s SEOPress schema-editor integration in wp-admin, which calls the builder directly. - Returning true short-circuits the rest of the chain:
happenboard_schema_event_type,happenboard_schema_offers,happenboard_schema_fallback_currencyandhappenboard_schema_eventnever fire. - You do not need it for SEOPress. When the post carries a manually configured Event schema in the
_seopress_pro_schemasmeta and SEOPress is active, the printer already steps aside on its own. - The value is cast with
(bool). Returning the string'false'disables the schema, because a non-empty string is truthy.
happenboard_schema_fallback_currency
Sets the currency of the placeholder free Offer that EventSchemaBuilder emits when an event ends up with no offers at all. It has no effect on real offers.
Signature
apply_filters( 'happenboard_schema_fallback_currency', string $currency )
Parameters
-
$currencystring - Default
'USD'.
Return value
string
A three-letter ISO 4217 code. The builder applies strtoupper() to it, so lowercase input is fine.
Example
add_filter(
'happenboard_schema_fallback_currency',
function ( $currency ) {
return 'EUR';
}
);
Notes
- One argument.
- It fires only when
happenboard_schema_offersreturned an empty array. As soon as one offer exists, the placeholder is never built and this filter never runs. - The placeholder is a single
Offerwithprice'0'andavailabilityInStock, pointing at the event permalink, alongsideisAccessibleForFreeset to true. Changing the currency does not make the event look paid. - The value is cast to string and uppercased but never validated. An invalid code goes straight into the JSON-LD and Google flags the offer.
- It runs inside
EventSchemaBuilder, which Pro’s SEOPress integration also calls in wp-admin to pre-fill the schema editor. Keep the callback free of front-end-only conditions such asis_singular().
happenboard_schema_offers
Supplies the offers array of the Event JSON-LD. Free passes an empty array, so this is the seam a ticketing integration uses to emit one schema.org Offer per ticket type.
Signature
apply_filters( 'happenboard_schema_offers', array<int,array<string,mixed>> $offers, int $event_id, string $url )
Parameters
-
$offersarray<int,array<string,mixed>> - Always
array()when the filter first runs in Free. -
$event_idint - The event post ID.
-
$urlstring - Canonical event permalink, ready to use as each Offer’s
url.
Return value
array<int,array<string,mixed>>
A list of Offer arrays. The result goes through is_array(), so a non-array return is replaced by an empty array without any warning.
Example
add_filter(
'happenboard_schema_offers',
function ( $offers, $event_id, $url ) {
$price = (string) get_post_meta( $event_id, '_my_ticket_price', true );
if ( '' === $price ) {
return $offers;
}
$offers[] = array(
'@type' => 'Offer',
'url' => $url,
'price' => $price,
'priceCurrency' => 'EUR',
'availability' => 'https://schema.org/InStock',
);
return $offers;
},
10,
3
);
Notes
- Three arguments. Use
add_filter( ..., 10, 3 )to receive$url. - Return an empty array and the builder substitutes a free placeholder Offer priced at
'0', in the currency fromhappenboard_schema_fallback_currency. There is no way to emit an Event with noofferskey. isAccessibleForFreeis computed from what you return, not from the placeholder: it stays true when every entry has apriceof 0 or less, and when you return nothing. Set a numericpriceon each offer or the event is advertised as free.- Entry shape is not validated. A missing
@type,priceCurrencyoravailabilityis emitted as is and Google rejects the offer. - The docblock on
EventSchemaBuilder::offers()states that Pro hooks this filter to inject one Offer per ticket type. No callback in the current Pro tree does, so the hook is unclaimed and priority 10 is free.
happenboard_term_color_presets
Changes the swatch palette offered when picking a color for a HappenBoard category, tag or calendar term. The result is localised as happenBoardVars.colorPresets for the admin SPA and the block editor sidebar.
Signature
apply_filters( 'happenboard_term_color_presets', array<int,array{name:string,color:string}> $presets )
Parameters
-
$presetsarray<int,array{name:string,color:string}> - Ten default swatches, each an array with
name(translated label) andcolor(lowercase#RRGGBB).
Return value
array<int,array{name:string,color:string}>
The palette. Every entry is re-validated afterwards, so malformed swatches disappear rather than breaking the picker.
Example
add_filter(
'happenboard_term_color_presets',
function ( $presets ) {
$presets[] = array(
'name' => 'Brand',
'color' => '#1a7f5a',
);
return $presets;
}
);
Notes
- One argument.
- Only
#RRGGBBsurvives. After the filter, each entry is dropped unlessstrtolower( $preset['color'] )matches/^#[0-9a-f]{6}$/, so three-digit shorthand,rgb(),hsl(), named colors and 8-digit hex with alpha all vanish silently. nameis optional and falls back to the hex string. An entry with nocolorkey, or one that is not an array, is dropped.- It is consumed on two admin surfaces only: the HappenBoard admin SPA bootstrap (
Admin\ScreenContext) and the block editor sidebar bundle (Admin\PostEditor). It changes the picker, not the colors already saved on terms, and has no effect on front-end rendering. - A second, client-side filter runs after it: the JS layer applies
happenboard.term.colorPresetsthrough@wordpress/hooksinassets/js/shared/colorPresets.js. A palette you set in PHP can still be changed there.
happenboard_venue_map_html
Replaces the entire map markup rendered by the Event Venue block. The returned string is inserted into the block output verbatim, with no escaping applied afterwards, so you own the escaping.
Signature
apply_filters( 'happenboard_venue_map_html', string $html, string $provider, array $context )
Parameters
-
$htmlstring - Default markup: a
<dd>wrapper containing a lazy-loaded<iframe>, already escaped. -
$providerstring - Resolved provider:
osm,googleorcustom. -
$contextarray lat(float),lng(float),zoom(int),height(int),name(string) andsettings(the full General settings array).
Return value
string
The markup to output. Cast with (string).
Example
add_filter(
'happenboard_venue_map_html',
function ( $html, $provider, $context ) {
return sprintf(
'<dd class="my-map" data-lat="%s" data-lng="%s" data-zoom="%d" style="height:%dpx"></dd>',
esc_attr( (string) $context['lat'] ),
esc_attr( (string) $context['lng'] ),
(int) $context['zoom'],
(int) $context['height']
);
},
20,
3
);
Notes
- Three arguments. Use
add_filter( ..., 10, 3 ). $context['settings']isGeneralRepository::all(), which includes the raw server-only secrets:google_maps_api_key,weather_api_key,turnstile_secret_keyandakismet_api_key. Never echo that array into markup or into a JavaScript payload.- It only runs when the block has
showMapenabled, the event format is notvirtual, and the resolved venue has both a latitude and a longitude. No coordinates means no map and no filter. - Pro’s
Service\Maps\Renderer::filter_map_htmlis already registered at priority 10 with 3 args. When the Map Design Studio is active, a callback at a higher priority receives Pro’s MapLibre<div>rather than the iframe, while$providerstill names the Free provider. customreaches$provideronly when a Venue block explicitly sets itsmapProviderattribute tocustomandcustom_iframe_urlis configured. It is unreachable through the site default: the settings sanitizer coercesmaps_providertoosmfor anything other thanosmorgoogle.
happenboard_venue_map_iframe_src
Swaps the URL loaded in the Event Venue block’s map iframe without touching the wrapper markup. It runs just before the iframe is assembled, so the height, lazy loading, title and referrer policy of the default output are kept.
Signature
apply_filters( 'happenboard_venue_map_iframe_src', string $src, string $provider, array $context )
Parameters
-
$srcstring - Provider-built URL: the OpenStreetMap embed with a computed bounding box, the Google Maps Embed API URL, or the
custom_iframe_urltemplate with{lat},{lng}and{zoom}already expanded. -
$providerstring - Resolved provider:
osm,googleorcustom. -
$contextarray lat(float),lng(float),zoom(int) andname(string). Nothing else.
Return value
string
The iframe URL. It is passed through esc_url() before output.
Example
add_filter(
'happenboard_venue_map_iframe_src',
function ( $src, $provider, $context ) {
return add_query_arg(
array(
'lat' => $context['lat'],
'lng' => $context['lng'],
'zoom' => $context['zoom'],
),
'https://maps.example.com/embed'
);
},
10,
3
);
Notes
- Three arguments. Use
add_filter( ..., 10, 3 ). The method docblock above the call announces a filter namedhappenboard/venue/map/iframe_src, with slashes: that name does not exist, the hook ishappenboard_venue_map_iframe_src. - It runs before
happenboard_venue_map_html. A callback that replaces the whole markup on that later filter makes whatever you return here irrelevant, which is exactly what Pro’s Map Design Studio does. esc_url()is applied after the filter.data:andjavascript:URLs are stripped and the iframe ends up with an emptysrc.$contexthere is the short form. There is noheightand nosettingskey: those exist only onhappenboard_venue_map_html.- A filter keyed on
'custom' === $providermay never fire, because the block falls back toosmwhencustom_iframe_urlis empty, and also whengoogleis requested withoutgoogle_maps_api_key. Handleosmtoo, or key on the coordinates instead.
happenboard_weather_data
Adjusts the normalised weather payload WeatherRepository::get() hands back to the Event Weather block, after the cache lookup and any Open-Meteo call. Add fields or correct values without triggering another fetch.
Signature
apply_filters( 'happenboard_weather_data', array<string,mixed> $result, array{lat:float,lng:float,date:string,regime:string} $ctx )
Parameters
-
$resultarray<string,mixed> - Normalised day data merged with
regime(historical,forecastorclimatology),dateandunit_labels. The block readsweather_code,is_day,temp,temp_maxandunit_labels. -
$ctxarray{lat:float,lng:float,date:string,regime:string} - Request context:
lat,lng,date(Y-m-din the site timezone) andregime.
Return value
array<string,mixed>
The payload the renderer consumes. Cast with (array): a scalar return becomes a single-element array and the block then renders with regime and every other key missing.
Example
add_filter(
'happenboard_weather_data',
function ( $result, $ctx ) {
// Long-range climatology has no meaningful daily high.
if ( 'climatology' === $ctx['regime'] ) {
$result['temp_max'] = null;
}
return $result;
},
10,
2
);
Notes
- Two arguments. Use
add_filter( ..., 10, 2 ). - Weather is off by default. Nothing fires until
weather_enabledis switched on in the General settings, andget()also returns before the filter on out-of-range coordinates or a date that is notY-m-d. - It runs after the cache, not before it. The upstream response is cached under a key built from regime, coordinates rounded to two decimals, date and units, so your changes are re-applied on every request and never stored.
regimedrives both the block’s CSS class (is-regime-*) and the label prefix. Removing or renaming it breaks the rendered output.- The source docblock says Pro adds fields here, such as alerts and an hourly strip. No callback in the current Pro tree listens on this filter, so priority 10 is free.