Notification and email hooks

Available in:Free

These hooks change the emails HappenBoard sends: to attendees who sign up for an event, to customers who book an appointment, and to the host and the site admin about each booking. Use them to rewrite or cancel a message, choose its language, change when reminders go out or decide who hears about a booking.

For the settings side, see automatic emails and emails in the attendee’s language. New to hooks? Start with Extending HappenBoard with hooks.

Which emails HappenBoard sends

Each email has a template id. The id ends the name of the filter that can rewrite the message, and it is passed to happenboard_email_locale.

Sign-up emails go through happenboard_notifications_{$template_id}:

Template idSent when
confirmationSomeone signs up, or gets a place from the waitlist. Needs Send confirmation email on RSVP / ticket purchase.
reminderTheir date comes within the reminder lead time. Needs Send reminder email before each event.
cancellationTheir registration is cancelled: by them, by a refund or by an administrator.
date_changedTheir date moves: the event was edited, or an administrator moved them to another date.
date_cancelledTheir date is cancelled, or no longer part of the series.

Booking emails go through happenboard_notifications_booking_{$template_id}:

Template idSent toWhen
requestCustomerA booking that needs approval is received.
confirmationCustomerThe booking is confirmed: at once, on approval or once paid.
reminderCustomerBefore the appointment, 24 hours and 1 hour by default.
cancellationCustomerThe booking is cancelled.
declinedCustomerA request is declined.
payment_failedCustomerThe card held for a request could not be charged.
rescheduled, request_rescheduledCustomerA booking, or a request, moves to another time.
operator_request, operator_confirmed, operator_cancelled, operator_rescheduledHost and site adminA request is waiting, or a booking is confirmed, cancelled or moved. Needs Email the host and the site admin about bookings.

These settings are under HappenBoard → Settings → Email. See approving booking requests for the request flow.

How reminders go out

Sign-up reminders come from one WP-Cron event, happenboard_rsvp_reminder_sweep, which runs every 15 minutes. Each run finds the dates that now start within the lead time (Send reminder hours before start, 24 by default). It then fires happenboard_cron_reminder once for each attendee still going.

HappenBoard’s reminder email listens there, and so do HappenBoard Pro’s WhatsApp and MailerPress reminders. Before version 0.2.0, each sign-up scheduled its own cron event; the first sweep after the update takes those over.

Booking reminders work differently. Each confirmed booking schedules its own reminders, with Action Scheduler when it is installed and WP-Cron otherwise, at the hours set by happenboard_booking_reminder_offsets.

Which language an email uses

  • Sign-up emails: the language of the event translation the attendee signed up on (WPML or Polylang), else the site language.
  • Booking emails to the customer: the language of the page they booked on, else their profile language when they have an account, else the site language.
  • Booking emails to the host and the site admin: each person’s profile language. happenboard_email_locale does not run for these.

happenboard_email_locale can change the first two. HappenBoard Pro uses it to read a language field from the registration form.

MailerPress triggers (Pro)

The happenboard_mp_* actions exist only in HappenBoard Pro, and only fire when MailerPress is active and the MailerPress integration is turned on. HappenBoard sends nothing on them: they are the triggers you build automations on in MailerPress. See MailerPress automations.

happenboard_email_locale

Filter Free src/Service/Notifications/AttendeeNotifier.php

Filters the language an email is written in. HappenBoard switches to the returned locale while it builds the subject and the body, so one recipient can read French on an English site.

Signature

apply_filters( 'happenboard_email_locale', string $locale, string $template_id, WP_Post|null $event, array<string,mixed> $row )

Parameters

$locale string
The default. Sign-up emails: the locale of the event translation the attendee signed up on (WPML or Polylang), else the site locale. Booking emails: the locale of the page the booking was made on, else the customer’s profile locale when they have an account, else the site locale.
$template_id string
The email being sent. Sign-up emails: confirmation, reminder, cancellation, date_changed, date_cancelled. Booking emails: request, confirmation, reminder, cancellation, declined, payment_failed, rescheduled, request_rescheduled.
$event WP_Post|null
The event, for sign-up emails. Always null for booking emails.
$row array<string,mixed>
The attendee row for sign-up emails, the booking row without its cancel_token for booking emails. Both carry custom_fields, where a language field is stored.

Return value

string A WordPress locale such as fr_FR. Return $locale unchanged to keep the default.

Example

add_filter(
    'happenboard_email_locale',
    function ( $locale, $template_id, $event, $row ) {
        // Attendee rows have "email", booking rows "customer_email".
        $email = (string) ( $row['email'] ?? $row['customer_email'] ?? '' );

        return str_ends_with( $email, '.fr' ) ? 'fr_FR' : $locale;
    },
    20,
    4
);

