Appointment booking hooks

Appointment booking runs through two services. SlotGenerator computes the offered times, and BookingService re-validates the chosen one, picks a host and writes the row. Each exposes one filter, and the write path fires four lifecycle actions.

One rule applies to the whole page: the slot list is generated a second time inside the write path. Whatever happenboard_booking_slots removes can no longer be booked, and whatever it adds becomes bookable.

happenboard_booking_approved

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires when you approve a booking that was waiting for your answer on a booking type set to require approval. The built-in notifier listens here to send the confirmation email that was withheld at request time.

Signature

do_action( 'happenboard_booking_approved', int $booking_id )

Parameters

$booking_id int
Booking primary key.

Return value

void

Example

add_action(
    'happenboard_booking_approved',
    function ( $booking_id ) {
        acme_notify_ops( 'Booking approved', $booking_id );
    }
);

Notes

  • happenboard_booking_confirmed fires immediately after, so anything that only cares that a booking is now real should listen there instead and it will catch every path.
  • Approving twice is refused before this fires, so a listener never sees the same booking approved more than once.

happenboard_booking_assignment_strategy

Filter Free Since 1.0 src/Service/Booking/BookingService.php

Replaces the object that decides which host gets a booking. It runs inside BookingService::create(), after the requested slot has been re-validated and the candidate host list narrowed, and before the row is inserted.

Signature

apply_filters( 'happenboard_booking_assignment_strategy', \HappenBoard\Service\Booking\Assignment\Strategy $strategy, string $assignment )

Parameters

$strategy \HappenBoard\Service\Booking\Assignment\Strategy
The resolved default: LeastLoaded (fewest upcoming bookings) when the booking type is set to round_robin, Fixed (first candidate) for every other value.
$assignment string
The booking type’s configured mode, read from the _happenboard_bt_assignment meta: fixed, round_robin, collective, weighted or priority. Empty meta falls back to round_robin.

Return value

\HappenBoard\Service\Booking\Assignment\Strategy An object implementing HappenBoard\Service\Booking\Assignment\Strategy, whose pick() returns the chosen WP user ID or 0.

Example

add_filter(
    'happenboard_booking_assignment_strategy',
    function ( $strategy, $assignment ) {
        if ( 'round_robin' !== $assignment ) {
            return $strategy;
        }

        // Always give the booking to host 12 when they are free at the
        // slot; otherwise defer to HappenBoard's least-loaded strategy.
        return new class( $strategy ) implements \HappenBoard\Service\Booking\Assignment\Strategy {

            private $fallback;

            public function __construct( $fallback ) {
                $this->fallback = $fallback;
            }

            public function pick( array $candidate_host_ids, int $booking_type_id, string $slot_utc ): int {
                $senior = 12;
                if ( in_array( $senior, array_map( 'intval', $candidate_host_ids ), true ) ) {
                    return $senior;
                }
                return $this->fallback->pick( $candidate_host_ids, $booking_type_id, $slot_utc );
            }
        };
    },
    10,
    2
);

Notes

  • Two arguments are passed: register with add_filter( ..., 10, 2 ) or you never see $assignment.
  • The calling method declares a return type of Strategy. Returning an array, a closure or null throws a TypeError and the booking submission fails with a 500.
  • Nothing re-checks the user ID your pick() returns. Returning 0 makes create() answer happenboard_booking_no_host (HTTP 409); returning an ID that is not in $candidate_host_ids writes it to host_user_id unchecked, which is how you create a double booking.
  • The free plugin maps only round_robin to LeastLoaded. collective, weighted and priority all fall through to Fixed. The docblock says Pro supplies those three strategies, but no code in HappenBoard Pro registers a callback on this filter, so today they behave exactly like fixed.
  • It only runs on creation. BookingService::reschedule() never calls the strategy resolver, so moving a booking keeps its original host even when that host is not free at the new time.

happenboard_booking_awaiting_payment

Filter Free Since 1.0 src/Service/Booking/BookingService.php

Decides whether a booking must be paid online before it counts. Free always answers no, because it has no payment rail: a price on a booking type is a statement of what the visitor will owe on the day. HappenBoard Pro answers yes when its Stripe path is configured for that booking type.

Signature

apply_filters( 'happenboard_booking_awaiting_payment', bool $awaiting, int $booking_type_id, array $config )

