Skip to main content

Hooks & Filters

WooCommerce Appointments provides a comprehensive set of hooks and filters that allow you to customize and extend the plugin's functionality. This reference includes all available hooks with their parameters, descriptions, and usage examples.

Actions

Actions are events that fire at specific points in the plugin's execution. You can hook into these actions to perform custom functionality.

Appointment Lifecycle

woocommerce_new_appointment

Fires when a new appointment is created and saved to the database.

Parameters:

  • $appointment_id (int) - The appointment ID

Since: 3.0.0

Example:

add_action( 'woocommerce_new_appointment', function( $appointment_id ) {
$appointment = wc_appointment( $appointment_id );
// Send custom notification
wp_mail( 'admin@example.com', 'New Appointment', 'Appointment #' . $appointment_id . ' created' );
} );

woocommerce_appointment_status_changed

Fires when an appointment status changes.

Parameters:

  • $from (string) - Previous status
  • $to (string) - New (current) status
  • $appointment_id (int) - The appointment ID
  • $appointment (WC_Appointment) - The appointment object

Since: 4.11.3

Example:

add_action( 'woocommerce_appointment_status_changed', function( $from, $to, $appointment_id, $appointment ) {
if ( 'confirmed' === $to ) {
// Log status change
error_log( "Appointment #{$appointment_id} changed from {$from} to {$to}" );
}
}, 10, 4 );

woocommerce_appointment_{status}

Dynamic hook that fires when an appointment reaches a specific status. Replace {status} with the actual status (e.g., unpaid, pending-confirmation, confirmed, paid, cancelled, complete, in-cart, was-in-cart).

Parameters:

  • $appointment_id (int) - The appointment ID
  • $appointment (WC_Appointment) - The appointment object

Since: 3.0.0

Example:

add_action( 'woocommerce_appointment_confirmed', function( $appointment_id, $appointment ) {
// Trigger custom action when appointment is confirmed
do_action( 'my_custom_confirmed_action', $appointment_id );
}, 10, 2 );

woocommerce_appointment_{old_status}_to_{new_status}

Dynamic hook for specific status transitions. Fires when an appointment transitions from one status to another.

Parameters:

  • $appointment_id (int) - The appointment ID
  • $appointment (WC_Appointment) - The appointment object

Since: 3.0.0

Example:

add_action( 'woocommerce_appointment_pending-confirmation_to_confirmed', function( $appointment_id, $appointment ) {
// Custom logic when appointment moves from pending to confirmed
}, 10, 2 );

woocommerce_appointment_cancelled

Fires when an appointment is cancelled.

Parameters:

  • $appointment_id (int) - The appointment ID
  • $appointment (WC_Appointment) - The appointment object

Since: 3.0.0

Example:

add_action( 'woocommerce_appointment_cancelled', function( $appointment_id, $appointment ) {
// Release resources or send cancellation notification
}, 10, 2 );

woocommerce_appointment_staff_changed

Fires when appointment staff changes.

Parameters:

  • $from (int) - Previous staff ID
  • $to (int) - New staff ID
  • $appointment_id (int) - The appointment ID
  • $appointment (WC_Appointment) - The appointment object

Since: 4.22.0

Example:

add_action( 'woocommerce_appointment_staff_changed', function( $from, $to, $appointment_id, $appointment ) {
// Notify new staff member
$staff = get_user_by( 'id', $to );
if ( $staff ) {
wp_mail( $staff->user_email, 'New Assignment', 'You have been assigned to appointment #' . $appointment_id );
}
}, 10, 4 );

woocommerce_appointments_rescheduled_appointment

Fires after an appointment is rescheduled.

Parameters:

  • $appointment_id (int) - The appointment ID
  • $prev_start_date (int) - Previous start date timestamp
  • $prev_end_date (int) - Previous end date timestamp

Since: 3.0.0

Example:

add_action( 'woocommerce_appointments_rescheduled_appointment', function( $appointment_id, $prev_start_date, $prev_end_date ) {
$appointment = wc_appointment( $appointment_id );
error_log( sprintf(
'Appointment #%d rescheduled from %s to %s',
$appointment_id,
date( 'Y-m-d H:i', $prev_start_date ),
date( 'Y-m-d H:i', $appointment->get_start() )
) );
}, 10, 3 );

woocommerce_appointments_cancelled_appointment

Fires when a customer cancels an appointment.

Parameters:

  • $appointment_id (int) - The appointment ID

