Created
February 24, 2026 09:39
-
-
Save thisissandip/a03bfd81dc3616917c73d51d9c8954a9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Cross-Resource Booking Blocker | |
| * | |
| * When a booking is paid using one resource, block the related resources | |
| * to prevent double-booking of shared spaces. | |
| */ | |
| // Define the resource relationships (update these IDs after creating resources) | |
| define('PRIMARY_RESOURCE_ID', 123); // Replace with actual resource ID (e.g., Entire Space) | |
| define('SECONDARY_RESOURCE_A_ID', 456); // Replace with actual resource ID (e.g., Space A) | |
| define('SECONDARY_RESOURCE_B_ID', 789); // Replace with actual resource ID (e.g., Space B) | |
| function get_resources_to_block($booked_resource_id) { | |
| $resources_to_block = []; | |
| switch ($booked_resource_id) { | |
| case PRIMARY_RESOURCE_ID: | |
| // Primary resource booked → block secondary resources | |
| $resources_to_block = [SECONDARY_RESOURCE_A_ID, SECONDARY_RESOURCE_B_ID]; | |
| break; | |
| case SECONDARY_RESOURCE_A_ID: | |
| case SECONDARY_RESOURCE_B_ID: | |
| // Secondary resource booked → block primary resource | |
| $resources_to_block = [PRIMARY_RESOURCE_ID]; | |
| break; | |
| } | |
| return $resources_to_block; | |
| } | |
| function get_resource_name($resource_id) { | |
| $resource_name = get_the_title($resource_id); | |
| return $resource_name ? $resource_name : 'Unknown Resource'; | |
| } | |
| function block_related_resources_on_payment($booking_id) { | |
| $booking = new WC_Booking($booking_id); | |
| $resource_id = $booking->get_resource_id(); | |
| $start_time = $booking->get_start(); | |
| $end_time = $booking->get_end(); | |
| if (!$resource_id) { | |
| return; | |
| } | |
| $resources_to_block = get_resources_to_block($resource_id); | |
| if (empty($resources_to_block) || !$start_time || !$end_time) { | |
| return; | |
| } | |
| $from_date = date('Y-m-d', $start_time); | |
| $to_date = date('Y-m-d', $end_time); | |
| $from_time = date('H:i', $start_time); | |
| $to_time = date('H:i', $end_time); | |
| $is_full_day = ($from_time === '00:00' && ($to_time === '00:00' || $to_time === '23:59')); | |
| // Build the availability rule | |
| $availability_rule = [ | |
| 'bookable' => 'no', | |
| 'priority' => 1, | |
| 'booking_id' => $booking_id, // Track which booking created this rule (for cleanup) | |
| ]; | |
| if ($is_full_day) { | |
| $availability_rule['type'] = 'custom'; | |
| $availability_rule['from'] = $from_date; | |
| $availability_rule['to'] = $to_date; | |
| } else { | |
| $availability_rule['type'] = 'custom:daterange'; | |
| $availability_rule['from_date'] = $from_date; | |
| $availability_rule['to_date'] = $to_date; | |
| $availability_rule['from'] = $from_time; | |
| $availability_rule['to'] = $to_time; | |
| } | |
| // Get booked resource name for logging | |
| $booked_resource_name = get_resource_name($resource_id); | |
| // Add blocking rule to each related resource | |
| foreach ($resources_to_block as $block_resource_id) { | |
| $existing_availability = get_post_meta($block_resource_id, '_wc_booking_availability', true); | |
| if (!is_array($existing_availability)) { | |
| $existing_availability = []; | |
| } | |
| $existing_availability[] = $availability_rule; | |
| update_post_meta($block_resource_id, '_wc_booking_availability', $existing_availability); | |
| // Log the action | |
| if (function_exists('wc_get_logger')) { | |
| $logger = wc_get_logger(); | |
| $blocked_resource_name = get_resource_name($block_resource_id); | |
| if ($is_full_day) { | |
| $log_message = sprintf( | |
| 'Booking #%d paid: "%s" (Resource ID: %d) was blocked from %s to %s (full day) — triggered by booking of "%s" (Resource ID: %d)', | |
| $booking_id, | |
| $blocked_resource_name, | |
| $block_resource_id, | |
| $from_date, | |
| $to_date, | |
| $booked_resource_name, | |
| $resource_id | |
| ); | |
| } else { | |
| $log_message = sprintf( | |
| 'Booking #%d paid: "%s" (Resource ID: %d) was blocked from %s %s to %s %s — triggered by booking of "%s" (Resource ID: %d)', | |
| $booking_id, | |
| $blocked_resource_name, | |
| $block_resource_id, | |
| $from_date, | |
| $from_time, | |
| $to_date, | |
| $to_time, | |
| $booked_resource_name, | |
| $resource_id | |
| ); | |
| } | |
| $logger->info($log_message, ['source' => 'cross-resource-blocker']); | |
| } | |
| } | |
| } | |
| // Hook into payment status transitions | |
| add_action('woocommerce_booking_in-cart_to_paid', 'block_related_resources_on_payment'); | |
| add_action('woocommerce_booking_unpaid_to_paid', 'block_related_resources_on_payment'); | |
| add_action('woocommerce_booking_confirmed_to_paid', 'block_related_resources_on_payment'); | |
| /** | |
| * Remove blocking rules when a booking is cancelled or refunded | |
| */ | |
| function unblock_related_resources_on_cancellation($booking_id) { | |
| $booking = new WC_Booking($booking_id); | |
| $resource_id = $booking->get_resource_id(); | |
| if (!$resource_id) { | |
| return; | |
| } | |
| $resources_to_unblock = get_resources_to_block($resource_id); | |
| if (empty($resources_to_unblock)) { | |
| return; | |
| } | |
| // Get cancelled resource name for logging | |
| $cancelled_resource_name = get_resource_name($resource_id); | |
| foreach ($resources_to_unblock as $unblock_resource_id) { | |
| $existing_availability = get_post_meta($unblock_resource_id, '_wc_booking_availability', true); | |
| if (!is_array($existing_availability)) { | |
| continue; | |
| } | |
| // Remove rules that were created by this booking | |
| $updated_availability = array_filter($existing_availability, function($rule) use ($booking_id) { | |
| return !isset($rule['booking_id']) || $rule['booking_id'] !== $booking_id; | |
| }); | |
| update_post_meta($unblock_resource_id, '_wc_booking_availability', array_values($updated_availability)); | |
| // Log the action | |
| if (function_exists('wc_get_logger')) { | |
| $logger = wc_get_logger(); | |
| $unblocked_resource_name = get_resource_name($unblock_resource_id); | |
| $log_message = sprintf( | |
| 'Booking #%d cancelled: "%s" (Resource ID: %d) was unblocked — triggered by cancellation of "%s" (Resource ID: %d)', | |
| $booking_id, | |
| $unblocked_resource_name, | |
| $unblock_resource_id, | |
| $cancelled_resource_name, | |
| $resource_id | |
| ); | |
| $logger->info($log_message, ['source' => 'cross-resource-blocker']); | |
| } | |
| } | |
| } | |
| // Hook into cancellation/refund status transitions | |
| add_action('woocommerce_booking_paid_to_cancelled', 'unblock_related_resources_on_cancellation'); | |
| add_action('woocommerce_booking_confirmed_to_cancelled', 'unblock_related_resources_on_cancellation'); | |
| add_action('woocommerce_booking_paid_to_refunded', 'unblock_related_resources_on_cancellation'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment