PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 All 69 releases
← All changes | app/Http/Controllers/AuthController.php +690 -21 1.5.1 → 2.4.5 View file →
@@ -1,17 +1,49 @@
1 1 <?php
2 2
3 3 namespace FluentSupport\App\Http\Controllers;
4 4
5 +use FluentSupport\App\Models\Meta;
5 6 use FluentSupport\App\Services\Helper;
6 7 use FluentSupport\Framework\Support\Arr;
7 -use FluentSupport\Framework\Request\Request;
8 +use FluentSupport\Framework\Http\Request\Request;
8 9 use FluentSupport\App\Hooks\Handlers\AuthHandler;
10 +use FluentSupport\App\Hooks\Handlers\ReCaptchaHandler;
11 +use FluentSupport\App\Hooks\Handlers\TwoFaHandler;
12 +use FluentSupport\App\Hooks\Handlers\EmailVerificationHandler;
9 13
14 +
10 15 class AuthController extends Controller
11 16 {
17 + /**
18 + * Two steps: the first submit emails a verification code, the second
19 + * verifies it and creates the user.
20 + *
21 + * @param Request $request
22 + * @return \WP_REST_Response
23 + * @throws \FluentSupport\Framework\Validator\ValidationException
24 + */
12 25 public function signup(Request $request)
13 26 {
27 +
28 + if(Helper::getAuthProvider() !== 'fluent_support') {
29 + return $this->sendError([
30 + 'message' => __('You are not allowed to signup using this form', 'fluent-support')
31 + ]);
32 + }
33 +
34 + if (!Helper::isSignupEnabled()) {
35 + return $this->sendError([
36 + 'message' => __('User registration is not enabled on this site.', 'fluent-support')
37 + ], 403);
38 + }
39 +
40 + if (!wp_verify_nonce($request->getSafe('_fsupport_signup_nonce', 'sanitize_text_field'), 'fluent_support_signup_nonce')) {
41 + return $this->sendError([
42 + 'message' => __('Security verification failed. Please try again', 'fluent-support')
43 + ]);
44 + }
45 +
14 46 $fields = AuthHandler::getSignupFields();
15 47
16 48 $rules = $this->getRules($fields);
17 49
@@ -16,40 +48,391 @@
16 48 $rules = $this->getRules($fields);
17 49
18 50 $messages = $this->getMessages($rules);
19 51
52 + /*
53 + * Filter user signup form data
54 + *
55 + * @since v1.0.0
56 + * @param array $formData
57 + */
20 58 $formData = apply_filters('fluent_support/signup_form_data', $request->all());
21 59
22 - do_action('fluent_support/before_signup_validation', []);
60 + /*
61 + * Action before validate user signup
62 + *
63 + * @since v1.0.0
64 + * @param array $formData
65 + */
66 + do_action('fluent_support/before_signup_validation', $formData);
23 67
68 + // The captcha was already passed on the first step, and the second step is
69 + // gated by the issued verification record below.
70 + $isVerificationStep = !empty($formData['_email_verification_token']);
71 +
72 + $checkRecaptchaAvailability = ReCaptchaHandler::isRecaptchaApplicable('signup_form');
73 + if ($checkRecaptchaAvailability && !$isVerificationStep) {
74 + $validateCaptcha = ReCaptchaHandler::validateRecaptcha($formData['g-recaptcha-response'] ?? '', null, null, 'signup');
75 + if (!$validateCaptcha) {
76 + return $this->response([
77 + 'message' => __('Your recaptcha is not verified', 'fluent-support')
78 + ], 422);
79 + }
80 + }
81 +
24 82 $this->validate($formData, $rules, $messages);
25 83
84 + if (!$isVerificationStep) {
85 + $tokenHtml = EmailVerificationHandler::sendSignupEmailVerificationHtml($formData);
86 +
87 + return $this->response([
88 + 'verification_html' => $tokenHtml
89 + ]);
90 + } else {
91 + $token = $formData['_email_verification_token'];
92 + $verificationHash = $formData['_email_verification_hash'] ?? '';
93 +
94 + $logHashMeta = Meta::where('object_type', 'fs_login_hashes',)
95 + ->where('key', $verificationHash)
96 + ->first();
97 +
98 + if (!$logHashMeta) {
99 + wp_send_json([
100 + 'message' => __('Please provide a valid verification code that was sent to your email address', 'fluent-support')
101 + ], 422);
102 + }
103 +
104 + $logHash = Helper::safeUnserialize($logHashMeta->value);
105 +
106 + if (!$logHash) {
107 + wp_send_json([
108 + 'message' => __('Please provide a valid verification code that was sent to your email address', 'fluent-support')
109 + ], 422);
110 + }
111 +
112 + if (($logHash['status'] ?? '') !== 'issued') {
113 + wp_send_json([
114 + 'message' => __('Your verification code has already been used. Please try again', 'fluent-support')
115 + ], 422);
116 + }
117 +
118 + // Old or malformed records have no bound email.
119 + if (empty($logHash['email'])) {
120 + wp_send_json([
121 + 'message' => __('Your verification code has expired. Please request a new one', 'fluent-support')
122 + ], 422);
123 + }
124 +
125 + // valid_till is written with gmdate(). Parse it as UTC explicitly, since a plugin
126 + // may have changed the PHP default timezone.
127 + $validTill = $logHash['valid_till'] ?? '';
128 + if (($logHash['used_count'] ?? 0) > 5 || ($validTill && strtotime($validTill . ' UTC') < current_time('timestamp'))) {
129 + wp_send_json([
130 + 'message' => __('Your verification code has been expired. Please try again', 'fluent-support')
131 + ], 422);
132 + }
133 +
134 + if (!wp_check_password($token, $logHash['two_fa_code_hash'])) {
135 +
136 + $logHash['used_count'] += 1;
137 + Meta::where('key', $logHash['login_hash'])->update([
138 + 'value' => maybe_serialize($logHash)
139 + ]);
140 +
141 + wp_send_json([
142 + 'message' => __('Please provide a valid verification code that was sent to your email address', 'fluent-support')
143 + ], 422);
144 + }
145 +
146 + // Consume atomically: the update only matches if the record is unchanged since
147 + // we read it, so two concurrent requests can't both succeed.
148 + $consumed = Meta::where('key', $logHash['login_hash'])
149 + ->where('object_type', 'fs_login_hashes')
150 + ->where('value', $logHashMeta->value)
151 + ->update([
152 + 'value' => maybe_serialize(array_merge($logHash, [
153 + 'used_count' => ($logHash['used_count'] ?? 0) + 1,
154 + 'status' => 'used',
155 + ]))
156 + ]);
157 +
158 + if (!$consumed) {
159 + wp_send_json([
160 + 'message' => __('Your verification code has already been used. Please try again', 'fluent-support')
161 + ], 422);
162 + }
163 +
164 + // Use the address the code was issued to, not the submitted one.
165 + $formData['email'] = $logHash['email'];
166 + }
167 +
168 + /*
169 + * Action After validate user signup validation success
170 + *
171 + * @since v1.0.0
172 + * @param array $formData
173 + */
26 174 do_action('fluent_support/after_signup_validation', $formData);
27 175
28 176 $userId = $this->createUser($formData);
29 177
30 - if (is_wp_error($userId)) {
178 + if (!$userId) {
31 179 return $this->response(
32 180 apply_filters(
33 181 'fluent_support/signup_create_user_error',
34 - ['error' => $userId->get_error_message()]
182 + ['error' => __('Could not create your account. The username or email address may already be registered.', 'fluent-support')]
35 183 ), 423);
36 184 }
37 185
186 + /*
187 + * Action After creating WP user from ticket sign up form
188 + *
189 + * @since v1.0.0
190 + */
38 191 do_action('fluent_support/after_creating_user');
39 192
40 193 $this->maybeUpdateUser($userId, $formData);
194 + $this->addUserMetaData($userId, $formData);
41 195 $this->assignRole($userId);
42 196 $this->login($userId);
43 197
44 - return $this->response(
45 - apply_filters('fluent_support/signup_complete_response', [
46 - 'message' => __('Successfully registered to the site.', 'fluent-support'),
47 - 'redirect' => Arr::get($formData, '__redirect_to', Helper::getPortalBaseUrl())
48 - ])
49 - );
198 + /*
199 + * Filter for user signup complete message and redirect
200 + *
201 + * @since v1.0.0
202 + * @param array $response
203 + */
204 + $response = apply_filters('fluent_support/signup_complete_response', [
205 + 'message' => __('Successfully registered to the site.', 'fluent-support'),
206 + 'redirect' => Arr::get($formData, '__redirect_to', Helper::getPortalBaseUrl())
207 + ]);
208 +
209 + // The browser navigates to this by script; keep it on this site.
210 + if (!empty($response['redirect'])) {
211 + $portalUrl = Helper::getPortalBaseUrl();
212 + $response['redirect'] = wp_validate_redirect(esc_url_raw($response['redirect']), $portalUrl) ?: $portalUrl;
213 + }
214 +
215 + return $this->response($response);
50 216 }
51 217
218 + /**
219 + * @param Request $request
220 + * @return \WP_REST_Response
221 + */
222 + public function handleLogin(Request $request)
223 + {
224 + if(Helper::getAuthProvider() !== 'fluent_support') {
225 + return $this->sendError([
226 + 'message' => __('You are not allowed to login using this form', 'fluent-support')
227 + ]);
228 + }
229 +
230 + if (!wp_verify_nonce($request->getSafe('_support_login_nonce', 'sanitize_text_field'), 'fsupport_login_nonce')) {
231 + return $this->response([
232 + 'message' => __('Security verification failed', 'fluent-support')
233 + ], 403);
234 + }
235 +
236 + $data = $request->all();
237 +
238 + $checkRecaptchaAvailability = ReCaptchaHandler::isRecaptchaApplicable('login_form');
239 + if ($checkRecaptchaAvailability) {
240 + $validateCaptcha = ReCaptchaHandler::validateRecaptcha($data['g-recaptcha-response'] ?? '', null, null, 'login');
241 +
242 + if (!$validateCaptcha) {
243 + return $this->response([
244 + 'message' => __('Your recaptcha is not verified', 'fluent-support')
245 + ], 422);
246 + }
247 + }
248 +
249 + if (empty($data['pwd']) || empty($data['log'])) {
250 + return $this->response([
251 + 'message' => __('Email and Password is required', 'fluent-support')
252 + ], 403);
253 + }
254 + $redirectUrl = Helper::getPortalBaseUrl();
255 + if ($redirect = $request->getSafe('redirect_to', 'sanitize_text_field')) {
256 + $redirectUrl = wp_validate_redirect($redirect, $redirectUrl);
257 + }
258 +
259 + if (get_current_user_id()) { // already logged in
260 + return $this->sendSuccess([
261 + 'redirect' => $redirectUrl
262 + ]);
263 + }
264 +
265 + $email = sanitize_user($data['log']);
266 + $password = trim($data['pwd'] ?? '');
267 +
268 + if (is_email($email)) {
269 + $user = get_user_by('email', $email);
270 + } else {
271 + $user = get_user_by('login', $email);
272 + }
273 +
274 + // 5 attempts per account+IP, 20 per account.
275 + $ip = Helper::getIp();
276 + $ipKey = $user
277 + ? 'fs_login_ip_' . wp_hash($user->ID . '|' . $ip)
278 + : 'fs_login_ip_' . wp_hash(strtolower($email) . '|' . $ip);
279 + $accountKey = $user
280 + ? 'fs_login_act_' . wp_hash($user->ID)
281 + : 'fs_login_act_' . wp_hash(strtolower($email));
282 +
283 + $ipAttempts = get_transient($ipKey);
284 + $accountAttempts = get_transient($accountKey);
285 +
286 + if (($ipAttempts !== false && $ipAttempts >= 5) || ($accountAttempts !== false && $accountAttempts >= 20)) {
287 + return $this->sendError([
288 + 'message' => __('Too many login attempts. Please try again after 15 minutes.', 'fluent-support')
289 + ], 429);
290 + }
291 +
292 + if (!$user) {
293 + $user = new \WP_Error('authentication_failed', __('Invalid username, email address or incorrect password.', 'fluent-support'));
294 +
295 + do_action('wp_login_failed', $email, $user);
296 + $this->incrementLoginAttempts($ipKey);
297 + $this->incrementLoginAttempts($accountKey);
298 +
299 + return $this->response([
300 + 'message' => __('Email or Password is not valid. Please try again', 'fluent-support')
301 + ], 403);
302 +
303 + }
304 +
305 + $twoFactorEnabled = Helper::getBusinessSettings('enable_two_fa');
306 + if ('yes' === $twoFactorEnabled) {
307 + if (!wp_check_password($password, $user->user_pass, $user->ID)) {
308 + $this->incrementLoginAttempts($ipKey);
309 + $this->incrementLoginAttempts($accountKey);
310 +
311 + return $this->response([
312 + 'message' => __('Invalid username, email address or incorrect password.', 'fluent-support')
313 + ], 403);
314 + }
315 +
316 + (new TwoFaHandler)->maybe2FaRedirect($user);
317 + }
318 +
319 + if (apply_filters('fluent_support_use_native_login', true)) {
320 + $user = wp_signon();
321 + if (is_wp_error($user)) {
322 + $this->incrementLoginAttempts($ipKey);
323 + $this->incrementLoginAttempts($accountKey);
324 + return $this->response([
325 + 'message' => $user->get_error_message()
326 + ], 403);
327 + }
328 +
329 + $authIpKey = 'fs_login_ip_' . wp_hash($user->ID . '|' . $ip);
330 + $authAccountKey = 'fs_login_act_' . wp_hash($user->ID);
331 + delete_transient($authIpKey);
332 + delete_transient($authAccountKey);
333 + return $this->sendSuccess([
334 + 'redirect' => $redirectUrl
335 + ]);
336 + }
337 +
338 + if (wp_check_password($password, $user->user_pass, $user->ID)) {
339 + delete_transient($ipKey);
340 + delete_transient($accountKey);
341 + $this->login($user->ID);
342 + return $this->sendSuccess([
343 + 'redirect' => $redirectUrl
344 + ]);
345 + }
346 +
347 + $this->incrementLoginAttempts($ipKey);
348 + $this->incrementLoginAttempts($accountKey);
349 +
350 + return $this->response([
351 + 'message' => __('Invalid username, email address or incorrect password.', 'fluent-support')
352 + ], 403);
353 + }
354 +
355 + private function incrementLoginAttempts($rateLimitKey)
356 + {
357 + $attempts = get_transient($rateLimitKey);
358 + if ($attempts === false) {
359 + set_transient($rateLimitKey, 1, 15 * MINUTE_IN_SECONDS);
360 + } else {
361 + set_transient($rateLimitKey, $attempts + 1, 15 * MINUTE_IN_SECONDS);
362 + }
363 + }
364 +
365 + private function nativeLoginHandler($user, $info, $redirectUrl = '')
366 + {
367 + if (!$redirectUrl) {
368 + $redirectUrl = Helper::getPortalBaseUrl();
369 + }
370 +
371 + $secure_cookie = is_ssl();
372 + if (!$secure_cookie && !force_ssl_admin()) {
373 + if (get_user_option('use_ssl', $user->ID)) {
374 + $secure_cookie = true;
375 + force_ssl_admin(true);
376 + }
377 + }
378 +
379 + if (class_exists('\Limit_Login_Attempts')) {
380 + global $limit_login_attempts_obj;
381 + $limit_login_attempts_try = $limit_login_attempts_obj->wp_authenticate_user($user, false);
382 + if (is_wp_error($limit_login_attempts_try)) {
383 + return $this->response([
384 + 'message' => implode('<br/>', $limit_login_attempts_try->get_error_messages())
385 + ], 403);
386 + }
387 + }
388 +
389 + $user_signon = wp_signon($info, $secure_cookie);
390 +
391 + // Only checked for emptiness, so no sanitizing needed.
392 + if (!is_wp_error($user_signon) && empty($_COOKIE[LOGGED_IN_COOKIE])) {
393 + if (headers_sent()) {
394 + return $this->response([
395 + // translators: %1$s is the URL to WordPress cookies documentation, %2$s is the URL to WordPress support forums
396 + 'message' => sprintf(__('<strong>ERROR</strong>: Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.', 'fluent-support'),
397 + 'https://codex.wordpress.org/Cookies', 'https://wordpress.org/support/')
398 + ], 403);
399 + }
400 + }
401 +
402 + if (is_wp_error($user_signon)) {
403 + $errorMessage = __('Email or Password is not valid. Please try again', 'fluent-support');
404 +
405 + if (class_exists('Limit_Login_Attempts')) {
406 + global $limit_login_attempts_obj;
407 + if ($limit_login_attempts_obj) {
408 + $limit_login_attempts_obj->limit_login_failed($user->user_login);
409 + $msg = $limit_login_attempts_obj->get_message();
410 + if ($msg) {
411 + $errorMessage = $msg;
412 + }
413 + }
414 + }
415 +
416 + return $this->response([
417 + 'message' => $errorMessage
418 + ], 403);
419 + }
420 +
421 + // WP Last Login plugin compatibility
422 + if (class_exists('\Obenland_Wp_Last_Login')) {
423 + update_user_meta($user_signon->ID, 'wp-last-login', time());
424 + }
425 +
426 + return $this->sendSuccess([
427 + 'redirect' => $redirectUrl
428 + ]);
429 + }
430 +
431 + /**
432 + * @param array $fields
433 + * @return mixed
434 + */
52 435 protected function getRules($fields = [])
53 436 {
54 437 $rules = [];
55 438
@@ -65,67 +448,346 @@
65 448 } elseif ($field['type'] === 'password') {
66 449 $rules[$fieldName] = $rules[$fieldName] . $pipe . 'min:8';
67 450 }
68 451 }
452 + /*
453 + * Filter user signup validation rules
454 + *
455 + * @since v1.0.0
456 + * @param array $rules
457 + */
458 + return apply_filters('fluent_support/signup_validation_rules', $rules);
459 + }
69 460
70 - return apply_filters('fluent_support/signup_validation_rules', $rules);
461 +
462 + public function resetPassword(Request $request)
463 + {
464 +
465 + if(Helper::getAuthProvider() !== 'fluent_support') {
466 + return $this->sendError([
467 + 'message' => __('You are not allowed to reset password using this form', 'fluent-support')
468 + ]);
469 + }
470 +
471 + $errors = new \WP_Error();
472 +
473 + if (!wp_verify_nonce($request->getSafe('_fsupport_reset_pass_nonce', 'sanitize_text_field'), 'fluent_support_reset_pass_nonce')) {
474 + return $this->sendError([
475 + 'message' => __('Security verification failed. Please try again', 'fluent-support')
476 + ]);
477 + }
478 +
479 + $usernameOrEmail = trim(wp_unslash($request->getSafe('user_login', 'sanitize_text_field')));
480 +
481 + if (!$usernameOrEmail) {
482 + return $this->sendError([
483 + 'message' => __('Username or email is required.', 'fluent-support')
484 + ]);
485 + }
486 +
487 + // Generous because of shared NAT IPs. Runs before the account lookup so probes for
488 + // missing accounts are throttled too, and a 429 reveals nothing about existence.
489 + if (Helper::hitRateLimit('fs_reset_pass_ip_' . wp_hash(Helper::getIp()), 20)) {
490 + return $this->sendError([
491 + 'message' => __('Too many password reset requests. Please try again after 15 minutes.', 'fluent-support')
492 + ], 429);
493 + }
494 +
495 + $user_data = get_user_by('email', $usernameOrEmail);
496 +
497 + if (!$user_data) {
498 + $user_data = get_user_by('login', $usernameOrEmail);
499 + }
500 +
501 + if (!$user_data) {
502 + return $this->sendResetPassResponse();
503 + }
504 +
505 + $user_data = apply_filters('lostpassword_user_data', $user_data, $errors);
506 +
507 + do_action('lostpassword_post', $errors, $user_data);
508 +
509 + $errors = apply_filters('lostpassword_errors', $errors, $user_data);
510 +
511 + if ($errors->has_errors()) {
512 + return $this->sendResetPassResponse();
513 + }
514 +
515 + if (!$user_data) {
516 + return $this->sendResetPassResponse();
517 + }
518 +
519 + if (is_multisite() && !is_user_member_of_blog($user_data->ID, get_current_blog_id())) {
520 + return $this->sendResetPassResponse();
521 + }
522 +
523 + // Redefining user_login ensures we return the right case in the email.
524 + $user_login = $user_data->user_login;
525 +
526 + do_action('retrieve_password', $user_login);
527 +
528 + $allow = apply_filters('allow_password_reset', true, $user_data->ID);
529 +
530 + if (!$allow || is_wp_error($allow)) {
531 + return $this->sendResetPassResponse();
532 + }
533 +
534 +
535 + /*
536 + * Filter reset password link text
537 + *
538 + * @since v1.5.7
539 + * @param string $linkText
540 + */
541 + // translators: %s is the site name
542 + $linkText = apply_filters("fluent_support/reset_password_link", sprintf(__('Reset your password for %s', 'fluent-support'), get_bloginfo('name')));
543 +
544 + // get_password_reset_key() invalidates the previous link, so repeated requests could
545 + // block recovery. The owner already has a working link from the first send.
546 + $cooldownKey = 'fs_reset_pass_sent_' . wp_hash($user_data->ID);
547 +
548 + if (get_transient($cooldownKey)) {
549 + return $this->sendResetPassResponse();
550 + }
551 +
552 + set_transient($cooldownKey, 1, 5 * MINUTE_IN_SECONDS);
553 +
554 + $resetUrl = add_query_arg([
555 + 'action' => 'rp',
556 + 'key' => get_password_reset_key($user_data),
557 + 'login' => rawurlencode($user_data->user_login)
558 + ], wp_login_url());
559 +
560 + $resetLink = '<a href="' . $resetUrl . '">' . $linkText . '</a>';
561 +
562 + /*
563 + * Filter reset password email subject
564 + *
565 + * @since v1.5.7
566 + * @param string $mailSubject
567 + */
568 + // translators: %s is the site name
569 + $mailSubject = apply_filters("fluent_support/reset_password_mail_subject", sprintf(__('Reset your password for %s support portal', 'fluent-support'), get_bloginfo('name')));
570 +
571 + // translators: %s is the user's first name
572 + $message = '<p>' . sprintf(__('Hi %s,', 'fluent-support'), $user_data->first_name) . '</p>' .
573 + '<p>' . __('Someone has requested a new password for the following account on WordPress:', 'fluent-support') . '</p>' .
574 + // translators: %s is the username
575 + '<p>' . sprintf(__('Username: %s', 'fluent-support'), $user_login) . '</p>' .
576 + '<p>' . $resetLink . '</p>' .
577 + '<p>' . __('If you did not request to reset your password, please ignore this email.', 'fluent-support') . '</p>';
578 +
579 + /*
580 + * Filter reset password email body text
581 + *
582 + * @since v1.5.7
583 + * @param string $message
584 + * @param object $user
585 + * @param string $resetLink
586 + */
587 + $message = apply_filters('fluent_support/reset_password_message', $message, $user_data, $resetLink);
588 +
589 + $headers = array('Content-Type: text/html; charset=UTF-8');
590 +
591 + wp_mail($user_data->user_email, $mailSubject, $message, $headers);
592 +
593 + return $this->sendResetPassResponse();
71 594 }
72 595
596 + /**
597 + * Same response for every outcome, so the form can't confirm which accounts exist.
598 + *
599 + * @return mixed
600 + */
601 + protected function sendResetPassResponse()
602 + {
603 + return $this->sendSuccess([
604 + 'message' => __('If an account matches that username or email, a password reset link has been sent. Please check your inbox, including the spam folder.', 'fluent-support')
605 + ]);
606 + }
607 +
608 + /**
609 + * @param array $rules
610 + * @return mixed
611 + */
73 612 protected function getMessages($rules = [])
74 613 {
614 + /*
615 + * Filter user signup validation message
616 + *
617 + * @since v1.0.0
618 + * @param array $arg
619 + * @param array $rules
620 + */
75 621 return apply_filters('fluent_support/signup_validation_messages', [], $rules);
76 622 }
77 623
78 - protected function createUser($formData = [])
624 + /**
625 + * @param array $formData
626 + * @return int|false
627 + */
628 + public function createUser($formData = [])
79 629 {
630 + /*
631 + * Filter user signup email
632 + *
633 + * @since v1.0.0
634 + * @param string $email
635 + */
80 636 $email = apply_filters('fluent_support/signup_email', Arr::get($formData, 'email'));
637 +
638 + /*
639 + * Filter user signup username
640 + *
641 + * @since v1.0.0
642 + * @param string $username
643 + */
81 644 $userName = apply_filters('fluent_support/signup_username', Arr::get($formData, 'username'));
82 645
83 646 if (empty($formData['password'])) {
84 - $password = wp_generate_password(8);
647 + $password = wp_generate_password(16, true, true);
85 648 } else {
86 649 $password = $formData['password'];
87 650 }
88 651
652 + /*
653 + * Filter user signup password
654 + *
655 + * @since v1.0.0
656 + * @param string $password
657 + */
89 658 $password = apply_filters('fluent_support/signup_password', $password);
90 659
660 + /*
661 + * Action before creating WP user using Fluent Support signup form
662 + *
663 + * @since v1.0.0
664 + * @param string $userName
665 + * @param string $password
666 + * @param string $email
667 + */
91 668 do_action('fluent_support/before_creating_user', $userName, $password, $email);
92 669
93 - return wp_create_user($userName, $password, $email);
670 + $userId = wp_create_user($userName, $password, $email);
671 +
672 + if (is_wp_error($userId)) {
673 + return false;
674 + }
675 +
676 + return $userId;
677 +
94 678 }
95 679
96 - protected function maybeUpdateUser($userId, $formData)
680 + /**
681 + * Sets the name fields from first/last name, if given.
682 + *
683 + * @param int $userId
684 + * @param array $formData
685 + */
686 + public function maybeUpdateUser($userId, $formData)
97 687 {
98 - $name = trim(Arr::get($formData, 'first_name') . ' ' . Arr::get($formData, 'last_name'));
688 + if (!$userId) {
689 + return;
690 + }
99 691
692 + $firstName = Arr::get($formData, 'first_name', '');
693 + $lastName = Arr::get($formData, 'last_name', '');
694 + $name = trim($firstName . ' ' . $lastName);
695 +
100 696 $data = array_filter([
101 - 'ID' => $userId,
697 + 'ID' => $userId,
102 698 'user_nicename' => $name,
103 - 'display_name' => $name
699 + 'display_name' => $name,
700 + 'first_name' => $firstName,
701 + 'last_name' => $lastName,
104 702 ]);
105 703
106 704 if ($name) {
705 + /*
706 + * Action before updating a customer/user
707 + *
708 + * @since v1.0.0
709 + * @param array $data
710 + */
107 711 do_action('fluent_support/before_updating_user', $data);
108 712
109 - wp_update_user(apply_filters('fluent_support/update_user_data', $data));
713 + /*
714 + * Filter user updatable data
715 + *
716 + * @since v1.0.0
717 + * @param $data
718 + */
719 + $updateUserData = apply_filters('fluent_support/update_user_data', $data);
720 + wp_update_user($updateUserData);
110 721
722 + /*
723 + * Action after updating a customer/user
724 + *
725 + * @since v1.0.0
726 + * @param array $data
727 + */
111 728 do_action('fluent_support/after_updating_user', $data);
112 729 }
113 730 }
114 731
732 + public function addUserMetaData($userId, $formData) {
733 + $customFieldsKey = Helper::getCustomRegistrationFieldKeys();
734 +
735 + if (empty($customFieldsKey)) {
736 + return;
737 + }
738 +
739 + foreach ($customFieldsKey as $key) {
740 + if (isset($formData[$key]) && is_scalar($formData[$key])) {
741 + update_user_meta($userId, $key, sanitize_text_field($formData[$key]));
742 + }
743 + }
744 + }
745 +
746 + /**
747 + * @param int $userId
748 + */
115 749 protected function assignRole($userId)
116 750 {
117 751 $user = new \WP_User($userId);
118 752
753 + /*
754 + * Action before assigning role to registered user
755 + *
756 + * @since v1.0.0
757 + * @param \WP_User $user
758 + */
119 759 do_action('fluent_support/before_assigning_role', $user);
760 + /*
761 + * Filter user assignable role after signup
762 + *
763 + * @since v1.0.0
764 + * @param string $setRole WordPress user role key
765 + */
766 + $setRole = apply_filters('fluent_support/user_role', 'subscriber');
767 + $user->set_role($setRole);
120 768
121 - $user->set_role(apply_filters('fluent_support/user_role', 'subscriber'));
122 -
769 + /*
770 + * Action after assigning role to registered user
771 + *
772 + * @since v1.0.0
773 + * @param \WP_User $user
774 + */
123 775 do_action('fluent_support/after_assigning_role', $user);
124 776 }
125 777
778 +
779 + /**
780 + * @param int $userId
781 + */
126 782 protected function login($userId)
127 783 {
784 + /*
785 + * Action before login
786 + *
787 + * @since v1.0.0
788 + * @param integer $userId
789 + */
128 790 do_action('fluent_support/before_logging_in_user', $userId);
129 791
130 792 wp_clear_auth_cookie();
131 793 wp_set_current_user($userId);
@@ -130,7 +792,14 @@
130 792 wp_clear_auth_cookie();
131 793 wp_set_current_user($userId);
132 794 wp_set_auth_cookie($userId);
133 795
796 + /*
797 + * Action after login
798 + *
799 + * @since v1.0.0
800 + * @param integer $userId
801 + */
134 802 do_action('fluent_support/after_logging_in_user', $userId);
135 803 }
804 +
136 805 }