Parameters

$awaiting bool
false by default.
$booking_type_id int
The booking type being booked.
$config array<string,mixed>
Resolved booking-type config, including price_cents, requires_approval and the scheduling rules.

Return value

bool True to write the booking as pending_payment, which holds the slot while the customer pays.

Example

add_filter(
    'happenboard_booking_awaiting_payment',
    function ( $awaiting, $booking_type_id, $config ) {
        // Only ask for payment above a threshold.
        return $config['price_cents'] >= 5000;
    },
    10,
    3
);

Notes

  • Three arguments: register with add_filter( ..., 10, 3 ).
  • It is never consulted for a booking an operator entered from the admin, nor on a booking type that requires approval. Charging for a slot you might then decline is a refund waiting to happen, so those two flows stay mutually exclusive.
  • Returning true without also supplying a URL through happenboard_booking_payment_url leaves the customer holding a slot they cannot pay for.

happenboard_booking_cancelled

Action Free Since 1.0 src/REST/Bookings.php

Fires once a booking row’s status has been switched to cancelled in the database. Both the public cancellation link and the admin cancel action reach it.

Signature

do_action( 'happenboard_booking_cancelled', int $booking_id )

Parameters

$booking_id int
Primary key of the cancelled booking in the happenboard_bookings table.

Example

add_action(
    'happenboard_booking_cancelled',
    function ( $booking_id ) {
        $repository = new \HappenBoard\Service\Booking\BookingRepository();
        $booking    = $repository->find_by_id( (int) $booking_id );
        if ( null === $booking ) {
            return;
        }

        error_log( sprintf(
            'Booking %d cancelled (host %d, start %s)',
            (int) $booking['booking_id'],
            (int) $booking['host_user_id'],
            (string) $booking['start_utc']
        ) );
    }
);

Notes

  • There is no docblock on either call, so the auto-extracted signature shows no arguments. That is wrong: one argument is passed.
  • Two call sites, same single argument. BookingService::cancel_by_token() serves DELETE /happenboard/v1/bookings/{token}, and REST\Bookings::admin_update() serves PATCH /happenboard/v1/bookings/{id} with status=cancelled. Handle both.
  • Only the ID is passed. If you need the customer, host or start time, read the row yourself with BookingRepository::find_by_id(); it is already saved with the new status.
  • The action fires only after the repository reports the UPDATE succeeded, so a failed cancellation (HTTP 500) never reaches your callback.
  • The free plugin listens at priority 10 (BookingNotifier::on_cancelled): it sends the cancellation email and clears the booking’s pending reminders. A callback at a lower priority that throws will prevent both.

happenboard_booking_client_ip

Filter Free Since 1.0 src/REST/Bookings.php

Overrides the client IP the public booking submission works from. It runs once per POST /happenboard/v1/bookings, right after the nonce check and before any throttling. Use it when the site sits behind a reverse proxy or CDN.

Signature

apply_filters( 'happenboard_booking_client_ip', string $ip )

Parameters

$ip string
REMOTE_ADDR after sanitize_text_field() and filter_var( ..., FILTER_VALIDATE_IP ), or '' when it is absent or not a valid IP.

Return value

string An IP address as a string. The caller casts the result with (string) and does not validate it further.

Example

add_filter(
    'happenboard_booking_client_ip',
    function ( $ip ) {
        // Only do this when every request really is proxied by Cloudflare.
        if ( empty( $_SERVER['HTTP_CF_CONNECTING_IP'] ) ) {
            return $ip;
        }

        $forwarded = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CF_CONNECTING_IP'] ) );

        return filter_var( $forwarded, FILTER_VALIDATE_IP ) ? $forwarded : $ip;
    }
);

Notes

  • The docblock calls it the IP used by the rate limiter, but the returned value feeds three consumers: the per-IP throttle (8 submissions per minute, keyed on md5( $ip )), the Cloudflare Turnstile verification call, and the user_ip field sent to Akismet.
  • Returning '' switches the per-IP throttle off completely: that whole block is wrapped in if ( '' !== $ip ). The per-email throttle (5 per hour) still applies.
  • Validate anything you read from a proxy header before returning it. The plugin only casts to string, and the value then goes into a transient key and out to two third-party services.
  • Only the booking submission uses it. GET /happenboard/v1/booking-types/{id}/slots reads REMOTE_ADDR directly in src/REST/BookingSlots.php and is not filterable. RSVP submissions have their own happenboard_rsvp_client_ip.

