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 );
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
woocommerce_appointment_get_permalink
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 );
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.
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:
| Method | Description |
|---|---|
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.
| Hook | What It Filters | Callback Receives |
|---|---|---|
appointment_modal_header | Header row (title) | React element |
appointment_modal_customer_section | Customer info rows | Array of { label, value, key } |
appointment_modal_schedule_section | When/Duration rows | Array of { label, value, key } |
appointment_modal_staff_section | Staff info rows | Array of { label, value, key } |
appointment_modal_addons_section | Add-ons rows | Array of { label, value, key } |
appointment_modal_pricing_section | Pricing/order section | React element |
appointment_modal_footer_actions | Status action controls in the modal status section | Array of React elements |
Insertion Points
Use these to add custom content at specific positions. Return an array of React elements.
| Hook | Position |
|---|---|
appointment_modal_after_header | After header, before body content |
appointment_modal_after_customer | After customer section |
appointment_modal_after_schedule | After schedule (when/duration) section |
appointment_modal_after_staff | After staff section |
appointment_modal_after_addons | After add-ons section |
appointment_modal_after_pricing | After pricing section |
appointment_modal_before_footer | Before 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:
- Code Snippets Plugin - Add to a custom snippet that runs on admin pages
- Custom Plugin - Enqueue your JS file on the appointments admin page
- 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