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 +572 -37 1.5.4 → 2.4.5 View file →
@@ -1,20 +1,45 @@
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 {
14 27
15 - if (!wp_verify_nonce($request->get('_fsupport_signup_nonce'), 'fluent_support_signup_nonce')) {
16 - $this->sendError([
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([
17 42 'message' => __('Security verification failed. Please try again', 'fluent-support')
18 43 ]);
19 44 }
20 45
@@ -23,43 +48,187 @@
23 48 $rules = $this->getRules($fields);
24 49
25 50 $messages = $this->getMessages($rules);
26 51
52 + /*
53 + * Filter user signup form data
54 + *
55 + * @since v1.0.0
56 + * @param array $formData
57 + */
27 58 $formData = apply_filters('fluent_support/signup_form_data', $request->all());
28 59
29 - 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);
30 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 +
31 82 $this->validate($formData, $rules, $messages);
32 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 + */
33 174 do_action('fluent_support/after_signup_validation', $formData);
34 175
35 176 $userId = $this->createUser($formData);
36 177
37 - if (is_wp_error($userId)) {
178 + if (!$userId) {
38 179 return $this->response(
39 180 apply_filters(
40 181 'fluent_support/signup_create_user_error',
41 - ['error' => $userId->get_error_message()]
182 + ['error' => __('Could not create your account. The username or email address may already be registered.', 'fluent-support')]
42 183 ), 423);
43 184 }
44 185
186 + /*
187 + * Action After creating WP user from ticket sign up form
188 + *
189 + * @since v1.0.0
190 + */
45 191 do_action('fluent_support/after_creating_user');
46 192
47 193 $this->maybeUpdateUser($userId, $formData);
194 + $this->addUserMetaData($userId, $formData);
48 195 $this->assignRole($userId);
49 196 $this->login($userId);
50 197
51 - return $this->response(
52 - apply_filters('fluent_support/signup_complete_response', [
53 - 'message' => __('Successfully registered to the site.', 'fluent-support'),
54 - 'redirect' => Arr::get($formData, '__redirect_to', Helper::getPortalBaseUrl())
55 - ])
56 - );
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);
57 216 }
58 217
218 + /**
219 + * @param Request $request
220 + * @return \WP_REST_Response
221 + */
59 222 public function handleLogin(Request $request)
60 223 {
61 - if (!wp_verify_nonce($request->get('_support_login_nonce'), 'fsupport_login_nonce')) {
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')) {
62 231 return $this->response([
63 232 'message' => __('Security verification failed', 'fluent-support')
64 233 ], 403);
65 234 }
@@ -65,24 +234,37 @@
65 234 }
66 235
67 236 $data = $request->all();
68 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 +
69 249 if (empty($data['pwd']) || empty($data['log'])) {
70 250 return $this->response([
71 251 'message' => __('Email and Password is required', 'fluent-support')
72 252 ], 403);
73 253 }
74 -
75 254 $redirectUrl = Helper::getPortalBaseUrl();
255 + if ($redirect = $request->getSafe('redirect_to', 'sanitize_text_field')) {
256 + $redirectUrl = wp_validate_redirect($redirect, $redirectUrl);
257 + }
76 258
77 - if (get_current_user_id()) { // user already registered
259 + if (get_current_user_id()) { // already logged in
78 260 return $this->sendSuccess([
79 261 'redirect' => $redirectUrl
80 262 ]);
81 263 }
82 264
83 - $email = $data['log'];
84 - $password = $data['pwd'];
265 + $email = sanitize_user($data['log']);
266 + $password = trim($data['pwd'] ?? '');
85 267
86 268 if (is_email($email)) {
87 269 $user = get_user_by('email', $email);
88 270 } else {
@@ -88,25 +270,75 @@
88 270 } else {
89 271 $user = get_user_by('login', $email);
90 272 }
91 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 +
92 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 +
93 299 return $this->response([
94 300 'message' => __('Email or Password is not valid. Please try again', 'fluent-support')
95 301 ], 403);
302 +
96 303 }
97 304
98 - $info = array(
99 - 'user_login' => sanitize_text_field(trim($_POST['log'])),
100 - 'user_password' => trim($_POST['pwd']),
101 - 'remember' => isset($_POST['rememberme']),
102 - );
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);
103 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 +
104 319 if (apply_filters('fluent_support_use_native_login', true)) {
105 - return $this->nativeLoginHandler($user, $info, $redirectUrl);
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 + ]);
106 336 }
107 337
108 338 if (wp_check_password($password, $user->user_pass, $user->ID)) {
339 + delete_transient($ipKey);
340 + delete_transient($accountKey);
109 341 $this->login($user->ID);
110 342 return $this->sendSuccess([
111 343 'redirect' => $redirectUrl
112 344 ]);
@@ -111,13 +343,26 @@
111 343 'redirect' => $redirectUrl
112 344 ]);
113 345 }
114 346
347 + $this->incrementLoginAttempts($ipKey);
348 + $this->incrementLoginAttempts($accountKey);
349 +
115 350 return $this->response([
116 - 'message' => __('Email or Password is not valid. Please try again', 'fluent-support')
351 + 'message' => __('Invalid username, email address or incorrect password.', 'fluent-support')
117 352 ], 403);
118 353 }
119 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 +
120 365 private function nativeLoginHandler($user, $info, $redirectUrl = '')
121 366 {
122 367 if (!$redirectUrl) {
123 368 $redirectUrl = Helper::getPortalBaseUrl();
@@ -142,13 +387,15 @@
142 387 }
143 388
144 389 $user_signon = wp_signon($info, $secure_cookie);
145 390
391 + // Only checked for emptiness, so no sanitizing needed.
146 392 if (!is_wp_error($user_signon) && empty($_COOKIE[LOGGED_IN_COOKIE])) {
147 393 if (headers_sent()) {
148 394 return $this->response([
149 - '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>.'),
150 - __('https://codex.wordpress.org/Cookies'), __('https://wordpress.org/support/'))
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/')
151 398 ], 403);
152 399 }
153 400 }
154 401
@@ -180,8 +427,12 @@
180 427 'redirect' => $redirectUrl
181 428 ]);
182 429 }
183 430
431 + /**
432 + * @param array $fields
433 + * @return mixed
434 + */
184 435 protected function getRules($fields = [])
185 436 {
186 437 $rules = [];
187 438
@@ -197,69 +448,346 @@
197 448 } elseif ($field['type'] === 'password') {
198 449 $rules[$fieldName] = $rules[$fieldName] . $pipe . 'min:8';
199 450 }
200 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 + }
201 460
202 - 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();
203 594 }
204 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 + */
205 612 protected function getMessages($rules = [])
206 613 {
614 + /*
615 + * Filter user signup validation message
616 + *
617 + * @since v1.0.0
618 + * @param array $arg
619 + * @param array $rules
620 + */
207 621 return apply_filters('fluent_support/signup_validation_messages', [], $rules);
208 622 }
209 623
624 + /**
625 + * @param array $formData
626 + * @return int|false
627 + */
210 628 public function createUser($formData = [])
211 629 {
630 + /*
631 + * Filter user signup email
632 + *
633 + * @since v1.0.0
634 + * @param string $email
635 + */
212 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 + */
213 644 $userName = apply_filters('fluent_support/signup_username', Arr::get($formData, 'username'));
214 645
215 646 if (empty($formData['password'])) {
216 - $password = wp_generate_password(8);
647 + $password = wp_generate_password(16, true, true);
217 648 } else {
218 649 $password = $formData['password'];
219 650 }
220 651
652 + /*
653 + * Filter user signup password
654 + *
655 + * @since v1.0.0
656 + * @param string $password
657 + */
221 658 $password = apply_filters('fluent_support/signup_password', $password);
222 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 + */
223 668 do_action('fluent_support/before_creating_user', $userName, $password, $email);
224 669
225 - 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 +
226 678 }
227 679
680 + /**
681 + * Sets the name fields from first/last name, if given.
682 + *
683 + * @param int $userId
684 + * @param array $formData
685 + */
228 686 public function maybeUpdateUser($userId, $formData)
229 687 {
230 - $name = trim(Arr::get($formData, 'first_name') . ' ' . Arr::get($formData, 'last_name'));
688 + if (!$userId) {
689 + return;
690 + }
231 691
692 + $firstName = Arr::get($formData, 'first_name', '');
693 + $lastName = Arr::get($formData, 'last_name', '');
694 + $name = trim($firstName . ' ' . $lastName);
695 +
232 696 $data = array_filter([
233 - 'ID' => $userId,
697 + 'ID' => $userId,
234 698 'user_nicename' => $name,
235 - 'display_name' => $name,
236 - 'first_name' => Arr::get($formData, 'first_name'),
237 - 'last_name' => Arr::get($formData, 'last_name'),
699 + 'display_name' => $name,
700 + 'first_name' => $firstName,
701 + 'last_name' => $lastName,
238 702 ]);
239 703
240 704 if ($name) {
705 + /*
706 + * Action before updating a customer/user
707 + *
708 + * @since v1.0.0
709 + * @param array $data
710 + */
241 711 do_action('fluent_support/before_updating_user', $data);
242 712
243 - 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);
244 721
722 + /*
723 + * Action after updating a customer/user
724 + *
725 + * @since v1.0.0
726 + * @param array $data
727 + */
245 728 do_action('fluent_support/after_updating_user', $data);
246 729 }
247 730 }
248 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 + */
249 749 protected function assignRole($userId)
250 750 {
251 751 $user = new \WP_User($userId);
252 752
753 + /*
754 + * Action before assigning role to registered user
755 + *
756 + * @since v1.0.0
757 + * @param \WP_User $user
758 + */
253 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);
254 768
255 - $user->set_role(apply_filters('fluent_support/user_role', 'subscriber'));
256 -
769 + /*
770 + * Action after assigning role to registered user
771 + *
772 + * @since v1.0.0
773 + * @param \WP_User $user
774 + */
257 775 do_action('fluent_support/after_assigning_role', $user);
258 776 }
259 777
778 +
779 + /**
780 + * @param int $userId
781 + */
260 782 protected function login($userId)
261 783 {
784 + /*
785 + * Action before login
786 + *
787 + * @since v1.0.0
788 + * @param integer $userId
789 + */
262 790 do_action('fluent_support/before_logging_in_user', $userId);
263 791
264 792 wp_clear_auth_cookie();
265 793 wp_set_current_user($userId);
@@ -264,7 +792,14 @@
264 792 wp_clear_auth_cookie();
265 793 wp_set_current_user($userId);
266 794 wp_set_auth_cookie($userId);
267 795
796 + /*
797 + * Action after login
798 + *
799 + * @since v1.0.0
800 + * @param integer $userId
801 + */
268 802 do_action('fluent_support/after_logging_in_user', $userId);
269 803 }
804 +
270 805 }