happenboard_booking_confirmed

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires on the line right after happenboard_booking_created, inside BookingService::create(). There is no separate confirmation step in the free plugin, so in practice it fires on every successful booking creation.

Signature

do_action( 'happenboard_booking_confirmed', int $booking_id )

Parameters

$booking_id int
Primary key returned by the insert.

Example

add_action(
    'happenboard_booking_confirmed',
    function ( $booking_id ) {
        $booking = ( new \HappenBoard\Service\Booking\BookingRepository() )
            ->find_by_id( (int) $booking_id );
        if ( null === $booking ) {
            return;
        }

        update_user_meta(
            (int) $booking['host_user_id'],
            'my_last_confirmed_booking',
            (int) $booking_id
        );
    }
);

Notes

  • There is no docblock, so the auto-extracted signature lists no arguments. One argument is passed.
  • Unlike happenboard_booking_created it carries only the ID, not the saved row. Read the row with BookingRepository::find_by_id() if you need it.
  • Nothing in HappenBoard or HappenBoard Pro listens on it. It exists purely as an extension seam, which also means no other callback is competing with you on priority.
  • Do not read it as “payment received”. Rows are always inserted with status confirmed, and a priced booking type gets payment_status = on_site in the free create path, never pending_payment.
  • If you only need one hook, prefer happenboard_booking_created: it fires first, on the same code path, and hands you the row.

happenboard_booking_created

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires after the booking row has been inserted and read back, at the end of BookingService::create(). This is the seam to use for CRM sync, provisioning a meeting link, or anything that needs the full saved booking.

Signature

do_action( 'happenboard_booking_created', int $booking_id, array<string,mixed> $data )

Parameters

$booking_id int
Primary key of the inserted row.
$data array<string,mixed>
The persisted row, re-read with SELECT *: booking_id, booking_type_id, host_user_id, customer_user_id, customer_email, customer_name, customer_tz, start_utc, end_utc, status, quantity, payment_status, order_id, custom_fields (JSON string), rescheduled_from, cancel_token, created_utc, updated_utc.

Example

add_action(
    'happenboard_booking_created',
    function ( $booking_id, $data ) {
        // $data is the raw DB row: it contains cancel_token. Never forward
        // the whole row to a third party.
        $payload = array(
            'id'       => (int) $booking_id,
            'start'    => (string) ( $data['start_utc'] ?? '' ),
            'host'     => (int) ( $data['host_user_id'] ?? 0 ),
            'quantity' => (int) ( $data['quantity'] ?? 1 ),
        );

        wp_remote_post(
            'https://example.com/crm/bookings',
            array(
                'timeout' => 5,
                'body'    => wp_json_encode( $payload ),
                'headers' => array( 'Content-Type' => 'application/json' ),
            )
        );
    },
    10,
    2
);

Notes

  • Two arguments: register with add_action( ..., 10, 2 ).
  • $data contains cancel_token, the 64-character secret that lets anyone cancel or reschedule the booking through the public REST routes. The submit response deliberately never returns it. Do not log the row, mail it, or forward it to a third party.
  • The row comes from $wpdb->get_row( ..., ARRAY_A ), so every column arrives as a string, including booking_id and quantity. Cast before comparing, and note that custom_fields is still JSON-encoded.
  • $data is (array) $saved. If the read-back fails, $saved is null and you receive an empty array, not a row with empty values. Guard on the keys you use.
  • The free plugin listens at priority 10 (BookingNotifier::on_created): confirmation email with an .ics attachment, then reminder scheduling. The docblock says Pro listens here for payment, calendar write and SMS/WhatsApp, but no code in HappenBoard Pro registers a callback on this hook.

happenboard_booking_declined

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires when you decline a booking request. A decline is a cancellation with a different cause, so the slot is freed and the customer gets the cancellation email they would expect.

Signature

do_action( 'happenboard_booking_declined', int $booking_id )

Parameters

$booking_id int
Booking primary key.

Return value

void

Example

add_action(
    'happenboard_booking_declined',
    fn ( $booking_id ) => acme_log( 'declined', $booking_id )
);