Notes

  • Four arguments: register with 10, 4 or a later priority, or you never see the row. Fired from src/Service/Notifications/AttendeeNotifier.php and src/Service/Booking/Notifications/BookingNotifier.php.
  • Do not type-hint $event as WP_Post: it is null for booking emails.
  • The emails sent to the host and the site admin about a booking do not go through this filter. Each one is written in that person’s profile language.
  • HappenBoard Pro hooks it at priority 10 and returns the language stored in the attendee’s or customer’s language field (key language by default) when there is one. Switching only changes strings that have a translation installed on the site.

happenboard_notifications_{$template_id}

Filter Free src/Service/Notifications/AttendeeNotifier.php

Filters a sign-up email just before it is handed to wp_mail(), or cancels it. The name ends with the template id, so you hook the full 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

$payload array<string,mixed>
to, subject, body (HTML), text (plain-text version), headers (array of header lines) and attachments (file paths: the calendar file of the date on confirmation and date_changed).
$event WP_Post
The event the email is about.
$attendee array<string,mixed>
The attendee row, including attendee_id, status, occurrence_seq (their date in a series), quantity and custom_fields.

Return value

array<string,mixed> The email to send. Add 'send' => false to cancel it.

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 email.
        return $payload;
    },
    40,
    3
);

Notes

  • Five names fire: happenboard_notifications_confirmation (a sign-up, or a place from the waitlist), happenboard_notifications_reminder, happenboard_notifications_cancellation, happenboard_notifications_date_changed and happenboard_notifications_date_cancelled. The table at the top of this page says when each is sent.
  • Three arguments: register with 10, 3. A payload with 'send' => false cancels the send, for example when your own email service delivers the message.
  • HappenBoard Pro adds the check-in QR code at priority 20 and the PDF ticket at priority 30, on confirmation and date_changed. Append to body and attachments rather than replacing them, and hook after 30 to see the final content.
  • Keep each headers entry a string: one that is not can end in a PHP fatal error. Removing headers is safe. A Content-Type header is replaced with text/html. The calendar file is temporary and deleted right after sending.

happenboard_cron_reminder

Action Free src/Service/Notifications/ReminderSweep.php

Fires when an attendee’s reminder is due: once per attendee and date, when the date comes within the reminder lead time. HappenBoard’s reminder email goes out on it at priority 10, and HappenBoard Pro’s WhatsApp and MailerPress reminders follow.

Signature

do_action( 'happenboard_cron_reminder', int $attendee_id )

Parameters

$attendee_id int
The attendee to remind.

Example

add_action(
    'happenboard_cron_reminder',
    function ( int $attendee_id ): void {
        // A channel of your own, next to the email.
        my_send_sms_reminder( $attendee_id );
    },
    50
);

Notes

  • One argument. It comes from the reminder sweep, a WP-Cron event (happenboard_rsvp_reminder_sweep) that runs every 15 minutes. A reminder can therefore go out up to 15 minutes after the exact lead time, and later on a site whose WP-Cron only runs on visits.
  • It fires only while “Send reminder email before each event” is on, and only for an attendee still going to a published event that is not cancelled or postponed. It never fires twice for the same attendee and date, and someone who signs up after the reminder time gets no reminder.
  • Before HappenBoard 0.2.0, each sign-up scheduled its own one-off cron event on this hook. The first sweep after the update takes those over and removes them. Calling do_action() on it yourself sends the email only if the reminder is due now and has not gone out.
  • To stop the email but keep Pro’s WhatsApp and MailerPress reminders, cancel it on happenboard_notifications_reminder. Removing HappenBoard’s own callback stops those too: they only go out in the run that sends the email.

happenboard_booking_email_tokens

Filter Free src/Service/Booking/Notifications/BookingNotifier.php

Filters the values a booking email is filled with, subject line included. Use it to add a detail to every email about a booking, such as a room, a meeting link or a dress code.

Signature

apply_filters( 'happenboard_booking_email_tokens', array<string,string> $tokens, int $booking_id, array<string,mixed> $row )

Parameters

$tokens array<string,string>
Customer emails: display_name, event_title (the booking type) and start_local (date and time in the customer’s time zone, with the host’s name). Then event_url, cancel_url (the customer’s private link to cancel or move the booking), price, payment_line (what was paid and what is due) and persons (“2 × Adult, 1 × Child”). Emails to the host and the site admin replace cancel_url with customer_email, host_name and previous_local. Their time is in the site’s time zone, and event_url opens the Bookings screen.
$booking_id int
The booking ID.
$row array<string,mixed>
The booking row, without its cancel_token.

