Skip to content
Gaurav TiwariDocs

Hooks and Filters

Updated October 22, 2026

You want Core Bookings to price by time of day, block slots from another calendar, push bookings into your CRM or add a column to the export, without editing the plugin. Every one of those is a hook. The built-in modules use the same hooks you do, so anything a module can do, your own plugin can do too.

All hooks use the core_bookings/ prefix. Amounts are integers in minor currency units (2500 is 25.00), and times are Unix seconds unless a row says otherwise.

Before You Start

  • Rejecting a request. Validation hooks reject by throwing Gatilab\CoreBookings\Problem: throw new Problem('slot_taken', __('That time is taken.'), 409);. The slug becomes the cb_<slug> error code customers and the REST API see. The status defaults to 422.
  • Module hooks. Some hooks below fire only while their module is switched on. Those rows name the module.
  • Transactions. Hooks that run inside the reservation or import transaction roll the whole request back when they throw. Never call a slow external API from them.
  • Events are at least once. Lifecycle actions can repeat after a retry. Deduplicate with event_id.

Booking Engine and Availability

HookTypeArgumentsUse
core_bookings/request_servicefilterarray $service, array $inputApply customer choices ($input['choices']), such as a longer duration. Keep id. Used for availability, quotes, reservations and waitlist joins; rescheduling keeps the purchased snapshot.
core_bookings/staff_servicefilterarray $service, int $staffIdThe service as one host delivers it (per-staff length). Never applied to rescheduling.
core_bookings/validate_requestactionarray $service, array $input, string $intentThrow a Problem to reject. $intent is booking, offer or admin. A slug of answer_<key> marks a question field.
core_bookings/request_fingerprintfilterarray $key, array $input, array $serviceAdd your own input that must match when a request key is retried.
core_bookings/pricefilterarray $price, array $service, array $input, array $context$price is ['total','due','lines']; lines are ['label','amount']. $context has seats, index, count, start and staff.
core_bookings/candidatesfilterint[] $starts, array $service, array $staff, string $dateRemove start times for one staff date (opening hours). It can only remove.
core_bookings/slotsfilterarray $result, array $service, array $staff, int $from, int $until, array $contextReorder or remove offered starts. $context has ignore, seats and any.
core_bookings/remainingfilterint $left, array $service, array $staff, int $start, string $ignoreLower the places left at a start (shared resources). It can never raise the count.
core_bookings/staff_orderfilterint[] $ids, array $service, array $inputOrder the staff tried for “any available” bookings.
core_bookings/series_startsfilterint[] $starts, array $service, array $input, array $staffGroup services: every start of a fixed series (a course), reserved together. At most 52, including the requested start.
core_bookings/reservedactionarray $row, array $service, array $input, int $index, Store $storeInside the reservation transaction after each row is saved. Throwing rolls back the request.
core_bookings/validate_rescheduleactionarray $service, array $booking, int $start, bool $operatorBefore a reschedule, outside the transaction. Throw to refuse.
core_bookings/rescheduledactionarray $new, array $old, Store $storeInside the reschedule transaction.
core_bookings/validate_confirmationactionarray $service, array $booking, string $contextBefore a held booking is confirmed later (approval, claim, payment or review). Throw slot_taken to refuse.
core_bookings/booking_hostsfilterint[] $ids, array $bookingStaff who co-host a booking and may open and change it.

Payments and Checkout

HookTypeArgumentsUse
core_bookings/payment_gatewaysfilterGateway[] $gatewaysRegister a hosted checkout provider for service payments. PayPal, Polar and Paddle use it.
core_bookings/booking_creditfilterint $credit, array $bookingAmount already settled outside money payments (a gift card). Lowers the balance due.
core_bookings/cancellation_retainedfilterint $retained, array $booking, int $credit, Store $storeThe part of a credit kept when a cancelled booking returns it (Promotions).
core_bookings/refund_suggestionfilterint $amount, array $booking, Store $storeAmount prefilled in the appointment panel’s refund form.
core_bookings/balance_tip_limitfilterint $limit, array $bookingLargest tip allowed on a Stripe balance payment. 0 turns tips off.
core_bookings/stripe_event_typesfilterstring[] $typesExtra Stripe event types the verified webhook stores.
core_bookings/stripe_eventfilterfalse, array $event, Payments $paymentsHandle a stored, signature-verified Stripe event. Return true once handled; throw to retry.
core_bookings/fluentcart_cartfiltermixed $record, string $kind, string $refDescribe a module’s one-item FluentCart cart.
core_bookings/fluentcart_linkedactionstring $kind, string $ref, object $orderThe checkout created an order for a module cart.
core_bookings/fluentcart_orderactionint $order, int $versionA FluentCart order was paid, refunded or changed.
core_bookings/fluentcart_subscriptionfilterarray $record, object $subscriptionCorrect a normalized FluentCart subscription (Memberships).
core_bookings/fluentcart_order_urlfilterstring $url, array $bookingThe customer’s FluentCart order page (Taxes).

A gateway extends Gatilab\CoreBookings\Gateway and implements id(), label(), ready(), offered(), currencies(), hosts(), start(), state(), webhook(), history() and refund(). IDs are 2 to 32 lower-case letters, digits or underscores, starting with a letter; free, offline, stripe, stripe_embedded and fluentcart are reserved. Its webhook address is /wp-json/core-bookings/v1/webhooks/<id>. Register the filter even while your settings are off, so payments already started still settle.

add_filter('core_bookings/payment_gateways', function (array $gateways): array {
    $gateways[] = new My_Gateway(); // extends \Gatilab\CoreBookings\Gateway
    return $gateways;
});

Lifecycle Events

These fire from the background worker after the change is committed. Tokens, provider keys and private manage links are never included.

HookTypeArgumentsUse
core_bookings/lifecycleactionarray $eventEvery booking event: event_id, event, booking (snapshot), occurred_at.
core_bookings/booking_<event>actionarray $eventOne booking event, such as booking_created, booking_confirmed, booking_cancel, booking_reschedule, booking_paid or booking_refunded.
core_bookings/<subject>_<event>actionarray $eventOther subjects: customer_created, pack_activated, waitlist_offered and so on. The payload sits under the subject key.
core_bookings/eventactionarray $eventEvery event for every subject: event_id, event, subject_type, subject_id, booking_id, payload, occurred_at.
core_bookings/booking_erasedactionstring $id, Store $storeA booking was anonymized. Remove your copy of its personal data.
core_bookings/checked_inactionarray $booking, array $state, Store $storeA check-in was saved or undone (Classes, Staff portal).
core_bookings/webhook_eventsfilterarray $typesList your module’s events on the Webhooks screen.
core_bookings/webhook_bookingfilterarray $data, array $booking, Store $storeAdd fields to the booking object of webhook payloads. Core fields always win.
add_action('core_bookings/booking_confirmed', function (array $event): void {
    if (get_transient('my_crm_' . $event['event_id'])) { return; } // already sent
    my_crm_push($event['booking']['email'], $event['booking']['start_at']);
    set_transient('my_crm_' . $event['event_id'], 1, DAY_IN_SECONDS);
});

Throwing an exception retries the event a limited number of times. For HTTP delivery without code, use outgoing webhooks.

Services, Staff, Customers and the Workspace

HookTypeArgumentsUse
core_bookings/service_configfilterarray $config, array $inputValidate and add your keys to a saved service. Throw to reject. Prefix your keys.
core_bookings/service_editoractionarray $servicePrint fields inside the service form.
core_bookings/service_savedactionint $id, array $service, array $oldAfter a service is saved (editor, block editor, WP-CLI). Imports don’t fire it.
core_bookings/staff_editoractionint $userId, array $rowPrint fields inside the staff form.
core_bookings/staff_savedactionint $userId, array $inputAfter a staff profile, time block or portal hours edit is saved.
core_bookings/staff_scopefilterstring $sql, int $userId, Store $storeThe bookings a staff member works on (prepared SQL, table alias b).
core_bookings/customer_meta_fieldsfilterarray $fieldsRegister customer fields: key => ['schema', 'customer_read', 'customer_write', 'internal']. Only registered fields can be saved.
core_bookings/customer_profileactionarray $customer, Store $storePrint sections on a customer’s admin profile.
core_bookings/customer_mergeactionarray $from, array $to, Store $storeInside the duplicate-merge transaction. Move your rows keyed by the old customer.
core_bookings/customer_bookingfilterarray $payload, array $booking, Store $storeAdd details and links rows to the customer’s booking page and dashboard.
core_bookings/customer_dashboardfilterarray $sections, string $email, Store $storeAdd sections to the customer dashboard.
core_bookings/appointment_panelfilterstring $html, array $booking, Store $storeEscaped HTML sections for the appointment panel.
core_bookings/admin_viewsfilterarray $viewsAdd a workspace screen: id => ['label', 'description', 'capability', 'render', 'parent'].
core_bookings/export_columnsfilterarray $columnskey => label columns added to the appointments CSV.
core_bookings/export_rowfilterarray $values, array $booking, Store $storekey => value for those columns, one booking at a time.
core_bookings/email_placeholdersfilterarray $placeholdersname => label placeholders listed under Emails.
core_bookings/email_valuesfilterarray $values, array $booking, array $service, Store $storeFill those placeholders.
core_bookings/deliver_emailfiltermixed $handled, array $messageSend Core Bookings email through your own provider. Return true once your provider accepts it, null to use the configured delivery, or throw to retry. Deduplicate by $message['event_id'].
core_bookings/staff_recipientsfilterarray $to, array $booking, int $actoremail => name recipients of a staff booking email.
core_bookings/jobfilterfalse, array $job, Store $storeHandle your own background job kind. Return true when done. Name kinds with core_bookings/job_labels and list ones without a booking in core_bookings/independent_jobs.
core_bookings/dismissible_jobsfilterstring[] $kindsJob kinds a manager may dismiss in Operations after a failure.
core_bookings/transfer_exportfilterarray $data, bool $withBookings, Store $storeAdd your portable records to a JSON export.
core_bookings/transfer_importedactionarray $data, array $serviceIds, array $bookingIds, Store $store, array $staffInside the import transaction. Map your records to this site.
core_bookings/module_enabledactionstring $idA module was switched on.

Calendars, Meetings and Integrations

HookTypeArgumentsUse
core_bookings/busyfilterarray $busy, array $staff, int $start, int $endAdd busy intervals [[start, end], …] from another calendar. Throw calendar_unavailable (503) to pause that person’s online availability.
core_bookings/calendar_eventfilterarray $event, array $booking, string $kindThe Google Calendar event body before it’s written (booking or meeting).
core_bookings/calendar_jobactionarray $booking, Store $storeA booking’s calendar job is running. Queue your own sync.
core_bookings/calendar_workeractionCalendarSync $sync, float $deadlineBounded maintenance inside the calendar worker, every minute.
core_bookings/calendar_connectionsactionint $userId, array $staffPrint sections on My calendar.
core_bookings/meeting_providersfilterarray $providersAdd a video meeting choice (id => label). none, meet and zoom are built in.
core_bookings/meeting_readyactionstring $provider, array $service, array $staffThrow when this host can’t create links.
core_bookings/meeting_linkfilterstring $url, string $provider, array $meeting, array $booking, array $staff, array $snapshotCreate or update the remote meeting and return its HTTPS join URL.
core_bookings/meeting_cleanupfilter?int $status, string $provider, array $meetingDelete the remote meeting and return the provider’s HTTP status.
core_bookings/automation_actionsfilterarray $actionsAdd actions to the Automations module.
core_bookings/automation_valuesfilterarray $values, array $booking, Store $storeFill automation placeholders.
core_bookings/crm_contactfilterarray $contact, array $booking, string $toolChange the contact sent to FluentCRM or MailerPress (Integrations).
core_bookings/review_approvedactionarray $review, Store $storeA review was approved (Reviews).
core_bookings/review_displayfilterbool $show, array $argsReturn false to turn off the built-in reviews block and shortcode.
core_bookings/insights_locationsfilterarray $locationsid => label locations for the Reports filter.
core_bookings/whatsapp_graph_versionfilterstring $versionGraph API version for WhatsApp (default v21.0).

Filters Core Bookings Answers

With the Integrations module on, other plugins can ask Core Bookings for data through these filters:

  • apply_filters('core_bookings/portal_bookings', [], $userId, $args): bookings of the customer linked to a WordPress user, for a client portal.
  • apply_filters('core_bookings/support_context', [], $email, $args): a customer’s upcoming and recent bookings for a support ticket.
  • apply_filters('core_bookings/quote_booking_url', '', $quote) and do_action('core_bookings/open_booking', $quote): a private booking link with the customer prefilled, for a quote. core_bookings/quote_booked fires when it’s used.

Booking Form Extensions

HookTypeArgumentsUse
core_bookings/public_servicefilterarray $payload, array $serviceSet choices, questions, coupon, quote or hidden for the booking form.
core_bookings/public_servicesfilterarray $listRemove or reorder services the form and dashboard list.
core_bookings/widget_assetsactionint $service, array $optionsEnqueue scripts that extend the form.
core_bookings/checkin_urlfilterstring $url, string $code, array $bookingThe URL a class ticket’s QR code opens (Classes, Staff portal).

In the browser, register scripts with core-bookings as a dependency and push functions onto window.coreBookingsHooks.appointment, details, payload or manage. Custom question types render through window.coreBookingsQuestionTypes[type].

add_filter('core_bookings/price', function (array $price, array $service, array $input, array $context): array {
    $hour = (int) wp_date('G', $context['start'] ?: time());
    if ($context['start'] && $hour >= 18) {
        $price['lines'][] = ['label' => 'Evening rate', 'amount' => 1000];
        $price['total'] += 1000;
        $price['due'] += 1000;
    }
    return $price;
}, 10, 4);

Need a hook that isn’t here? Ask on the roadmap.

Share

Was this helpful?

Still stuck? Open a support ticket