Notes

  • happenboard_booking_cancelled fires immediately after, which is what sends the cancellation email.

happenboard_booking_location_labels

Filter Free Since 1.0 src/Block/BookingPage/Block.php

Filters the visitor-facing label for each booking-type location mode. Use it to name the custom mode, which has no default label, or to relabel the built-in three.

Signature

apply_filters( 'happenboard_booking_location_labels', array $labels )

Parameters

$labels array<string,string>
Slug to label. Defaults: in_person to “In person”, virtual to “Online”, phone to “By phone”.

Return value

array<string,string> The labels to print. A mode with no entry prints nothing.

Example

add_filter(
    'happenboard_booking_location_labels',
    function ( $labels ) {
        $labels['custom'] = 'At your premises';

        return $labels;
    }
);

Notes

  • Applies to both the Booking Page and the Booking Availability block, so one filter covers every surface that names a location mode.

happenboard_booking_paid

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires when the payment for a held booking lands and the booking is confirmed. The payment counterpart of approving a request.

Signature

do_action( 'happenboard_booking_paid', int $booking_id )

Parameters

$booking_id int
Booking primary key.

Return value

void

Example

add_action(
    'happenboard_booking_paid',
    fn ( $booking_id ) => acme_issue_receipt( $booking_id )
);

Notes

  • happenboard_booking_confirmed fires immediately after, on purpose: an extension that already subscribes to “this booking is now real” should not have to learn a second name because the money arrived by card.
  • Payment providers deliver webhooks at least once and retry, so a booking that is already confirmed is treated as a success with nothing left to do. This action does not fire twice for one appointment.

happenboard_booking_payment_abandoned

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires when a booking whose payment never arrived is released and its slot goes back on offer.

Signature

do_action( 'happenboard_booking_payment_abandoned', int $booking_id )

Parameters

$booking_id int
Booking primary key.

Return value

void

Example

add_action(
    'happenboard_booking_payment_abandoned',
    fn ( $booking_id ) => acme_metrics( 'checkout_abandoned', $booking_id )
);

Notes

  • Abandoning a checkout is not a cancellation the customer should hear about, since they never had a booking. happenboard_booking_cancelled deliberately does not fire, so no cancellation email goes out.

happenboard_booking_payment_hold_hours

Filter Free Since 1.0 src/Service/Booking/PaymentHoldSweeper.php

Filters how long an unpaid booking may hold its slot before the sweeper releases it. This is the backstop for a payment webhook that never arrives: a dropped delivery would otherwise leave an appointment slot off the calendar for good.

Signature

apply_filters( 'happenboard_booking_payment_hold_hours', int $hours )

Parameters

$hours int
Hold window in hours. Defaults to 24.

Return value

int Hours to hold. Floored at 1.

Example

add_filter( 'happenboard_booking_payment_hold_hours', fn () => 6 );

Notes

  • Lower it only in step with your payment provider’s checkout session lifetime. A window shorter than the session lets a customer pay for a slot that has already been given away.

happenboard_booking_payment_pending

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires when a booking is holding its slot while the customer pays. The slot is blocked from that moment, so the time is still theirs when they come back from checkout.

Signature

do_action( 'happenboard_booking_payment_pending', int $booking_id )

Parameters

$booking_id int
Booking primary key.

Return value

void

Example

add_action(
    'happenboard_booking_payment_pending',
    fn ( $booking_id ) => acme_metrics( 'checkout_started', $booking_id )
);

Notes

  • Named _payment_pending, not _awaiting_payment, which is the filter above. WordPress keeps actions and filters in one namespace, so the two cannot share a name.

happenboard_booking_payment_url

Filter Free Since 1.0 src/Service/Booking/BookingService.php

Filters the address a customer must be sent to in order to pay for a booking held pending payment. HappenBoard Pro returns a Stripe hosted-checkout URL.

Signature

apply_filters( 'happenboard_booking_payment_url', string $url, int $booking_id, array $booking )

Parameters

$url string
Empty by default.
$booking_id int
Booking primary key.
$booking array<string,mixed>
The persisted row, redacted.

Return value

string An absolute URL, or an empty string.

Example

add_filter(
    'happenboard_booking_payment_url',
    fn ( $url, $booking_id ) => $url ?: acme_checkout_link( $booking_id ),
    10,
    2
);