Return value

array<string,string> The values. The templates only print the keys listed above, so change values rather than adding keys.

Example

add_filter(
    'happenboard_booking_email_tokens',
    function ( $tokens, $booking_id, $row ) {
        // The meeting link saved on the booking type.
        $link = (string) get_post_meta( (int) $row['booking_type_id'], 'acme_meeting_link', true );
        if ( '' !== $link && '' !== $tokens['start_local'] ) {
            $tokens['start_local'] .= ' · ' . $link;
        }

        return $tokens;
    },
    10,
    3
);

Notes

  • Three arguments: register with 10, 3. It runs for every booking email, to the customer and to the team, in the recipient’s language, so strings you translate come out in it.
  • To change only the team’s emails, test isset( $tokens['customer_email'] ): customer emails do not have that key.
  • Pass cancel_url through untouched: it is the customer’s private link. Values are escaped when the email is built, so return plain text.
  • HappenBoard Pro adds the shared resource a booking holds (a room, a table) to start_local at priority 10.

happenboard_notifications_booking_{$template_id}

Filter Free src/Service/Booking/Notifications/BookingNotifier.php

Filters a booking email just before it is handed to wp_mail(), or cancels it. The name ends with the template id, for example happenboard_notifications_booking_confirmation.

Signature

apply_filters( "happenboard_notifications_booking_{$template_id}", array<string,mixed> $payload, int $booking_id, array<string,mixed> $row )

Parameters

$payload array<string,mixed>
to, subject, body (HTML), text (plain-text version), headers and attachments (file paths: the calendar invite on confirmation and rescheduled, the invite that removes the booking from the calendar on cancellation).
$booking_id int
The booking ID.
$row array<string,mixed>
The booking row, without its cancel_token.

Return value

array<string,mixed> The email to send. Add 'send' => false to cancel it.

Example

add_filter(
    'happenboard_notifications_booking_confirmation',
    function ( array $payload, int $booking_id, array $row ): array {
        // Copy the front desk on every booking confirmation.
        $payload['headers'][] = 'Bcc: [email protected]';

        return $payload;
    },
    10,
    3
);

Notes

  • Twelve template ids. To the customer: request, confirmation, reminder, cancellation, declined, payment_failed, rescheduled and request_rescheduled. To the host and the site admin: operator_request, operator_confirmed, operator_cancelled and operator_rescheduled.
  • Three arguments: register with 10, 3. A payload with 'send' => false cancels the send.
  • A team email fires once per recipient, with to set to that person and a Reply-To header set to the customer.
  • A Content-Type header is replaced with text/html, and headers or attachments that are not strings are dropped. Invites are temporary files, deleted after sending. Mail to an address erased under a privacy request is dropped before this filter.

happenboard_booking_operator_recipients

Filter Free src/Service/Booking/Notifications/BookingNotifier.php

Filters who is emailed on the team side of a booking: by default the booking’s host and the site admin address. Use it to add a front desk, leave out the admin or keep only some events.

Signature

apply_filters( 'happenboard_booking_operator_recipients', array<int,string> $recipients, string $event, int $booking_id, array<string,mixed> $row )

Parameters

$recipients array<int,string>
Email addresses: the host’s account email and the admin_email option, less the person making the change. Empty when “Email the host and the site admin about bookings” is off.
$event string
request (waiting for approval), confirmed, cancelled or rescheduled.
$booking_id int
The booking ID.
$row array<string,mixed>
The booking row, without its cancel_token.

Return value

array<int,string> The addresses to email. Invalid and duplicate addresses, and the customer’s own address, are removed afterwards. Return an empty array to send nothing.

Example

add_filter(
    'happenboard_booking_operator_recipients',
    function ( array $recipients, string $event, int $booking_id, array $row ): array {
        // The front desk hears about every request waiting for approval.
        if ( 'request' === $event ) {
            $recipients[] = '[email protected]';
        }

        return $recipients;
    },
    10,
    4
);

Notes

  • Four arguments: register with 10, 4. The setting is under HappenBoard → Settings → Email and is on by default.
  • The filter runs even when the setting is off, with an empty list, so a callback can still add addresses.
  • Nobody is emailed about a change they made: the logged-in user’s address is removed before the filter, but an address you add back is emailed. A declined request sends no team email.
  • Each recipient gets their own email, in their profile language when the address belongs to a user account, through happenboard_notifications_booking_operator_{$event}.

happenboard_booking_reminder_offsets

