PluginProbe
Bookit — Booking & Appointment Calendar / 2.6.0.5
Bookit — Booking & Appointment Calendar v2.6.0.5
2.6.0.5 2.6.0.4 2.6.0.3 2.6.0.2 2.6.0.1 2.6.0 trunk 1.2 1.2.2 1.2.3 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 All 62 releases
← All changes | includes/classes/AppointmentController.php +80 -27 trunk2.6.0.5 View file →
@@ -9,8 +9,11 @@
9 9 use Bookit\Classes\Database\Customers;
10 10 use Bookit\Classes\Database\Staff_Services;
11 11 use Bookit\Classes\Vendor\Payments;
12 12 use Bookit\Helpers\CleanHelper;
13 +use DateTimeZone;
14 +use DateTime;
15 +use Exception;
13 16
14 17
15 18 class AppointmentController {
16 19
@@ -54,9 +57,61 @@
54 57 );
55 58 }
56 59
57 60 /**
61 + * Convert UTC offset to timezone name.
62 + *
63 + * @since 2.5.2
64 + *
65 + * @param string $timezone_string The timezone string from wp_timezone_string().
66 + *
67 + * @return string The timezone name or an empty string if no match is found.
68 + */
69 + private static function convert_offset_to_timezone_name( $timezone_string ) {
70 + // Check if it's a UTC offset (format: +HH:MM or -HH:MM).
71 + if ( preg_match( '/^([+-])(\d{2}):(\d{2})$/', $timezone_string, $matches ) ) {
72 + $sign = ( $matches[1] === '-' ) ? -1 : 1;
73 + $hours = (int) $matches[2];
74 + $minutes = (int) $matches[3];
75 + $offset_seconds = $sign * ( $hours * 3600 + $minutes * 60 );
76 +
77 + // Try to find a timezone name based on the offset.
78 + $timezone_name = timezone_name_from_abbr( '', $offset_seconds, 0 );
79 +
80 + if ( $timezone_name !== false ) {
81 + return $timezone_name;
82 + }
83 +
84 + // If timezone_name_from_abbr() fails, search through timezone identifiers.
85 + $timezone_identifiers = DateTimeZone::listIdentifiers();
86 + $now = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
87 +
88 + foreach ( $timezone_identifiers as $identifier ) {
89 + try {
90 + $tz = new DateTimeZone( $identifier );
91 + $offset = $tz->getOffset( $now );
92 +
93 + if ( $offset === $offset_seconds ) {
94 + return $identifier;
95 + }
96 + } catch ( Exception $e ) {
97 + continue;
98 + }
99 + }
100 +
101 + // If no match found, return an empty string.
102 + return '';
103 + }
104 +
105 + // Already a timezone name, return as is.
106 + return $timezone_string;
107 + }
108 +
109 + /**
58 110 * Validation
111 + *
112 + * @since 2.6.0 Booking identity is derived from the authenticated session in Registered mode.
113 + *
59 114 * @param $data
60 115 */
61 116 public static function validate( $data ) {
62 117 $errors = array();
@@ -111,34 +166,8 @@
111 166 } else {
112 167 $errors['full_name'] = __( 'Please enter full name', 'bookit' );
113 168 }
114 169
115 - if ( 'registered' == $settings['booking_type'] ) {
116 -
117 - $exist_user = get_user_by( 'email', $data['email'] );
118 - if ( ! $data['user_id'] && $exist_user && ! wp_check_password( $data['password'], $exist_user->data->user_pass, $exist_user->ID ) ) {
119 - $errors['password'] = __( 'Wrong password', 'bookit' );
120 - }
121 -
122 - if ( ! $data['user_id'] ) {
123 - if ( empty( $data['password'] ) ) {
124 - $errors['password'] = __( 'Please enter a password', 'bookit' );
125 - }
126 -
127 - if ( false !== strpos( wp_unslash( $data['password'] ), '\\' ) ) {
128 - $errors['password'] = __( "Passwords may not contain the character '\\'", 'bookit' );
129 - }
130 -
131 - if ( ! ( $exist_user instanceof \WP_User ) && ( ! empty( $data['password'] ) ) && $data['password'] != $data['password_confirmation'] ) {
132 - $errors['password_confirmation'] = __( 'Please enter the same password in both password fields', 'bookit' );
133 - }
134 - }
135 -
136 - if ( $data['user_id'] && ! is_user_logged_in() ) {
137 - $errors['appointment'] = __( 'Authorization error', 'bookit' );
138 - }
139 - }
140 -
141 170 $price = Staff_Services::get_service_price_by_staff( $data['service_id'], $data['staff_id'] );
142 171 if ( (float) $data['clear_price'] !== (float) $price ) {
143 172 $errors['clear_price'] = __( 'Price is incorrect', 'bookit' );
144 173 }
@@ -153,11 +182,13 @@
153 182 }
154 183
155 184 /**
156 185 * Book Appointment
186 + *
187 + * @since 2.6.0 Require authentication and link the booking to the current user in Registered mode.
188 + * @since 2.6.0.2 Derive the booking identity from the current session.
157 189 */
158 190 public static function save() {
159 -
160 191 $send_no_cache_headers = apply_filters( 'rest_send_nocache_headers', is_user_logged_in() );
161 192 $nonce = '';
162 193 if ( ! $send_no_cache_headers ) {
163 194 $nonce = wp_create_nonce( 'bookit_nonce' );
@@ -166,8 +197,25 @@
166 197
167 198 check_ajax_referer( 'bookit_book_appointment', 'nonce' );
168 199
169 200 $data = CleanHelper::cleanData( $_POST, self::getCleanRules() );
201 +
202 + // Identify the booking from the current session.
203 + $data['user_id'] = get_current_user_id();
204 +
205 + $settings = SettingsController::get_settings();
206 + if ( 'registered' == $settings['booking_type'] ) {
207 + // Registered booking is tied to the authenticated visitor.
208 + if ( ! is_user_logged_in() ) {
209 + wp_send_json_error( array(
210 + 'login_required' => true,
211 + 'message' => __( 'Please log in to complete your booking.', 'bookit' ),
212 + ) );
213 + }
214 +
215 + $data['email'] = wp_get_current_user()->user_email;
216 + }
217 +
170 218 self::validate( $data );
171 219
172 220 if ( empty( $data ) ) {
173 221 wp_send_json_error( array( 'message' => __( 'Error occurred!', 'bookit' ) ) );
@@ -207,8 +255,13 @@
207 255 $appointment['customer_phone'] = $notes['phone'] ?? $appointment['customer_phone'];
208 256 do_action( 'bookit_google_calendar_create_appointment', $appointment );
209 257 }
210 258 /** if google calendar addon is installed | end */
259 +
260 + // Add timezone to the appointment.
261 + $appointment['timezone_name'] = self::convert_offset_to_timezone_name(
262 + wp_timezone_string()
263 + );
211 264
212 265 $redirect_url = '';
213 266 if ( ! is_null( $appointment['payment_method'] ) ) {
214 267 $payments = new Payments( $appointment );