Since: 3.0.0

Example:

add_action( 'woocommerce_appointments_cancelled_appointment', function( $appointment_id ) {
// Process refund or update external system
// Note: This example assumes you have an external system integration
// (e.g., CRM, accounting software, or custom API)
}, 10, 1 );
External Service Required

This example assumes integration with an external system (CRM, accounting software, custom API, etc.). You'll need to implement the connection logic based on your specific service.

woocommerce_new_appointment_order

Fires when a new order is created for an appointment.

Parameters:

  • $order_id (int) - The order ID

Since: 3.0.0

Example:

add_action( 'woocommerce_new_appointment_order', function( $order_id ) {
$order = wc_get_order( $order_id );
// Custom order processing
}, 10, 1 );

Admin Interface

woocommerce_appointments_after_staff_cost

Fires after staff cost field in admin.

Parameters:

  • $staff (WC_Appointment_Staff) - The staff object
  • $post_id (int) - The product/post ID

Since: 3.0.0

Example:

add_action( 'woocommerce_appointments_after_staff_cost', function( $staff, $post_id ) {
// Add custom field after staff cost
echo '<input type="text" name="custom_staff_field[' . $staff->get_id() . ']" />';
}, 10, 2 );

woocommerce_appointments_after_staff_qty

Fires after staff quantity field in admin.

Parameters:

  • $staff (WC_Appointment_Staff) - The staff object
  • $post_id (int) - The product/post ID

Since: 3.0.0

Google Calendar Integration

woocommerce_appointments_sync_from_gcal_event_start

Fires before processing a Google Calendar event during sync.

Parameters:

  • $event (object) - The Google Calendar event object

Since: 3.0.0

Example:

add_action( 'woocommerce_appointments_sync_from_gcal_event_start', function( $event ) {
// Log or modify event before processing
error_log( 'Syncing event: ' . $event->summary );
}, 10, 1 );

Indexing & Performance

wc_appointments_index_availability_rule

Fires when indexing an availability rule.

Parameters:

  • $rule_id (int) - The availability rule ID

Since: 3.0.0

wc_appointments_index_appointment

Fires when indexing an appointment.

Parameters:

  • $appointment_id (int) - The appointment ID

Since: 3.0.0

Filters

Filters allow you to modify data before it's used or displayed. Always return the modified value.

Availability & Scheduling

woocommerce_appointments_get_posted_data

Filters posted appointment form data before processing.

Parameters:

  • $data (array) - The appointment data array
  • $product (WC_Product_Appointment) - The product object
  • $posted (array) - The posted form data

Returns: (array) Modified appointment data

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointments_get_posted_data', function( $data, $product, $posted ) {
// Add custom field to appointment data
if ( isset( $posted['custom_field'] ) ) {
$data['custom_field'] = sanitize_text_field( $posted['custom_field'] );
}
return $data;
}, 10, 3 );

woocommerce_appointments_get_available_quantity

Filters available quantity for a product.

Parameters:

  • $qty (int) - Available quantity
  • $product (WC_Product_Appointment) - The product object
  • $staff_id (int|null) - Staff ID (null if no staff)

Returns: (int) Modified quantity

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointments_get_available_quantity', function( $qty, $product, $staff_id ) {
// Limit quantity based on custom logic
if ( $staff_id && $staff_id === 5 ) {
return min( $qty, 2 ); // Max 2 for this staff member
}
return $qty;
}, 10, 3 );

woocommerce_appointments_time_slots

Filters all time slots for availability calculation.

Parameters:

  • $available_slots (array) - Available slots array
  • $slots (array) - All slots array
  • $intervals (array) - Time intervals
  • $time_to_check (int) - Timestamp to check
  • $staff_id (int) - Staff ID
  • $from (int) - Start timestamp
  • $to (int) - End timestamp
  • $timezone (string) - Timezone string
  • $product (WC_Product_Appointment) - The product object

Returns: (array) Modified available slots

Since: 3.0.0

woocommerce_appointments_time_slot_html

Filters HTML for a single time slot display.

Parameters:

  • $slot_html (string) - The slot HTML
  • $display_slot (int) - Display slot timestamp
  • $quantity (array) - Quantity array
  • $time_to_check (int) - Timestamp to check
  • $staff_id (int) - Staff ID
  • $timezone (string) - Timezone string
  • $product (WC_Product_Appointment) - The product object
  • $spaces_left (int) - Spaces remaining
  • $args (array) - Additional arguments

Returns: (string) Modified HTML

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointments_time_slot_html', function( $slot_html, $display_slot, $quantity, $time_to_check, $staff_id, $timezone, $product, $spaces_left, $args ) {
// Add custom class to low availability slots
if ( $spaces_left <= 2 ) {
$slot_html = str_replace( 'class="', 'class="low-availability ', $slot_html );
}
return $slot_html;
}, 10, 9 );

appointment_form_posted_total_duration

Filters total duration from form data.

Parameters:

  • $duration (int) - Duration in minutes
  • $product (WC_Product_Appointment) - The product object
  • $posted (array) - Posted form data

Returns: (int) Modified duration

Since: 3.0.0

Appointment Behavior

woocommerce_appointment_requires_confirmation

Filters whether an appointment requires confirmation.

Parameters:

  • $requires_confirmation (bool) - Whether confirmation is required
  • $product (WC_Product_Appointment) - The product object

Returns: (bool) Modified requirement

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointment_requires_confirmation', function( $requires_confirmation, $product ) {
// Always require confirmation for specific product
if ( $product->get_id() === 123 ) {
return true;
}
return $requires_confirmation;
}, 10, 2 );

woocommerce_appointment_user_can_cancel

Filters whether a user can cancel an appointment.

Parameters:

  • $can_cancel (bool) - Whether user can cancel
  • $appointment (WC_Appointment) - The appointment object

Returns: (bool) Modified permission

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointment_user_can_cancel', function( $can_cancel, $appointment ) {
// Prevent cancellation within 24 hours
$hours_until_start = ( $appointment->get_start() - time() ) / HOUR_IN_SECONDS;
if ( $hours_until_start < 24 ) {
return false;
}
return $can_cancel;
}, 10, 2 );

woocommerce_appointment_user_can_reschedule

Filters whether a user can reschedule an appointment.

Parameters:

  • $can_reschedule (bool) - Whether user can reschedule
  • $appointment (WC_Appointment) - The appointment object

Returns: (bool) Modified permission

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointment_user_can_reschedule', function( $can_reschedule, $appointment ) {
// Only allow rescheduling for confirmed appointments
if ( $appointment->get_status() !== 'confirmed' ) {
return false;
}
return $can_reschedule;
}, 10, 2 );

woocommerce_appointment_cancelled_notice

Filters the cancellation notice message.

Parameters:

  • $message (string) - The notice message

Returns: (string) Modified message

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointment_cancelled_notice', function( $message ) {
return 'Your appointment has been successfully cancelled. We hope to see you again soon!';
}, 10, 1 );

woocommerce_appointment_rescheduled_notice

Filters the reschedule notice message.

Parameters:

  • $message (string) - The notice message
  • $appointment (WC_Appointment) - The appointment object
  • $prev_start_date (int) - Previous start date timestamp
  • $prev_end_date (int) - Previous end date timestamp

Returns: (string) Modified message

Since: 3.0.0

woocommerce_appointments_cancel_appointment_redirect

Filters redirect URL after appointment cancellation.

Parameters:

  • $redirect (string) - Redirect URL
  • $appointment_id (int) - The appointment ID

Returns: (string) Modified URL

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointments_cancel_appointment_redirect', function( $redirect, $appointment_id ) {
return wc_get_page_permalink( 'myaccount' ) . 'appointments/';
}, 10, 2 );

woocommerce_appointments_reschedule_appointment_redirect

Filters redirect URL after appointment rescheduling.

Parameters:

  • $redirect (string) - Redirect URL
  • $appointment_id (int) - The appointment ID

Returns: (string) Modified URL

Since: 3.0.0

Product Settings

woocommerce_appointments_get_duration

Filters appointment duration.

Parameters:

  • $value (int) - Duration value
  • $product (WC_Product_Appointment) - The product object

Returns: (int) Modified duration

Since: 3.0.0

woocommerce_appointments_get_duration_unit

Filters duration unit.

Parameters:

  • $unit (string) - Duration unit (minute, hour, day, month)
  • $product (WC_Product_Appointment) - The product object

Returns: (string) Modified unit

Since: 3.0.0

woocommerce_appointments_get_duration_in_minutes

Filters duration in minutes.

Parameters:

  • $duration (int) - Duration in minutes
  • $product (WC_Product_Appointment) - The product object

Returns: (int) Modified duration