Filter Free src/Service/Booking/Notifications/BookingNotifier.php

Sets how many hours 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

$offsets array<int,int>
Hours before the start. Defaults to array( 24, 1 ).
$booking_id int
The booking ID.
$row array<string,mixed>
The booking row, without its cancel_token. An empty array when reminders are being cleared, see the notes.

Return value

array<int,int> Whole hours before the booking start. An empty array turns booking reminders off.

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: register with 10, 3. Zero, negative and duplicate values are dropped, and a reminder due less than a minute from now is skipped.
  • Reminders are scheduled with the confirmation: when the booking is made, approved or paid. A reschedule clears and schedules them again. They use Action Scheduler when it is installed, WP-Cron otherwise, and go out only while the booking is confirmed or awaiting payment.
  • Return the same list every time. Without Action Scheduler, the filter runs again with an empty $row when reminders are cleared (on cancellation and reschedule): a list built from $row would leave reminders behind.
  • The subject reads “Starting soon” for offsets under 12 hours. This filter only covers appointments: sign-up reminders follow “Send reminder hours before start” and fire happenboard_cron_reminder.

happenboard_mp_rsvp_created

Action Pro src/Service/Integrations/MailerPress/Bridge.php

The MailerPress trigger fired when someone signs up for an event. Use it to welcome the attendee, send practical details or start a sequence before the event.

Signature

do_action( 'happenboard_mp_rsvp_created', array<string,mixed> $ctx )

Parameters

$ctx array<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 {
        // Log each sign-up sent to MailerPress.
        error_log(
            sprintf(
                '%s registered for %s (%d seats).',
                (string) ( $ctx['email'] ?? '' ),
                (string) ( $ctx['event_title'] ?? '' ),
                (int) ( $ctx['quantity'] ?? 1 )
            )
        );
    }
);

Notes

  • One argument. It follows happenboard_rsvp_submitted at priority 20, after HappenBoard’s confirmation email at priority 10. A sign-up put on the waitlist fires nothing until it is moved to going, through happenboard_attendee_status_changed.
  • When attendee sync is on, the MailerPress contact is created or updated before the action fires, so it exists when MailerPress runs the trigger.
  • Paid orders fire the underlying action once per ticket line, so one Stripe checkout or WooCommerce order can fire several triggers for the same buyer.
  • event_date is the attendee’s date (their date in a series), as a readable string in the site’s date and time formats. first_name and last_name come from splitting the name at its first space.

happenboard_mp_rsvp_cancelled

Action Pro src/Service/Integrations/MailerPress/Bridge.php

The MailerPress 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

$ctx array<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 {
        // Tag the contact in your own system.
        my_plugin_tag_contact(
            (string) ( $ctx['email'] ?? '' ),
            'cancelled-' . (int) ( $ctx['event_id'] ?? 0 )
        );
    }
);

Notes

  • One argument. It follows happenboard_rsvp_cancelled at priority 20: the attendee’s cancel link, but also a Stripe refund or a reversed WooCommerce order, once per attendee row. Listen to happenboard_rsvp_cancelled directly if you need to tell them apart.
  • An administrator setting the status to cancelled in the attendee list does not fire this trigger.
  • No contact is created or updated here: only the sign-up trigger syncs contacts.
  • The context is read after the cancellation, so $ctx describes a row whose status is already cancelled.

happenboard_mp_checked_in

Action Pro src/Service/Integrations/MailerPress/Bridge.php

The MailerPress trigger fired when an attendee is checked in at the door.

Signature

do_action( 'happenboard_mp_checked_in', array<string,mixed> $ctx )

Parameters

$ctx array<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 {
        // Log each check-in sent to MailerPress.
        error_log(
            sprintf(
                '%s checked in at %s.',
                (string) ( $ctx['email'] ?? '' ),
                (string) ( $ctx['event_title'] ?? '' )
            )
        );
    }
);

Notes

  • One argument. It follows happenboard_pro_attendee_checked_in at priority 20, so it also fires when a ticket is scanned again.
  • The check-in row ID is not in $ctx. Hook happenboard_pro_attendee_checked_in if you need it.
  • It never fires with an empty context: an attendee row that cannot be read, or has no email, fires nothing.

happenboard_mp_reminder

Action Pro src/Service/Integrations/MailerPress/Bridge.php

The MailerPress trigger fired when an attendee’s reminder is due, 24 hours before their date by default. Use it for the “see you tomorrow” message.

Signature

do_action( 'happenboard_mp_reminder', array<string,mixed> $ctx )

Parameters

$ctx array<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 {
        // Log each reminder sent to MailerPress.
        error_log(
            sprintf(
                'Reminder due for %s (event %d).',
                (string) ( $ctx['email'] ?? '' ),
                (int) ( $ctx['event_id'] ?? 0 )
            )
        );
    }
);

Notes

  • One argument. It follows happenboard_cron_reminder at priority 20 and fires only in the run that sends HappenBoard’s own reminder, so once per attendee and date.
  • No reminder, no trigger. Nothing fires while “Send reminder email before each event” is off, for a sign-up made after the reminder time, or for an event cancelled, postponed or unpublished.
  • Timing follows the reminder sweep: within 15 minutes after the lead time set in “Send reminder hours before start”.
  • Cancelling the email on happenboard_notifications_reminder keeps this trigger.

happenboard_mp_post_event_tick

Action Pro src/Service/Integrations/MailerPress/PostEventCron.php

Fires once per attendee from the daily after-event scan. The MailerPress bridge turns it into happenboard_mp_post_event. Fire it yourself to send a follow-up to one attendee again.

Signature

do_action( 'happenboard_mp_post_event_tick', int $attendee_id, int $event_id )

Parameters

$attendee_id int
The attendee row ID.
$event_id int
The event whose date just ended.

Example

add_action(
    'happenboard_mp_post_event_tick',
    function ( int $attendee_id, int $event_id ): void {
        // Log each follow-up the scan finds.
        error_log(
            sprintf(
                'Follow-up due for attendee %d of event %d.',
                $attendee_id,
                $event_id
            )
        );
    },
    10,
    2
);

Notes

  • Two arguments: register with 10, 2. Unlike the other happenboard_mp_* hooks, it carries IDs, not the resolved context.
  • It comes from the daily WP-Cron job happenboard_pro_mp_post_event_scan, which does nothing while the MailerPress integration is off.
  • The scan takes the dates that ended between 26 hours and 1 hour ago, at most 500 per run and 1,000 attendees per event. Each date of a recurring event counts, and so does an event saved without an end. Only attendees still going produce a tick, and on a series only those of the date that ended.
  • Each date is recorded in the event’s _happenboard_mp_post_event_fired meta before its attendees are processed, so the scan never handles it twice. Calling do_action( 'happenboard_mp_post_event_tick', $attendee_id, $event_id ) yourself is the way to send a follow-up again.

happenboard_mp_post_event

Action Pro src/Service/Integrations/MailerPress/Bridge.php

The MailerPress trigger fired the day after an event’s date ends, once per attendee of that date 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

$ctx array<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 {
        // Queue a satisfaction survey.
        my_plugin_queue_survey(
            (string) ( $ctx['email'] ?? '' ),
            (int) ( $ctx['event_id'] ?? 0 )
        );
    }
);

Notes

  • One argument. It is the bridge’s version of happenboard_mp_post_event_tick, so the same rules apply: each date of a recurring event counts, for its own attendees, and only attendees still going are included.
  • Timing depends on WP-Cron: a site with too few visits to run its daily jobs can miss the 26-hour window.

happenboard_pro_mailerpress_contact

Filter Pro src/Service/Integrations/MailerPress/Bridge.php

Filters the MailerPress contact just before HappenBoard creates or updates it, so you can add custom fields, lists or your own opt-in source.

Signature

apply_filters( 'happenboard_pro_mailerpress_contact', array<string,mixed> $payload, array<string,mixed> $ctx )

Parameters

$payload array<string,mixed>
The arguments for add_mailerpress_contact(): email, firstName, lastName, subscription_status, lists, custom_fields and opt_in_source.
$ctx array<string,mixed>
The same resolved context the happenboard_mp_* triggers receive.

Return value

array<string,mixed> The arguments passed to add_mailerpress_contact(). Return the array you were given, extended.

Example

add_filter(
    'happenboard_pro_mailerpress_contact',
    function ( array $payload, array $ctx ): array {
        // Store the number of seats on the contact.
        $payload['custom_fields']['hp_seats'] = (string) ( $ctx['quantity'] ?? 1 );

        return $payload;
    },
    10,
    2
);

Notes

  • Two arguments: register with 10, 2.
  • It only runs on sign-up, and only when attendee sync is on in the MailerPress settings of HappenBoard Pro.
  • Keep the existing keys, email above all. Add to custom_fields rather than replacing it: hp_event_title, hp_event_date, hp_event_url and hp_event_venue are the merge tags the HappenBoard triggers offer in MailerPress.
  • subscription_status follows the opt-in setting (subscribed or pending). Forcing subscribed overrides a double opt-in choice.

Next steps