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/CustomerController.php +173 -20 trunk2.6.0.5 View file →
@@ -1,9 +1,8 @@
1 1 <?php
2 2
3 3 namespace Bookit\Classes;
4 4
5 -use Bookit\Classes\Admin\SettingsController;
6 5 use Bookit\Classes\Base\User;
7 6 use Bookit\Classes\Database\Customers;
8 7
9 8 class CustomerController {
@@ -10,10 +9,14 @@
10 9
11 10 /**
12 11 * Appointment Customer
13 12 *
14 - * @param $data
13 + * @since 2.6.0 Resolve the customer from the authenticated session instead of request-supplied credentials.
14 + * @since 2.6.0.2 Resolve an existing customer from the session identity.
15 + * @since 2.6.0.2 Reuse an unlinked customer when the submitted contact fully matches.
15 16 *
17 + * @param array $data
18 + *
16 19 * @return object customer
17 20 */
18 21 public static function get_customer( $data ) {
19 22 $id = null;
@@ -22,27 +25,13 @@
22 25 $customer = Customers::get( 'wp_user_id', $data['user_id'] );
23 26 $id = $customer ? $customer->id : null;
24 27 }
25 28
26 - if ( ! $id && ! empty( $data['email'] ) ) {
27 - $customer = Customers::get( 'email', $data['email'] );
29 + if ( ! $id ) {
30 + $customer = self::match_guest_customer( $data );
28 31 $id = $customer ? $customer->id : null;
29 32 }
30 33
31 - $settings = SettingsController::get_settings();
32 - if ( 'registered' == $settings['booking_type'] && ! is_user_logged_in() ) {
33 - $data['role'] = User::$customer_role;
34 - $data['user_id'] = Customers::save_or_get_wp_user( $data );
35 -
36 - /** authorize everyone except the admin */
37 - if ( ! user_can( $data['user_id'], 'administrator' ) ) {
38 - /** Authorize wp User */
39 - wp_clear_auth_cookie();
40 - wp_set_current_user( $data['user_id'] );
41 - wp_set_auth_cookie( $data['user_id'] );
42 - }
43 - }
44 -
45 34 if ( ! $id ) {
46 35 $id = self::save( $data );
47 36 }
48 37
@@ -53,9 +42,166 @@
53 42
54 43 return Customers::get( 'id', $id );
55 44 }
56 45
57 - /** Save Customer **/
46 + /**
47 + * Authenticate a returning customer through WordPress and return a
48 + * session-ready payload so booking can continue without leaving the page.
49 + *
50 + * @since 2.6.0
51 + */
52 + public static function login() {
53 + check_ajax_referer( 'bookit_login', 'nonce' );
54 +
55 + $creds = array(
56 + 'user_login' => sanitize_text_field( wp_unslash( $_POST['email'] ?? '' ) ),
57 + 'user_password' => (string) ( $_POST['password'] ?? '' ),
58 + 'remember' => true,
59 + );
60 +
61 + // Make the just-issued session available to wp_create_nonce() in this request.
62 + add_action( 'set_logged_in_cookie', array( self::class, 'sync_logged_in_cookie' ) );
63 +
64 + $user = wp_signon( $creds );
65 +
66 + if ( is_wp_error( $user ) ) {
67 + // Keep credential failures generic so the form can't reveal which emails exist.
68 + $generic = array( 'invalid_username', 'invalid_email', 'incorrect_password' );
69 + $message = array_intersect( $generic, $user->get_error_codes() )
70 + ? __( 'The email or password you entered is incorrect.', 'bookit' )
71 + : wp_strip_all_tags( $user->get_error_message() );
72 + wp_send_json_error( array( 'message' => $message ) );
73 + }
74 +
75 + wp_set_current_user( $user->ID );
76 +
77 + wp_send_json_success( self::auth_payload( $user ) );
78 + }
79 +
80 + /**
81 + * Register a new customer account, sign them in, and return a session-ready
82 + * payload so booking can continue without leaving the page.
83 + *
84 + * @since 2.6.0
85 + */
86 + public static function register() {
87 + check_ajax_referer( 'bookit_register', 'nonce' );
88 +
89 + $email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) );
90 + $full_name = sanitize_text_field( wp_unslash( $_POST['full_name'] ?? '' ) );
91 + $password = (string) ( $_POST['password'] ?? '' );
92 + $confirm = (string) ( $_POST['password_confirmation'] ?? '' );
93 +
94 + $errors = array();
95 + if ( ! is_email( $email ) ) {
96 + $errors['email'] = __( 'Please enter your email in format youremail@example.com', 'bookit' );
97 + }
98 + if ( strlen( $full_name ) < 3 || strlen( $full_name ) > 25 ) {
99 + $errors['full_name'] = __( 'Full name must be between 3 and 25 characters long', 'bookit' );
100 + }
101 + if ( empty( $password ) ) {
102 + $errors['password'] = __( 'Please enter a password', 'bookit' );
103 + } elseif ( false !== strpos( $password, '\\' ) ) {
104 + $errors['password'] = __( "Passwords may not contain the character '\\'", 'bookit' );
105 + } elseif ( $password !== $confirm ) {
106 + $errors['password_confirmation'] = __( 'Please enter the same password in both password fields', 'bookit' );
107 + }
108 + if ( $errors ) {
109 + wp_send_json_error( array( 'errors' => $errors ) );
110 + }
111 +
112 + if ( get_user_by( 'email', $email ) ) {
113 + wp_send_json_error( array( 'message' => __( 'An account with this email already exists. Please log in.', 'bookit' ) ) );
114 + }
115 +
116 + $user_id = Customers::save_or_get_wp_user( array(
117 + 'email' => $email,
118 + 'password' => $password,
119 + 'full_name' => $full_name,
120 + 'role' => User::$customer_role,
121 + ) );
122 +
123 + // Never create or authenticate a privileged account through the booking form.
124 + if ( is_wp_error( $user_id ) || ! $user_id || user_can( $user_id, 'administrator' ) ) {
125 + wp_send_json_error( array( 'message' => __( 'Could not create your account. Please try again.', 'bookit' ) ) );
126 + }
127 +
128 + // Make the just-issued session available to wp_create_nonce() in this request.
129 + add_action( 'set_logged_in_cookie', array( self::class, 'sync_logged_in_cookie' ) );
130 +
131 + wp_clear_auth_cookie();
132 + wp_set_current_user( $user_id );
133 + wp_set_auth_cookie( $user_id );
134 +
135 + wp_send_json_success( self::auth_payload( get_user_by( 'id', $user_id ) ) );
136 + }
137 +
138 + /**
139 + * Expose the freshly-set login cookie to the rest of this request so nonces
140 + * are minted against the new session token (they are verified on the next
141 + * request, which carries that same cookie).
142 + *
143 + * @since 2.6.0
144 + *
145 + * @param string $logged_in_cookie
146 + */
147 + public static function sync_logged_in_cookie( $logged_in_cookie ) {
148 + $_COOKIE[ LOGGED_IN_COOKIE ] = $logged_in_cookie;
149 + }
150 +
151 + /**
152 + * Session-ready payload shared by login()/register(): the current user plus
153 + * freshly minted nonces for the authenticated session.
154 + *
155 + * @since 2.6.0
156 + *
157 + * @param \WP_User $user
158 + *
159 + * @return array
160 + */
161 + private static function auth_payload( $user ) {
162 + return array(
163 + 'user' => array(
164 + 'ID' => $user->ID,
165 + 'display_name' => $user->display_name,
166 + 'user_email' => $user->user_email,
167 + 'customer' => Customers::get( 'wp_user_id', $user->ID ),
168 + 'nonce' => wp_create_nonce( 'bookit_book_appointment' ),
169 + ),
170 + 'nonces' => Nonces::get_frontend_nonces(),
171 + );
172 + }
173 +
174 + /**
175 + * Reuse an existing unlinked customer only when every submitted contact
176 + * field matches, so repeat guest bookings do not create duplicate records.
177 + *
178 + * @since 2.6.0.2
179 + *
180 + * @param array $data Cleaned booking request data.
181 + *
182 + * @return object|null
183 + */
184 + private static function match_guest_customer( $data ) {
185 + // Only anonymous bookings are matched; a session always resolves to its own customer.
186 + if ( ! empty( $data['user_id'] ) ) {
187 + return null;
188 + }
189 +
190 + if ( empty( $data['full_name'] ) || empty( $data['email'] ) || empty( $data['phone'] ) ) {
191 + return null;
192 + }
193 +
194 + return Customers::get_by_contact( $data['full_name'], $data['email'], $data['phone'] );
195 + }
196 +
197 + /**
198 + * Save Customer
199 + *
200 + * @param array $data
201 + *
202 + * @return int
203 + */
58 204 private static function save( $data ) {
59 205 $insert = array(
60 206 'full_name' => $data['full_name'],
61 207 'wp_user_id' => $data['user_id'],
@@ -66,9 +212,16 @@
66 212
67 213 return Customers::insert_id();
68 214 }
69 215
70 - /** Update Customer if appear new data **/
216 + /**
217 + * Update Customer if appear new data
218 + *
219 + * @param int $id
220 + * @param array $data
221 + *
222 + * @return void
223 + */
71 224 private static function maybe_update( $id, $data ) {
72 225 $customer = Customers::get( 'id', $id );
73 226
74 227 if ( $customer->wp_user_id || $customer->wp_user_id == $data['wp_user_id'] ) {