Since: 3.0.0

woocommerce_appointments_quantity_input_max

Filters maximum quantity input for a product.

Parameters:

  • $max (int) - Maximum quantity
  • $product (WC_Product_Appointment) - The product object

Returns: (int) Modified maximum

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointments_quantity_input_max', function( $max, $product ) {
// Limit to 5 per customer
return min( $max, 5 );
}, 10, 2 );

Google Calendar Sync

woocommerce_appointments_gcal_sync_statuses

Filters appointment statuses that trigger Google Calendar sync.

Parameters:

  • $statuses (array) - Array of statuses to sync

Returns: (array) Modified statuses array

Since: 3.0.0

Default: ['paid', 'confirmed', 'complete']

Example:

add_filter( 'woocommerce_appointments_gcal_sync_statuses', function( $statuses ) {
// Also sync pending-confirmation status
$statuses[] = 'pending-confirmation';
return $statuses;
}, 10, 1 );

woocommerce_appointments_gcal_statuses

Filters appointment statuses that sync to Google Calendar.

Parameters:

  • $statuses (array) - Array of statuses

Returns: (array) Modified statuses array

Since: 3.0.0

wc_appointments_sync_with_padding

Controls whether padding time syncs to Google Calendar.

Parameters:

  • $sync (bool) - Whether to sync padding

Returns: (bool) Modified sync setting

Since: 3.0.0

Display & Formatting

woocommerce_appointments_date_format

Filters date format for appointments.

Parameters:

  • $format (string) - Date format string

Returns: (string) Modified format

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointments_date_format', function( $format ) {
return 'l, F j, Y'; // Monday, January 1, 2024
}, 10, 1 );

woocommerce_appointments_time_format

Filters time format for appointments.

Parameters:

  • $format (string) - Time format string

Returns: (string) Modified format

Since: 3.0.0

Filters appointment permalink.

Parameters:

  • $permalink (string) - The permalink
  • $appointment (WC_Appointment) - The appointment object

Returns: (string) Modified permalink

Since: 3.0.0

woocommerce_appointments_get_status_label

Filters status label for display.

Parameters:

  • $label (string) - Status label
  • $status (string) - Status slug

Returns: (string) Modified label

Since: 3.0.0

Example:

add_filter( 'woocommerce_appointments_get_status_label', function( $label, $status ) {
if ( 'pending-confirmation' === $status ) {
return 'Awaiting Confirmation';
}
return $label;
}, 10, 2 );

wc_appointment_pretty_timestamp

Filters pretty formatted timestamp.

Parameters:

  • $return (string) - Formatted timestamp string
  • $time (int) - Unix timestamp

Returns: (string) Modified formatted string

Since: 3.0.0

wc_appointment_pretty_addon_duration

Filters pretty formatted addon duration HTML.

Parameters:

  • $html (string) - HTML string
  • $time (int) - Time in minutes
  • $product (WC_Product_Appointment) - The product object

Returns: (string) Modified HTML

Since: 3.0.0

Cart & Checkout

woocommerce_appointments_remove_inactive_cart_time

Filters cart hold time in minutes before removing inactive appointments.

Parameters:

  • $minutes (int) - Hold time in minutes

Returns: (int) Modified minutes

Since: 3.0.0

Default: 60 minutes

Example:

add_filter( 'woocommerce_appointments_remove_inactive_cart_time', function( $minutes ) {
// Extend to 2 hours
return 120;
}, 10, 1 );

My Account

woocommerce_appointments_account_endpoint

Filters My Account appointments endpoint slug.

Parameters:

  • $endpoint (string) - Endpoint slug

Returns: (string) Modified endpoint

Since: 3.0.0

Default: 'appointments'

Example:

add_filter( 'woocommerce_appointments_account_endpoint', function( $endpoint ) {
return 'bookings'; // Change to /my-account/bookings/
}, 10, 1 );

woocommerce_appointments_my_appointments_per_page

Filters appointments per page in My Account.

Parameters:

  • $per_page (int) - Items per page

Returns: (int) Modified per page count

Since: 3.0.0

Admin Interface

woocommerce_appointments_admin_list_table_filters

Adds custom filters to the admin appointments list table.

Parameters:

  • $filters (array) - Array of filter options

Returns: (array) Modified filters

Since: 3.0.0

woocommerce_appointments_admin_buyer_name

Customizes buyer name display in admin.

Parameters:

  • $name (string) - Buyer name
  • $appointment (WC_Appointment) - The appointment object

Returns: (string) Modified name

Since: 3.0.0

woocommerce_appointments_appointment_cost_html

Filters appointment cost HTML in admin.

Parameters:

  • $html (string) - Cost HTML
  • $product (WC_Product_Appointment|null) - The product object
  • $posted (array) - Posted data

Returns: (string) Modified HTML

Since: 3.0.0

Performance & Caching

wc_appointments_cache_horizon_months

Filters cache horizon in months for availability calculations.

Parameters:

  • $months (int) - Number of months to cache

Returns: (int) Modified months

Since: 3.0.0

Example:

add_filter( 'wc_appointments_cache_horizon_months', function( $months ) {
// Cache 6 months ahead instead of default
return 6;
}, 10, 1 );

woocommerce_appointments_booking_lock_ttl

Filters booking lock TTL in seconds.

Parameters:

  • $ttl (int) - Time to live in seconds

Returns: (int) Modified TTL

Since: 3.0.0

Default: 5 seconds

Order Integration

woocommerce_appointments_zero_order_status

Filters order status for zero-total orders.

Parameters:

  • $status (string) - Order status
  • $order (WC_Order) - The order object

Returns: (string) Modified status

Since: 3.0.0

Default: 'completed'

Example:

add_filter( 'woocommerce_appointments_zero_order_status', function( $status, $order ) {
// Use 'processing' for zero-total orders
return 'processing';
}, 10, 2 );

woocommerce_appointments_stop_order_delete

Filters whether to prevent order deletion when it has appointments.

Parameters:

  • $delete (bool) - Whether to allow deletion
  • $order_id (int) - The order ID
  • $appointment_id (int) - The appointment ID

Returns: (bool) Modified permission

Since: 3.0.0

woocommerce_appointments_stop_order_update

Filters whether to prevent order status update.

Parameters:

  • $stop (bool) - Whether to stop update
  • $order (WC_Order) - The order object
  • $appointment_id (int) - The appointment ID
  • $status (string) - New status

Returns: (bool) Modified permission

Since: 3.0.0

REST API

woocommerce_rest_availabilities_query

Modifies availability API query arguments.

Parameters:

  • $args (array) - Query arguments

Returns: (array) Modified arguments

Since: 3.0.0

woocommerce_appointments_product_type_rest_check

Validates product type for REST API requests.

Parameters:

  • $is_valid (bool) - Whether product type is valid
  • $product (WC_Product) - The product object

Returns: (bool) Modified validation

Since: 3.0.0

Email Notifications

woocommerce_email_recipient_admin_new_appointment

Filters email recipients for admin new appointment email.

Parameters:

  • $recipients (string|array) - Email recipients
  • $appointment (WC_Appointment) - The appointment object

Returns: (string|array) Modified recipients

Since: 3.0.0

Example:

add_filter( 'woocommerce_email_recipient_admin_new_appointment', function( $recipients, $appointment ) {
// Add additional recipient
if ( is_string( $recipients ) ) {
$recipients = array( $recipients, 'manager@example.com' );
} else {
$recipients[] = 'manager@example.com';
}
return $recipients;
}, 10, 2 );

woocommerce_email_recipient_admin_appointment_cancelled

Filters email recipients for admin appointment cancelled email.

Parameters:

  • $recipients (string|array) - Email recipients
  • $appointment (WC_Appointment) - The appointment object

Returns: (string|array) Modified recipients

Since: 3.0.0

woocommerce_email_recipient_admin_appointment_rescheduled

Filters email recipients for admin appointment rescheduled email.

Parameters:

  • $recipients (string|array) - Email recipients
  • $appointment (WC_Appointment) - The appointment object

Returns: (string|array) Modified recipients

Since: 3.0.0

woocommerce_appointments_emails_ics

Controls whether ICS calendar files are attached to emails.

Parameters:

  • $attach (bool) - Whether to attach ICS

Returns: (bool) Modified setting

Since: 3.0.0

Default: true

Best Practices

Priority

When using hooks, consider the priority parameter:

// Default priority is 10
add_action( 'woocommerce_new_appointment', 'my_function' );

// Higher priority runs earlier
add_action( 'woocommerce_new_appointment', 'my_early_function', 5 );

// Lower priority runs later
add_action( 'woocommerce_new_appointment', 'my_late_function', 20 );

Parameter Count

Always specify the correct number of parameters when using filters or actions with multiple parameters:

// Correct - specifies 4 parameters
add_action( 'woocommerce_appointment_status_changed', function( $from, $to, $appointment_id, $appointment ) {
// Your code
}, 10, 4 );

Returning Values

Filters must always return a value:

add_filter( 'woocommerce_appointment_user_can_cancel', function( $can_cancel, $appointment ) {
// Always return the modified value
return $can_cancel && some_condition();
}, 10, 2 );

Performance

Be mindful of performance when hooking into frequently called filters:

// Cache expensive operations
add_filter( 'woocommerce_appointments_get_available_quantity', function( $qty, $product, $staff_id ) {
static $cache = array();
$cache_key = $product->get_id() . '_' . $staff_id;

if ( isset( $cache[ $cache_key ] ) ) {
return $cache[ $cache_key ];
}

$result = expensive_calculation( $qty, $product, $staff_id );
$cache[ $cache_key ] = $result;

return $result;
}, 10, 3 );

Common Use Cases

Custom Validation

add_filter( 'woocommerce_appointments_get_posted_data', function( $data, $product, $posted ) {
// Validate custom field
if ( empty( $posted['special_requirements'] ) && $product->get_id() === 123 ) {
wc_add_notice( 'Special requirements are required for this appointment.', 'error' );
return false;
}
return $data;
}, 10, 3 );

Dynamic Pricing

add_filter( 'woocommerce_appointments_get_posted_data', function( $data, $product, $posted ) {
// Add custom pricing based on date
$start_date = $data['_start'];
$day_of_week = date( 'w', $start_date );

if ( $day_of_week == 0 || $day_of_week == 6 ) {
$data['_cost'] = $data['_cost'] * 1.5; // Weekend surcharge
}

return $data;
}, 10, 3 );

Custom Notifications

add_action( 'woocommerce_appointment_confirmed', function( $appointment_id, $appointment ) {
// Send SMS notification
$phone = $appointment->get_customer()->get_billing_phone();
if ( $phone ) {
send_sms( $phone, "Your appointment #{$appointment_id} has been confirmed!" );
}
}, 10, 2 );
External Service Required

This example requires an SMS service provider (e.g., Twilio, Nexmo, AWS SNS) or an SMS plugin. The send_sms() function is not part of WordPress core or WooCommerce Appointments. You'll need to:

  • Install an SMS plugin (e.g., WooCommerce Twilio SMS), or
  • Implement your own SMS integration using a service provider's API

JavaScript Hooks (Admin Calendar Modal)

The admin calendar's appointment view modal supports JavaScript hooks for customizing its content. These hooks allow you to filter existing sections or add custom content at specific positions—all without modifying core plugin files.

Dynamic Content

The appointment modal content is dynamically generated using React. All data (customer info, order details, pricing, etc.) is fetched via REST API when the modal opens. Your hook callbacks receive the full appointment data object plus a context with helper functions.

The Hooks API

Access the hooks system via window.wcaModalHooks:

MethodDescription
addFilter( hook, callback, priority )Register a filter (priority default: 10, lower runs first)
removeFilter( hook, callback )Remove a previously registered callback
applyFilters( hook, value, appt, context )Apply all filters to a value
hasFilters( hook )Check if any filters are registered

Available Hooks

Section Filters

Use these to modify existing content. Your callback receives the current content, modifies it, and returns the result.

HookWhat It FiltersCallback Receives
appointment_modal_headerHeader row (title)React element
appointment_modal_customer_sectionCustomer info rowsArray of { label, value, key }
appointment_modal_schedule_sectionWhen/Duration rowsArray of { label, value, key }
appointment_modal_staff_sectionStaff info rowsArray of { label, value, key }
appointment_modal_addons_sectionAdd-ons rowsArray of { label, value, key }
appointment_modal_pricing_sectionPricing/order sectionReact element
appointment_modal_footer_actionsStatus action controls in the modal status sectionArray of React elements

Insertion Points

Use these to add custom content at specific positions. Return an array of React elements.

HookPosition
appointment_modal_after_headerAfter header, before body content
appointment_modal_after_customerAfter customer section
appointment_modal_after_scheduleAfter schedule (when/duration) section
appointment_modal_after_staffAfter staff section
appointment_modal_after_addonsAfter add-ons section
appointment_modal_after_pricingAfter pricing section
appointment_modal_before_footerBefore footer buttons

Context Object

