PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / 1.0.64
Timetics – Appointment Booking Calendar & Scheduling v1.0.64
1.0.64 1.0.62 1.0.63 1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 All 65 releases
← All changes | core/appointments/appointment.php +74 -13 1.0.56 → 1.0.64 View file →
@@ -7,11 +7,12 @@
7 7 * @package Timetics
8 8 */
9 9 namespace Timetics\Core\Appointments;
10 10
11 +defined( 'ABSPATH' ) || exit;
12 +
11 13 use DateTime;
12 14 use Timetics\Base\PostModel;
13 -use Timetics\Core\Bookings\Booking;
14 15 use Timetics\Core\Bookings\Booking_Entry;
15 16 use Timetics\Core\Staffs\Staff;
16 17 use WP_Query;
17 18
@@ -84,8 +85,10 @@
84 85 'pabbly_hook_overwrite' => '',
85 86 'zapier_hook_overwrite' => '',
86 87 'pabbly_webook' => '',
87 88 'zapier_webook' => '',
89 + 'flowmattic_hook_overwrite' => '',
90 + 'flowmattic_webhook' => '',
88 91 'min_notice_time' => '',
89 92 'notifications' => [
90 93 'booking_created_email_form' => '',
91 94 'booking_created_email_title' => '',
@@ -237,8 +240,25 @@
237 240 return $this->get_prop( 'capacity' );
238 241 }
239 242
240 243 /**
244 + * Get the effective booking capacity used for availability checks.
245 + *
246 + * One-to-One meetings always allow a single booking per slot regardless of
247 + * the stored capacity meta (which is only meaningful for group meetings),
248 + * matching the one-to-one handling used elsewhere in the booking flow.
249 + *
250 + * @return integer
251 + */
252 + public function get_effective_capacity() {
253 + if ( 'one-to-one' === strtolower( (string) $this->get_type() ) ) {
254 + return 1;
255 + }
256 +
257 + return intval( $this->get_capacity() );
258 + }
259 +
260 + /**
241 261 * Get location
242 262 *
243 263 * @since 1.0.0
244 264 *
@@ -408,8 +428,14 @@
408 428 }
409 429 public function get_zapier_hook_overwrite() {
410 430 return $this->get_prop( 'zapier_hook_overwrite' );
411 431 }
432 + public function get_flowmattic_webhook() {
433 + return $this->get_prop( 'flowmattic_webhook' );
434 + }
435 + public function get_flowmattic_hook_overwrite() {
436 + return $this->get_prop( 'flowmattic_hook_overwrite' );
437 + }
412 438 public function get_min_notice_time() {
413 439 return $this->get_prop( 'min_notice_time' );
414 440 }
415 441 public function get_guest_enabled() {
@@ -537,9 +563,9 @@
537 563 */
538 564 public function get_author() {
539 565 $post = get_post( $this->id );
540 566
541 - return $post->post_author;
567 + return $post ? (int) $post->post_author : 0;
542 568 }
543 569
544 570 /**
545 571 * Get seat plan settings
@@ -649,13 +675,15 @@
649 675 $args = [
650 676 'post_title' => $this->data['name'],
651 677 'post_type' => $this->post_type,
652 678 'post_status' => 'publish',
653 - 'post_author' => get_current_user_id(),
654 679 ];
655 680
656 681 if ( ! empty( $this->id ) ) {
657 682 $args['ID'] = $this->id;
683 + } else {
684 + // Only on creation — setting this on update reassigns post_author to whoever edits it.
685 + $args['post_author'] = get_current_user_id();
658 686 }
659 687
660 688 // Insert or Update appointment.
661 689 $appoint_id = wp_insert_post( $args );
@@ -747,9 +775,10 @@
747 775 ];
748 776
749 777 $args = wp_parse_args( $args, $defaults );
750 778
751 - if ( ! empty( $args['staff'] ) ) {
779 + // isset()/'' check, not empty() — empty(0) skipped this filter, leaking all staff data to guests.
780 + if ( isset( $args['staff'] ) && '' !== $args['staff'] ) {
752 781 $args['meta_query'][] = [
753 782 'key' => '_tt_apointment_staff',
754 783 'value' => $args['staff'],
755 784 'compare' => 'LIKE',
@@ -817,8 +846,10 @@
817 846 'fleunt_crm_webhook' => $this->get_fleunt_crm_webhook(),
818 847 'pabbly_hook_overwrite' => $this->get_pabbly_hook_overwrite(),
819 848 'pabbly_webook' => $this->get_pabbly_webook(),
820 849 'zapier_webook' => $this->get_zapier_webook(),
850 + 'flowmattic_webhook' => $this->get_flowmattic_webhook(),
851 + 'flowmattic_hook_overwrite' => $this->get_flowmattic_hook_overwrite(),
821 852 'min_notice_time' => $this->get_min_notice_time(),
822 853 'zapier_hook_overwrite' => $this->get_zapier_hook_overwrite(),
823 854 'guest_enabled' => $this->get_guest_enabled(),
824 855 'guest_limit' => $this->get_guest_limit(),
@@ -877,12 +908,12 @@
877 908
878 909 // Get buffer times in seconds
879 910 $buffer_before = $this->get_buffer_time_before_in_seconds();
880 911 $buffer_after = $this->get_buffer_time_after_in_seconds();
881 -
912 +
882 913 // Adjust the start time to include buffer before
883 914 $adjusted_start = $start + $buffer_before;
884 -
915 +
885 916 // Adjust the end time to ensure we have enough time for the slot + buffer after
886 917 $min_slot_duration = $interval + $buffer_after;
887 918
888 919 for ( $time = $adjusted_start; $time + $min_slot_duration <= $end; $time += $interval + $buffer_after + $buffer_before ) {
@@ -887,9 +918,9 @@
887 918
888 919 for ( $time = $adjusted_start; $time + $min_slot_duration <= $end; $time += $interval + $buffer_after + $buffer_before ) {
889 920 $booked_entry = $this->get_booking_entries( $date, $time, $staff_id );
890 921 $status = 'available';
891 - $capacity = $this->get_capacity();
922 + $capacity = $this->get_effective_capacity();
892 923 $booked = 0;
893 924
894 925 if ( $booked_entry ) {
895 926 if ( $booked_entry->get_booked() >= $capacity ) {
@@ -898,9 +929,11 @@
898 929
899 930 $booked = $booked_entry->get_booked();
900 931 }
901 932
902 - $datetime = $this->convert_timezone( $time, $time_zone );
933 + // $time is only a clock reading, so pass the slot's own date or
934 + // today's DST offset gets applied to a date in the other season.
935 + $datetime = $this->convert_timezone( $date . ' ' . gmdate( 'g:ia', $time ), $time_zone );
903 936
904 937 $slot = [
905 938 'status' => $status,
906 939 'start_time' => $datetime->format( 'g:ia' ),
@@ -937,16 +970,21 @@
937 970 'date' => $this->convert_timezone( $date, $this->get_timezone())->format('Y-m-d'),
938 971 ] );
939 972
940 973 foreach ( $entries as $entry ) {
941 - $booking = new Booking( $entry->get_booking_id() );
942 974 $start_time = $entry->get_start();
943 975 $end_time = $entry->get_end();
944 976
945 977 // Check if current time slot falls within the booking duration
946 - if ( $this->is_time_in_range( $time, $start_time, $end_time ) ) {
947 - return $entry;
978 + if ( ! $this->is_time_in_range( $time, $start_time, $end_time ) ) {
979 + continue;
948 980 }
981 +
982 + if ( $this->is_orphan_entry( $entry ) ) {
983 + continue;
984 + }
985 +
986 + return $entry;
949 987 }
950 988
951 989 return false;
952 990 }
@@ -951,12 +989,34 @@
951 989 return false;
952 990 }
953 991
954 992 /**
993 + * Whether an entry outlived its booking and should stop blocking the slot.
994 + *
995 + * Only single-booking entries qualify: a shared entry names just its first
996 + * booker in `booking_id`, and entries with none belong to events/imports.
997 + *
998 + * @param Booking_Entry $entry
999 + *
1000 + * @return bool
1001 + */
1002 + private function is_orphan_entry( $entry ) {
1003 + $booking_id = $entry->get_booking_id();
1004 +
1005 + if ( ! $booking_id || intval( $entry->get_booked() ) > 1 ) {
1006 + return false;
1007 + }
1008 +
1009 + $booking = get_post( $booking_id );
1010 +
1011 + return ! $booking || 'timetics-booking' !== $booking->post_type;
1012 + }
1013 +
1014 + /**
955 1015 * Check if a time falls within a given time range
956 1016 *
957 1017 * @param string $current_time Current time in h:i a format
958 - * @param string $start_time Start time in h:i a format
1018 + * @param string $start_time Start time in h:i a format
959 1019 * @param string $end_time End time in h:i a format
960 1020 *
961 1021 * @return bool
962 1022 */
@@ -1033,9 +1093,10 @@
1033 1093 $start = strtotime( $day['start'] );
1034 1094 $end = strtotime( $day['end'] );
1035 1095
1036 1096 for ( $time = $start; $time <= $end; $time += $interval ) {
1037 - $datetime = $this->convert_timezone( $time, $time_zone );
1097 + // Slot's own date, see get_schedule_by_date().
1098 + $datetime = $this->convert_timezone( $date . ' ' . gmdate( 'g:ia', $time ), $time_zone );
1038 1099 $slot = $datetime->format( 'g:ia' );
1039 1100 $slots[] = $slot;
1040 1101 }
1041 1102 }