HappenBoard sends its transactional email through a small set of seams: one filter picks the recipient’s language, one filter per template rewrites or cancels the message just before it goes out, and one filter sets the reminder schedule for appointment bookings.
The happenboard_mp_* actions are outbound only. HappenBoard fires them into MailerPress, where the operator builds the actual email in the automation interface. They exist only in HappenBoard Pro, and they only fire when MailerPress is active and the integration is switched on.
happenboard_booking_reminder_offsets
Sets how long before an appointment the reminder emails go out. The default is two reminders, 24 hours and 1 hour before the start.
Signature
apply_filters( 'happenboard_booking_reminder_offsets', array<int,int> $offsets, int $booking_id, array<string,mixed> $row )
Parameters
-
$offsetsarray<int,int> - Hours before the start. Defaults to
array( 24, 1 ). -
$booking_idint - Primary key of the booking.
-
$rowarray<string,mixed> - The booking row. Empty array on the unschedule path, see the notes.
Return value
array<int,int>
A list of whole hours before the booking start. An empty array disables booking reminders.
Example
add_filter(
'happenboard_booking_reminder_offsets',
function ( array $offsets, int $booking_id, array $row ): array {
// Two days before, the day before, and two hours before.
return array( 48, 24, 2 );
},
10,
3
);
Notes
- Three arguments are passed, so register with
10, 3. - Values are whole hours. Zero, negative and duplicate values are dropped, and any reminder that would fire less than a minute from now is skipped, so a booking made an hour before it starts gets no reminder.
- Return the same list every time. Without Action Scheduler installed, the filter is called a second time when a booking is cancelled, in order to clear the pending reminders, and it is called with an empty
$row. A callback that derives the list from$rowreturns something different there and leaves orphan reminders scheduled. - Return an empty array to turn booking reminders off completely.
- This only covers appointment bookings. Event reminders are scheduled from the
reminder_hours_beforegeneral setting, which has no filter.
happenboard_email_locale
Chooses the language a notification is rendered in. HappenBoard wraps the subject line and the template body in switch_to_locale() using whatever this filter returns, so one recipient can get French while the site runs in English.
Signature
apply_filters( 'happenboard_email_locale', string $locale, string $template_id, WP_Post $event, array<string,mixed> $attendee )
apply_filters( 'happenboard_email_locale', string $locale, int $booking_id )
Parameters
-
$localestring - The site locale, from
get_locale(). Passed by both call shapes. -
$template_idstring - For attendee emails:
confirmationorreminder. The booking calls put the booking id, an integer, in this position instead. -
$eventWP_Post - The source event. Attendee emails only, the booking calls do not pass it.
-
$attendeearray<string,mixed> - The full attendee row, including the
custom_fieldsblob. Attendee emails only.
Return value
string
A WordPress locale such as fr_FR. Return $locale unchanged to keep the site language.
Example
add_filter(
'happenboard_email_locale',
function ( string $locale, $context = '', $event = null, $attendee = array() ): string {
// The booking notifier passes only two arguments, so every
// parameter after $locale needs a default value.
if ( ! is_array( $attendee ) || empty( $attendee['email'] ) ) {
return $locale;
}
return str_ends_with( (string) $attendee['email'], '.fr' ) ? 'fr_FR' : $locale;
},
10,
4
);
Notes
- The two call sites disagree.
src/Service/Notifications/AttendeeNotifier.phppasses four arguments, whilesrc/Service/Booking/Notifications/BookingNotifier.phppasses only two, and its second argument is the booking id (an integer), not a template id. Give every parameter after$localea default value in your callback, otherwise the booking calls reach it with missing arguments and PHP raises anArgumentCountError. - Register with
10, 4. With the default of one argument you never see$attendeeand cannot tell one recipient from another. - The two paths also treat an empty return differently. The attendee notifier checks for an empty string and skips the switch, so returning
''is safe there. The booking notifier feeds the return value straight intoswitch_to_locale()with no check, so always return a real locale. - HappenBoard Pro registers
Service\I18n\LocaleResolveron this filter at priority 10 with four accepted arguments. It reads the attendee’s language custom field (keylanguageby default) and returns the incoming value when it finds nothing. Hook later than 10 if you want the last word. - Switching only changes strings that have translation files installed on the site. A locale with no language pack produces an email in the original English.
happenboard_mp_checked_in
The MailerPress workflow trigger fired when an attendee is checked in at the door. It carries a ready-made context of contact identity and event merge fields.
Signature
do_action( 'happenboard_mp_checked_in', array<string,mixed> $ctx )
Parameters
-
$ctxarray<string,mixed> - Resolved context:
user_id,email,first_name,last_name,event_id,event_title,event_url,event_date,venue,quantity.
Example
add_action(
'happenboard_mp_checked_in',
function ( array $ctx ): void {
error_log(
sprintf(
'%s checked in at %s.',
(string) ( $ctx['email'] ?? '' ),
(string) ( $ctx['event_title'] ?? '' )
)
);
}
);
Notes
- One argument only, so a plain
add_action()is enough. - This is an outbound trigger. HappenBoard fires it into MailerPress and sends nothing itself. The operator builds the email, the tags and the delays in the MailerPress automation interface, where this trigger appears as “Event, Attendee checked in”.
- It is registered only when MailerPress is installed (the bridge tests for
add_mailerpress_contact()) and the integration is switched on in the HappenBoard Pro settings. Otherwise the action never fires at all. - It rides
happenboard_pro_attendee_checked_inat priority 20, so it fires on re-scans too. The check-in row id is dropped by the bridge and is not in$ctx; hook the underlying action if you need it. - The bridge returns early when the attendee row cannot be read or has no email, so this action never fires with an empty context.
happenboard_mp_post_event
The MailerPress workflow trigger fired the day after an event ends, once per attendee who was going. Use it for a thank-you, a survey or a follow-up offer.
Signature
do_action( 'happenboard_mp_post_event', array<string,mixed> $ctx )
Parameters
-
$ctxarray<string,mixed> - Resolved context:
user_id,email,first_name,last_name,event_id,event_title,event_url,event_date,venue,quantity.
Example
add_action(
'happenboard_mp_post_event',
function ( array $ctx ): void {
my_plugin_queue_survey(
(string) ( $ctx['email'] ?? '' ),
(int) ( $ctx['event_id'] ?? 0 )
);
}
);
Notes
- One argument only. It is the bridge translation of
happenboard_mp_post_event_tick, which a daily cron fires per attendee. - Recurring series are skipped. The daily scan excludes any event that has a non-empty
_happenboard_rrule, because a series has no single end date. Attendees of a recurring event never get this trigger. - Only attendees whose status is
goingare included. Cancelled and waitlisted rows are filtered out before the tick fires. - It fires at most once per event: the scan writes a
_happenboard_mp_post_event_firedflag on the event before looping over attendees, so a failure part way through loses the remaining attendees rather than replaying the whole event tomorrow. - Timing depends on WP-Cron. The scan looks at events whose end falls between 26 hours and 1 hour ago and processes at most 100 events per run, so a site with no cron traffic can miss the window entirely.
happenboard_mp_post_event_tick
The raw per-attendee tick emitted by the daily post-event scan. The MailerPress bridge listens to it and turns it into happenboard_mp_post_event. Fire it yourself to replay a follow-up for one attendee.
Signature
do_action( 'happenboard_mp_post_event_tick', int $attendee_id, int $event_id )
Parameters
-
$attendee_idint - Primary key of the attendee row.
-
$event_idint - The event that just ended.
Example
add_action(
'happenboard_mp_post_event_tick',
function ( int $attendee_id, int $event_id ): void {
error_log(
sprintf(
'Post-event follow-up due for attendee %d of event %d.',
$attendee_id,
$event_id
)
);
},
10,
2
);
Notes
- Two arguments are passed, so register with
10, 2. The MailerPress bridge itself listens with10, 2. - It comes from the daily WP-Cron job
happenboard_pro_mp_post_event_scan, which self-gates on the MailerPress integration being enabled. The scan does nothing when the setting is off, so nothing fires. - The scan window is events whose
_happenboard_endfalls between 26 hours and 1 hour ago, capped at 100 events per run and 1000 attendees per event. Recurring series are excluded and only attendees with statusgoingproduce a tick. - Unlike the other
happenboard_mp_*hooks, this one carries plain ids, not the resolved context array. The bridge resolves the context afterwards. - Calling
do_action( 'happenboard_mp_post_event_tick', $attendee_id, $event_id )yourself is the supported way to re-send a follow-up, since the per-event flag stops the scan from doing it twice.
happenboard_mp_reminder
The MailerPress workflow trigger fired at the reminder time before an event, 24 hours before the start by default. Use it for the “see you tomorrow” message anchored to the event date.
Signature
do_action( 'happenboard_mp_reminder', array<string,mixed> $ctx )
Parameters
-
$ctxarray<string,mixed> - Resolved context:
user_id,email,first_name,last_name,event_id,event_title,event_url,event_date,venue,quantity.
Example
add_action(
'happenboard_mp_reminder',
function ( array $ctx ): void {
error_log(
sprintf(
'Reminder due for %s, event on %s.',
(string) ( $ctx['email'] ?? '' ),
(string) ( $ctx['event_date'] ?? '' )
)
);
}
);
Notes
- One argument only. It rides
happenboard_cron_reminderat priority 20, the one-off cron event HappenBoard schedules when a sign-up is recorded. - If “send reminder email” is off in the HappenBoard settings, no reminder is ever scheduled and this trigger never fires, whatever MailerPress is configured to do.
- The offset comes from the
reminder_hours_beforegeneral setting, 24 by default, and is applied at sign-up time. Changing the setting later does not move reminders that are already scheduled. - The bridge does not re-check the attendee status, unlike HappenBoard’s own notifier at priority 10. An attendee who cancelled after signing up still produces this trigger. Test
$ctxagainst the current row if that matters. - A sign-up recorded less than the offset before the start schedules nothing at all, because the reminder time is already in the past.
happenboard_mp_rsvp_cancelled
The MailerPress workflow trigger fired when a registration is cancelled. Use it for a win-back sequence or to ask what went wrong.
Signature
do_action( 'happenboard_mp_rsvp_cancelled', array<string,mixed> $ctx )
Parameters
-
$ctxarray<string,mixed> - Resolved context:
user_id,email,first_name,last_name,event_id,event_title,event_url,event_date,venue,quantity.
Example
add_action(
'happenboard_mp_rsvp_cancelled',
function ( array $ctx ): void {
my_plugin_tag_contact(
(string) ( $ctx['email'] ?? '' ),
'cancelled-' . (int) ( $ctx['event_id'] ?? 0 )
);
}
);
Notes
- One argument only. It rides
happenboard_rsvp_cancelledat priority 20. - It therefore covers far more than a visitor clicking the cancel link: a Stripe refund and a reversed WooCommerce order also fire the underlying action, once per attendee row.
$ctxgives you no way to tell those apart, so listen tohappenboard_rsvp_cancelleddirectly if you need the distinction. - No contact is created or updated on this path. The bridge only upserts the MailerPress contact on the sign-up trigger, so a cancellation for someone who was never synced resolves a context but has no contact behind it.
- The context is read from the attendee row after the cancellation, so
$ctxdescribes a row whose status is alreadycancelled. - An administrator setting the status to
cancelledin the attendees list does not reach this trigger.
happenboard_mp_rsvp_created
The MailerPress workflow trigger fired when someone registers for an event. Use it to welcome the attendee, deliver practical details or start a pre-event sequence.
Signature
do_action( 'happenboard_mp_rsvp_created', array<string,mixed> $ctx )
Parameters
-
$ctxarray<string,mixed> - Resolved context:
user_id,email,first_name,last_name,event_id,event_title,event_url,event_date,venue,quantity.
Example
add_action(
'happenboard_mp_rsvp_created',
function ( array $ctx ): void {
error_log(
sprintf(
'%s registered for %s (%d seats).',
(string) ( $ctx['email'] ?? '' ),
(string) ( $ctx['event_title'] ?? '' ),
(int) ( $ctx['quantity'] ?? 1 )
)
);
}
);
Notes
- One argument only. It rides
happenboard_rsvp_submittedat priority 20, so it runs after HappenBoard’s own confirmation email at priority 10. - The MailerPress contact is upserted before the action fires, when attendee sync is enabled. That ordering is deliberate: the contact exists by the time MailerPress resolves the trigger.
- Paid orders fire the underlying action once per ticket line, so one Stripe checkout or WooCommerce order can produce several triggers for the same buyer.
first_nameandlast_namecome from splitting the display name on its first space. A single-word name leaveslast_nameempty.event_dateis a formatted, human-readable string built with the site date and time formats, not a machine-readable date. Useevent_idwhen you need the real value.
happenboard_pro_mailerpress_contact
Filters the MailerPress contact record just before HappenBoard creates or updates it, so you can attach extra custom fields, extra lists or your own opt-in source.
Signature
apply_filters( 'happenboard_pro_mailerpress_contact', array<string,mixed> $payload, array<string,mixed> $ctx )
Parameters
-
$payloadarray<string,mixed> - The arguments for
add_mailerpress_contact():email,firstName,lastName,subscription_status,lists,custom_fieldsandopt_in_source. -
$ctxarray<string,mixed> - The same resolved context the
happenboard_mp_*triggers receive.
Return value
array<string,mixed>
The arguments handed to add_mailerpress_contact(). Return the array you were given, extended.
Example
add_filter(
'happenboard_pro_mailerpress_contact',
function ( array $payload, array $ctx ): array {
$payload['custom_fields']['hp_seats'] = (string) ( $ctx['quantity'] ?? 1 );
return $payload;
},
10,
2
);
Notes
- Two arguments are passed, so register with
10, 2. - It only runs on the sign-up path, and only when attendee sync is enabled in the HappenBoard Pro MailerPress settings. Cancellations, check-ins, reminders and post-event ticks never reach it.
- The result is cast with
(array)and passed straight toadd_mailerpress_contact(). Keep the existing keys,emailabove all: an empty address would create a useless contact. - Add to
custom_fields, do not replace it. Thehp_event_title,hp_event_date,hp_event_urlandhp_event_venueentries are the merge tags the HappenBoard triggers expose in the automation interface. subscription_statusfollows the operator’s opt-in setting and is eithersubscribedorpending. Forcingsubscribedoverrides a deliberate double opt-in choice.listsholds MailerPress list ids and is an empty array when no sync list is configured.
happenboard_notifications_{$template_id}
Rewrites an attendee email just before it is handed to wp_mail(), or cancels it. The hook name is built at runtime by appending the template id, so you hook the finished name, for example happenboard_notifications_confirmation.
Signature
apply_filters( "happenboard_notifications_{$template_id}", array<string,mixed> $payload, WP_Post $event, array<string,mixed> $attendee )
Parameters
-
$payloadarray<string,mixed> to,subject,body(HTML),text(plain-text alternative),headers(array of raw header lines) andattachments(absolute file paths).-
$eventWP_Post - The event the email is about.
-
$attendeearray<string,mixed> - The full attendee row, including
attendee_id,created_utc,quantityandcustom_fields.
Return value
array<string,mixed>
The email payload to send. Add 'send' => false to cancel the send entirely.
Example
add_filter(
'happenboard_notifications_confirmation',
function ( array $payload, $event = null, $attendee = array() ): array {
$payload['subject'] = '[' . get_bloginfo( 'name' ) . '] ' . $payload['subject'];
$payload['body'] .= '<p>' . esc_html__( 'See you there.', 'my-plugin' ) . '</p>';
// Return array( 'send' => false ) + $payload to cancel the send.
return $payload;
},
40,
3
);
Notes
- The name is assembled by concatenation, so only the templates the code actually dispatches produce a hook. The attendee notifier dispatches two:
happenboard_notifications_confirmationandhappenboard_notifications_reminder. The docblock in the source also listshappenboard_notifications_cancellation, but nothing dispatches acancellationtemplate, so that name never fires. - Three arguments are passed, so register with
10, 3at least. Give$eventand$attendeedefault values so the callback stays safe if it is ever reused elsewhere. - Returning a payload that contains
'send' => falsecancels the send. This is the way to hand a message over to your own transport without HappenBoard sending a duplicate. - HappenBoard Pro already filters
happenboard_notifications_confirmation: the check-in QR block at priority 20 and the PDF ticket attachment at priority 30. Append tobodyandattachmentsinstead of replacing them, and hook after 30 if you want to see the final content. - Any
Content-Type:header you add is stripped straight after the filter and replaced withtext/html. Appointment bookings use a separate family,happenboard_notifications_booking_{$template_id}insrc/Service/Booking/Notifications/BookingNotifier.php, with a different signature:array $payload, int $booking_id, array $row, and three dispatched ids (confirmation,cancellation,reminder).