Every callback receives a context object with useful data and helpers:

{
h, // React createElement function - use this to create elements
t, // Translation function: t( 'key', 'Fallback text' )
i18n, // Full i18n translations object
appt, // The appointment data object
orderInfo, // WooCommerce order data (if available)
staffList, // Array of all staff members
products, // Array of all appointable products
adminBase, // WordPress admin URL (e.g., '/wp-admin/')
adminPost, // Admin post.php URL
customerAvatar, // Customer avatar URL
staffAvatar, // Staff member avatar URL
displayName, // Customer display name
resolvedStaffName, // Staff member name
rangeText, // Formatted date/time range string
durationText // Formatted duration string
}

Examples

Add a Custom Row to the Customer Section

Add extra information below the existing customer row:

window.wcaModalHooks.addFilter(
'appointment_modal_customer_section',
function( rows, appt, ctx ) {
// rows is an array of { label, value, key } objects

// Add a VIP badge if customer has made 10+ appointments
if ( appt.customer_appointment_count >= 10 ) {
rows.push({
label: 'Status',
value: ctx.h( 'span', {
className: 'wca-vip-badge',
style: { color: 'gold', fontWeight: 'bold' }
}, '⭐ VIP Customer' ),
key: 'vip-status'
});
}

return rows; // Always return the rows array
},
10 // Priority (optional, default is 10)
);

Add Custom Content After a Section

Insert entirely new content after the customer section:

window.wcaModalHooks.addFilter(
'appointment_modal_after_customer',
function( content, appt, ctx ) {
var h = ctx.h; // Get the createElement function

// Add a custom notes display
if ( appt.meta && appt.meta._customer_notes ) {
content.push(
h( 'div', {
key: 'customer-notes',
className: 'wca-custom-notes',
style: {
padding: '10px',
background: '#f0f0f1',
margin: '10px 0',
borderRadius: '4px'
}
},
h( 'strong', null, 'Customer Notes: ' ),
appt.meta._customer_notes
)
);
}

return content; // Always return the content array
}
);

Add a Custom Status Action

Add your own action control alongside the built-in status controls:

window.wcaModalHooks.addFilter(
'appointment_modal_footer_actions',
function( buttons, appt, ctx ) {
var h = ctx.h;

// Add a "Send Reminder" button
buttons.push(
h( 'a', {
key: 'send-reminder',
className: 'button wc-action-button',
href: '#',
title: 'Send a reminder email to the customer',
onClick: function( e ) {
e.preventDefault();

// Make an AJAX call to send reminder
fetch( '/wp-admin/admin-ajax.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'action=send_appointment_reminder&appointment_id=' + appt.id
})
.then( function() {
alert( 'Reminder sent!' );
});
}
}, 'Send Reminder' )
);

return buttons;
}
);

Modify the Schedule Section

Add or modify the when/duration information:

window.wcaModalHooks.addFilter(
'appointment_modal_schedule_section',
function( rows, appt, ctx ) {
// Add timezone information
var timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
rows.push({
label: 'Timezone',
value: timezone,
key: 'timezone'
});

// Add days until appointment
if ( appt.start ) {
var start = new Date( appt.start * 1000 );
var now = new Date();
var days = Math.ceil( ( start - now ) / ( 1000 * 60 * 60 * 24 ) );

if ( days > 0 ) {
rows.push({
label: 'Days Away',
value: days + ' day' + ( days !== 1 ? 's' : '' ),
key: 'days-away'
});
}
}

return rows;
}
);

Where to Add Your Code

You can add these hooks via:

  1. Code Snippets Plugin - Add to a custom snippet that runs on admin pages
  2. Custom Plugin - Enqueue your JS file on the appointments admin page
  3. Theme functions.php - Enqueue JavaScript for admin

Example of enqueueing your custom JS:

add_action( 'admin_enqueue_scripts', function( $hook ) {
// Only load on the appointments calendar page
if ( 'wc_appointment_page_appointment_calendar' !== $hook ) {
return;
}

wp_enqueue_script(
'my-appointment-modal-hooks',
plugin_dir_url( __FILE__ ) . 'js/my-modal-hooks.js',
array(), // Dependencies
'1.0.0',
true // Load in footer
);
});

Performance Notes

  • Zero overhead when no hooks are registered (fast-path check)
  • Hooks only execute when the modal opens, not on calendar load
  • The context object is created once per modal render and reused
  • No impact on initial page load or calendar performance