Notes

  • Only consulted when happenboard_booking_awaiting_payment returned true.
  • An empty return means whatever said the booking needs paying cannot actually take the payment, so treat it as a misconfiguration rather than a silent no-op.

happenboard_booking_requested

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires when a booking arrives as a request awaiting your approval, rather than as a confirmation. Use it to alert whoever has to answer.

Signature

do_action( 'happenboard_booking_requested', int $booking_id )

Parameters

$booking_id int
Booking primary key.

Return value

void

Example

add_action(
    'happenboard_booking_requested',
    function ( $booking_id ) {
        wp_mail( get_option( 'admin_email' ), 'New booking request', 'Booking #' . $booking_id . ' is waiting.' );
    }
);

Notes

  • happenboard_booking_confirmed deliberately does not fire for a request: a booking still waiting on your answer is not confirmed, and listeners on that seam must not act as though it were.
  • happenboard_booking_created fires first, for every booking whatever its status.

happenboard_booking_rescheduled

Action Free Since 1.0 src/Service/Booking/BookingService.php

Fires after a booking’s start and end have been moved, at the end of BookingService::reschedule(). The new time has already passed the same live-slot check a fresh booking goes through.

Signature

do_action( 'happenboard_booking_rescheduled', int $booking_id, string $old_start, string $new_start )

Parameters

$booking_id int
Primary key of the moved booking.
$old_start string
The previous start_utc, read from the row before the update. UTC Y-m-d H:i:s, or '' when the column was empty.
$new_start string
The new start, normalized to UTC Y-m-d H:i:s. The end time is derived from the booking type’s duration and is not passed.

Example

add_action(
    'happenboard_booking_rescheduled',
    function ( $booking_id, $old_start, $new_start ) {
        // Both timestamps are UTC 'Y-m-d H:i:s'.
        $old = new DateTimeImmutable( $old_start, new DateTimeZone( 'UTC' ) );
        $new = new DateTimeImmutable( $new_start, new DateTimeZone( 'UTC' ) );

        error_log( sprintf(
            'Booking %d moved from %s to %s (site time)',
            (int) $booking_id,
            $old->setTimezone( wp_timezone() )->format( 'Y-m-d H:i' ),
            $new->setTimezone( wp_timezone() )->format( 'Y-m-d H:i' )
        ) );
    },
    10,
    3
);

Notes

  • Three arguments: register with add_action( ..., 10, 3 ). There is no docblock, so the auto-extracted signature lists none at all.
  • Both timestamps are bare UTC Y-m-d H:i:s strings with no offset suffix. The customer’s own timezone stays in the row’s customer_tz column.
  • The host is not reassigned. reschedule() never calls the assignment strategy, so host_user_id keeps its original value even if that host is not among the hosts free at the new time.
  • The reschedule path checks that the new slot is offered but, unlike creation, never compares capacity_left against the booking’s quantity. A group booking can be moved onto a slot with fewer seats left than it needs.
  • Reachable only from PATCH /happenboard/v1/bookings/{token}/reschedule. The admin route PATCH /happenboard/v1/bookings/{id} supports cancellation only, so an admin-side move does not exist yet and cannot fire this.

happenboard_booking_slots

Filter Free Since 1.0 src/Service/Booking/Availability/SlotGenerator.php

The last step of the availability engine, after weekly windows, days off, notice and advance limits, buffers and capacity have all been applied. Every offered time for a booking type passes through here, so this is the single place to add or remove bookable slots.

Signature

apply_filters( 'happenboard_booking_slots', array<int,array<string,mixed>> $list, int $booking_type_id, string $from, string $to )

Parameters

$list array<int,array<string,mixed>>
Zero-indexed and sorted by UTC start. Each row has start_utc and end_utc (UTC Y-m-d H:i:s), start (ISO 8601 in the requester’s timezone), label (display string), hosts (WP user IDs free at that time) and capacity_left (seats remaining).
$booking_type_id int
The hboard_booking_type post ID the slots belong to.
$from string
The window start exactly as it reached the generator, before parsing and clamping. From the REST route it is the raw querystring value and can be ''.
$to string
The window end, same handling as $from.

Return value

array<int,array<string,mixed>> A zero-indexed list of slot arrays. The result is cast with (array) and returned as-is to the caller.

Example

add_filter(
    'happenboard_booking_slots',
    function ( $slots, $booking_type_id, $from, $to ) {
        if ( 42 !== $booking_type_id ) {
            return $slots;
        }

        // Remove: nothing on Friday afternoon, site timezone.
        $slots = array_filter(
            $slots,
            function ( $slot ) {
                $local = ( new DateTimeImmutable( $slot['start_utc'], new DateTimeZone( 'UTC' ) ) )
                    ->setTimezone( wp_timezone() );

                return ! ( 'Fri' === $local->format( 'D' ) && (int) $local->format( 'G' ) >= 12 );
            }
        );

        // Add: an extra 09:00 UTC slot tomorrow, hosted by user 7.
        $start = new DateTimeImmutable( 'tomorrow 09:00', new DateTimeZone( 'UTC' ) );

        $slots[] = array(
            'start_utc'     => $start->format( 'Y-m-d H:i:s' ),
            'end_utc'       => $start->modify( '+30 minutes' )->format( 'Y-m-d H:i:s' ),
            'start'         => $start->format( 'c' ),
            'label'         => $start->format( 'D, M j H:i' ),
            'hosts'         => array( 7 ),
            'capacity_left' => 1,
        );

        // Always hand back a zero-indexed list.
        return array_values( $slots );
    },
    10,
    4
);

Notes

  • Four arguments: register with add_filter( ..., 10, 4 ).
  • This filter also gates writes. BookingService::create() and ::reschedule() call the generator again at submit time and reject any start that is not in the returned list, so removing a slot really blocks the booking. A slot you invent becomes bookable, provided it carries start_utc in exactly the UTC Y-m-d H:i:s format, a hosts array of real WP user IDs and a capacity_left at least equal to the requested quantity. Otherwise the submission fails with happenboard_booking_slot_unavailable or happenboard_booking_no_host (HTTP 409).
  • Return a list, not a map. The array is serialized straight into the slots key of GET /happenboard/v1/booking-types/{id}/slots; a non-sequential array becomes a JSON object and breaks the front end. Finish with array_values(), as the Pro callback does.
  • The arguments differ on the write path: find_live_slot() calls the generator as for_type( $id, $day, $day, 'UTC' ), so $from and $to are the same Y-m-d day and the display fields are built in UTC rather than the customer’s timezone. Derive your logic from start_utc, not from $from and $to. Note also that the generator stops collecting at 750 slots before the filter runs, so a wide window can hand you a truncated list.
  • HappenBoard Pro already registers a callback at priority 10 with 4 arguments (Service\Resources\ConflictResolver::filter_slots), which drops slots whose shared resources are fully committed. Use a priority above 10 if you need the final set. The generator’s own docblock also claims Pro subtracts external calendar busy times here; only the shared-resource callback exists in HappenBoard Pro.

happenboard_currency

Filter Free Since 1.0 src/Service/Money.php

Filters the site display currency, as an uppercase ISO 4217 code. This is the single override point for every amount HappenBoard prints, which in the free plugin means the price on a booking type.

Signature

apply_filters( 'happenboard_currency', string $code )

Parameters

$code string
The code saved under Settings → General. USD by default.

Return value

string A three-letter code. It is normalised, so a lowercase or padded value is accepted.

Example

add_filter( 'happenboard_currency', fn () => 'EUR' );

Notes

  • It changes how amounts are written, not what they are worth. Nothing is converted, so switching currency relabels existing prices.
  • Read every amount through this rather than the raw setting, or your integration and the rest of the plugin will disagree.

happenboard_slot_cache_ttl

Filter Free Since 1.0 src/Service/Booking/Availability/SlotCache.php

Filters how long a computed set of bookable slots is reused before it is worked out again.

Signature

apply_filters( 'happenboard_slot_cache_ttl', int $ttl )

Parameters

$ttl int
Lifetime in seconds. Defaults to 5 minutes.

Return value

int Seconds to cache. Return 0 to disable slot caching entirely.

Example

// A shared-room calendar that changes constantly.
add_filter( 'happenboard_slot_cache_ttl', fn () => 60 );

Notes

  • The cache is only a display accelerator. The chosen slot is re-validated inside the write path, so a stale cache can offer a time that is then refused, never double-book one.
  • Returning 0 makes every booking page recompute availability on each load, which is correct but noticeably more work on a busy calendar.