PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.0
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.0
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 1.5.5 All 68 releases
← All changes | app/Http/Controllers/AuthController.php +697 -19 1.5.02.4.0 View file →
@@ -1,17 +1,41 @@
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 + * signUp method will create new user submitted data from sign up form
19 + * @param Request $request
20 + * @return \WP_REST_Response
21 + * @throws \FluentSupport\Framework\Validator\ValidationException
22 + */
12 23 public function signup(Request $request)
13 24 {
25 +
26 + if(Helper::getAuthProvider() !== 'fluent_support') {
27 + return $this->sendError([
28 + 'message' => __('You are not allowed to signup using this form', 'fluent-support')
29 + ]);
30 + }
31 +
32 + if (!wp_verify_nonce($request->getSafe('_fsupport_signup_nonce', 'sanitize_text_field'), 'fluent_support_signup_nonce')) {
33 + return $this->sendError([
34 + 'message' => __('Security verification failed. Please try again', 'fluent-support')
35 + ]);
36 + }
37 +
14 38 $fields = AuthHandler::getSignupFields();
15 39
16 40 $rules = $this->getRules($fields);
17 41
@@ -16,14 +40,140 @@
16 40 $rules = $this->getRules($fields);
17 41
18 42 $messages = $this->getMessages($rules);
19 43
44 + /*
45 + * Filter user signup form data
46 + *
47 + * @since v1.0.0
48 + * @param array $formData
49 + */
20 50 $formData = apply_filters('fluent_support/signup_form_data', $request->all());
21 51
22 - do_action('fluent_support/before_signup_validation', []);
52 + /*
53 + * Action before validate user signup
54 + *
55 + * @since v1.0.0
56 + * @param array $formData
57 + */
58 + do_action('fluent_support/before_signup_validation', $formData);
23 59
60 + // the verification code is only submitted on the second step, after the customer has
61 + // already passed the captcha and received the email; that step validates the hash
62 + // against an issued record below, so the captcha can be skipped there. The first
63 + // submit (which sends the verification email) always has to pass the captcha.
64 + $isVerificationStep = !empty($formData['_email_verification_token']);
65 +
66 + $checkRecaptchaAvailability = ReCaptchaHandler::isRecaptchaApplicable('signup_form');
67 + if ($checkRecaptchaAvailability && !$isVerificationStep) {
68 + $validateCaptcha = ReCaptchaHandler::validateRecaptcha($formData['g-recaptcha-response'] ?? '', null, null, 'signup');
69 + if (!$validateCaptcha) {
70 + return $this->response([
71 + 'message' => __('Your recaptcha is not verified', 'fluent-support')
72 + ], 422);
73 + }
74 + }
75 +
24 76 $this->validate($formData, $rules, $messages);
25 77
78 + if (!$isVerificationStep) {
79 + $tokenHtml = EmailVerificationHandler::sendSignupEmailVerificationHtml($formData);
80 +
81 + return $this->response([
82 + 'verification_html' => $tokenHtml
83 + ]);
84 + } else {
85 + $token = $formData['_email_verification_token'];
86 + $verificationHash = $formData['_email_verification_hash'] ?? '';
87 +
88 + $logHashMeta = Meta::where('object_type', 'fs_login_hashes',)
89 + ->where('key', $verificationHash)
90 + ->first();
91 +
92 + if (!$logHashMeta) {
93 + wp_send_json([
94 + 'message' => __('Please provide a valid verification code that was sent to your email address', 'fluent-support')
95 + ], 422);
96 + }
97 +
98 + $logHash = Helper::safeUnserialize($logHashMeta->value);
99 +
100 + if (!$logHash) {
101 + wp_send_json([
102 + 'message' => __('Please provide a valid verification code that was sent to your email address', 'fluent-support')
103 + ], 422);
104 + }
105 +
106 + // the code must still be unused and must not have been consumed by a prior request
107 + if (($logHash['status'] ?? '') !== 'issued') {
108 + wp_send_json([
109 + 'message' => __('Your verification code has already been used. Please try again', 'fluent-support')
110 + ], 422);
111 + }
112 +
113 + // records created before the email-binding fix (or any other legacy/malformed record)
114 + // have no bound email; treat them as invalid rather than proceeding with a null email
115 + if (empty($logHash['email'])) {
116 + wp_send_json([
117 + 'message' => __('Your verification code has expired. Please request a new one', 'fluent-support')
118 + ], 422);
119 + }
120 +
121 + // check if it got expired or not
122 + // valid_till is written via gmdate() on a current_time('timestamp') basis (always
123 + // UTC-equivalent, since WP resets the runtime timezone to UTC on every request), so
124 + // it must be parsed back as UTC here - otherwise strtotime() would silently reinterpret
125 + // it under whatever timezone a plugin/theme may have switched to via
126 + // date_default_timezone_set() without restoring it, causing false expiry (or non-expiry)
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 + // atomically consume the code: only succeeds if the record is still in the exact
147 + // state we just read, closing the race where two requests both pass the checks above
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 + // the email is now server-verified for this code; ignore whatever the client
165 + // submitted and use the address the code was actually issued to, so the signup
166 + // can never be completed against a different (e.g. victim's) email address
167 + $formData['email'] = $logHash['email'];
168 + }
169 +
170 + /*
171 + * Action After validate user signup validation success
172 + *
173 + * @since v1.0.0
174 + * @param array $formData
175 + */
26 176 do_action('fluent_support/after_signup_validation', $formData);
27 177
28 178 $userId = $this->createUser($formData);
29 179
@@ -34,22 +184,255 @@
34 184 ['error' => $userId->get_error_message()]
35 185 ), 423);
36 186 }
37 187
188 + /*
189 + * Action After creating WP user from ticket sign up form
190 + *
191 + * @since v1.0.0
192 + * @param array $formData
193 + */
38 194 do_action('fluent_support/after_creating_user');
39 195
40 196 $this->maybeUpdateUser($userId, $formData);
197 + $this->addUserMetaData($userId, $formData);
41 198 $this->assignRole($userId);
42 199 $this->login($userId);
43 200
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 - );
201 + /*
202 + * Filter for user signup complete message and redirect
203 + *
204 + * @since v1.0.0
205 + * @param array $response
206 + */
207 + $response = apply_filters('fluent_support/signup_complete_response', [
208 + 'message' => __('Successfully registered to the site.', 'fluent-support'),
209 + 'redirect' => Arr::get($formData, '__redirect_to', Helper::getPortalBaseUrl())
210 + ]);
211 +
212 + return $this->response($response);
50 213 }
51 214
215 + /**
216 + * handleLogin method will perform login functionality and redirect
217 + * @param Request $request
218 + * @return \WP_REST_Response
219 + */
220 + public function handleLogin(Request $request)
221 + {
222 + if(Helper::getAuthProvider() !== 'fluent_support') {
223 + return $this->sendError([
224 + 'message' => __('You are not allowed to login using this form', 'fluent-support')
225 + ]);
226 + }
227 +
228 + if (!wp_verify_nonce($request->getSafe('_support_login_nonce', 'sanitize_text_field'), 'fsupport_login_nonce')) {
229 + return $this->response([
230 + 'message' => __('Security verification failed', 'fluent-support')
231 + ], 403);
232 + }
233 +
234 + $data = $request->all();
235 +
236 + $checkRecaptchaAvailability = ReCaptchaHandler::isRecaptchaApplicable('login_form');
237 + if ($checkRecaptchaAvailability) {
238 + $validateCaptcha = ReCaptchaHandler::validateRecaptcha($data['g-recaptcha-response'] ?? '', null, null, 'login');
239 +
240 + if (!$validateCaptcha) {
241 + return $this->response([
242 + 'message' => __('Your recaptcha is not verified', 'fluent-support')
243 + ], 422);
244 + }
245 + }
246 +
247 + if (empty($data['pwd']) || empty($data['log'])) {
248 + return $this->response([
249 + 'message' => __('Email and Password is required', 'fluent-support')
250 + ], 403);
251 + }
252 + $redirectUrl = Helper::getPortalBaseUrl();
253 + if ($redirect = $request->getSafe('redirect_to', 'sanitize_text_field')) {
254 + $redirectUrl = wp_validate_redirect($redirect, $redirectUrl);
255 + }
256 +
257 + if (get_current_user_id()) { // user already registered
258 + return $this->sendSuccess([
259 + 'redirect' => $redirectUrl
260 + ]);
261 + }
262 +
263 + $email = sanitize_user($data['log']);
264 + $password = trim($data['pwd'] ?? '');
265 +
266 + if (is_email($email)) {
267 + $user = get_user_by('email', $email);
268 + } else {
269 + $user = get_user_by('login', $email);
270 + }
271 +
272 + // Rate limiting: per-IP bucket (5 attempts) + per-account bucket (20 attempts)
273 + $ip = Helper::getIp();
274 + $ipKey = $user
275 + ? 'fs_login_ip_' . wp_hash($user->ID . '|' . $ip)
276 + : 'fs_login_ip_' . wp_hash(strtolower($email) . '|' . $ip);
277 + $accountKey = $user
278 + ? 'fs_login_act_' . wp_hash($user->ID)
279 + : 'fs_login_act_' . wp_hash(strtolower($email));
280 +
281 + $ipAttempts = get_transient($ipKey);
282 + $accountAttempts = get_transient($accountKey);
283 +
284 + if (($ipAttempts !== false && $ipAttempts >= 5) || ($accountAttempts !== false && $accountAttempts >= 20)) {
285 + return $this->sendError([
286 + 'message' => __('Too many login attempts. Please try again after 15 minutes.', 'fluent-support')
287 + ], 429);
288 + }
289 +
290 + if (!$user) {
291 + $user = new \WP_Error('authentication_failed', __('Invalid username, email address or incorrect password.', 'fluent-support'));
292 +
293 + do_action('wp_login_failed', $email, $user);
294 + $this->incrementLoginAttempts($ipKey);
295 + $this->incrementLoginAttempts($accountKey);
296 +
297 + return $this->response([
298 + 'message' => __('Email or Password is not valid. Please try again', 'fluent-support')
299 + ], 403);
300 +
301 + }
302 +
303 + $twoFactorEnabled = Helper::getBusinessSettings('enable_two_fa');
304 + if ('yes' === $twoFactorEnabled) {
305 + if (!wp_check_password($password, $user->user_pass, $user->ID)) {
306 + $this->incrementLoginAttempts($ipKey);
307 + $this->incrementLoginAttempts($accountKey);
308 +
309 + return $this->response([
310 + 'message' => __('Invalid username, email address or incorrect password.', 'fluent-support')
311 + ], 403);
312 + }
313 +
314 + (new TwoFaHandler)->maybe2FaRedirect($user);
315 + }
316 +
317 + if (apply_filters('fluent_support_use_native_login', true)) {
318 + $user = wp_signon();
319 + if (is_wp_error($user)) {
320 + $this->incrementLoginAttempts($ipKey);
321 + $this->incrementLoginAttempts($accountKey);
322 + return $this->response([
323 + 'message' => $user->get_error_message()
324 + ], 403);
325 + }
326 +
327 + // Clear rate limits for the authenticated user
328 + $authIpKey = 'fs_login_ip_' . wp_hash($user->ID . '|' . $ip);
329 + $authAccountKey = 'fs_login_act_' . wp_hash($user->ID);
330 + delete_transient($authIpKey);
331 + delete_transient($authAccountKey);
332 + return $this->sendSuccess([
333 + 'redirect' => $redirectUrl
334 + ]);
335 + }
336 +
337 + if (wp_check_password($password, $user->user_pass, $user->ID)) {
338 + delete_transient($ipKey);
339 + delete_transient($accountKey);
340 + $this->login($user->ID);
341 + return $this->sendSuccess([
342 + 'redirect' => $redirectUrl
343 + ]);
344 + }
345 +
346 + $this->incrementLoginAttempts($ipKey);
347 + $this->incrementLoginAttempts($accountKey);
348 +
349 + return $this->response([
350 + 'message' => __('Invalid username, email address or incorrect password.', 'fluent-support')
351 + ], 403);
352 + }
353 +
354 + private function incrementLoginAttempts($rateLimitKey)
355 + {
356 + $attempts = get_transient($rateLimitKey);
357 + if ($attempts === false) {
358 + set_transient($rateLimitKey, 1, 15 * MINUTE_IN_SECONDS);
359 + } else {
360 + set_transient($rateLimitKey, $attempts + 1, 15 * MINUTE_IN_SECONDS);
361 + }
362 + }
363 +
364 + private function nativeLoginHandler($user, $info, $redirectUrl = '')
365 + {
366 + if (!$redirectUrl) {
367 + $redirectUrl = Helper::getPortalBaseUrl();
368 + }
369 +
370 + $secure_cookie = is_ssl();
371 + if (!$secure_cookie && !force_ssl_admin()) {
372 + if (get_user_option('use_ssl', $user->ID)) {
373 + $secure_cookie = true;
374 + force_ssl_admin(true);
375 + }
376 + }
377 +
378 + if (class_exists('\Limit_Login_Attempts')) {
379 + global $limit_login_attempts_obj;
380 + $limit_login_attempts_try = $limit_login_attempts_obj->wp_authenticate_user($user, false);
381 + if (is_wp_error($limit_login_attempts_try)) {
382 + return $this->response([
383 + 'message' => implode('<br/>', $limit_login_attempts_try->get_error_messages())
384 + ], 403);
385 + }
386 + }
387 +
388 + $user_signon = wp_signon($info, $secure_cookie);
389 +
390 + // Note: No sanitization needed here as we're only checking emptiness, not using the cookie value
391 + if (!is_wp_error($user_signon) && empty($_COOKIE[LOGGED_IN_COOKIE])) {
392 + if (headers_sent()) {
393 + return $this->response([
394 + // translators: %1$s is the URL to WordPress cookies documentation, %2$s is the URL to WordPress support forums
395 + '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'),
396 + 'https://codex.wordpress.org/Cookies', 'https://wordpress.org/support/')
397 + ], 403);
398 + }
399 + }
400 +
401 + if (is_wp_error($user_signon)) {
402 + $errorMessage = __('Email or Password is not valid. Please try again', 'fluent-support');
403 +
404 + if (class_exists('Limit_Login_Attempts')) {
405 + global $limit_login_attempts_obj;
406 + if ($limit_login_attempts_obj) {
407 + $limit_login_attempts_obj->limit_login_failed($user->user_login);
408 + $msg = $limit_login_attempts_obj->get_message();
409 + if ($msg) {
410 + $errorMessage = $msg;
411 + }
412 + }
413 + }
414 +
415 + return $this->response([
416 + 'message' => $errorMessage
417 + ], 403);
418 + }
419 +
420 + // WP Last Login plugin compatibility
421 + if (class_exists('\Obenland_Wp_Last_Login')) {
422 + update_user_meta($user_signon->ID, 'wp-last-login', time());
423 + }
424 +
425 + return $this->sendSuccess([
426 + 'redirect' => $redirectUrl
427 + ]);
428 + }
429 +
430 + /**
431 + * getRules method will prepare the rules for the input field
432 + * @param array $fields
433 + * @return mixed
434 + */
52 435 protected function getRules($fields = [])
53 436 {
54 437 $rules = [];
55 438
@@ -65,67 +448,355 @@
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'
484 + ]);
485 + }
486 +
487 + // IP bucket is a generous volumetric backstop (shared office/NAT IPs can have many
488 + // unrelated users). It runs before the account lookup so that probes for accounts
489 + // that don't exist are throttled too. Keyed on the IP only, so a 429 here reveals
490 + // nothing about whether any given account exists.
491 + if (Helper::hitRateLimit('fs_reset_pass_ip_' . wp_hash(Helper::getIp()), 20)) {
492 + return $this->sendError([
493 + 'message' => __('Too many password reset requests. Please try again after 15 minutes.', 'fluent-support')
494 + ], 429);
495 + }
496 +
497 + $user_data = get_user_by('email', $usernameOrEmail);
498 +
499 + if (!$user_data) {
500 + $user_data = get_user_by('login', $usernameOrEmail);
501 + }
502 +
503 + if (!$user_data) {
504 + return $this->sendResetPassResponse();
505 + }
506 +
507 + $user_data = apply_filters('lostpassword_user_data', $user_data, $errors);
508 +
509 + do_action('lostpassword_post', $errors, $user_data);
510 +
511 + $errors = apply_filters('lostpassword_errors', $errors, $user_data);
512 +
513 + if ($errors->has_errors()) {
514 + return $this->sendResetPassResponse();
515 + }
516 +
517 + if (!$user_data) {
518 + return $this->sendResetPassResponse();
519 + }
520 +
521 + if (is_multisite() && !is_user_member_of_blog($user_data->ID, get_current_blog_id())) {
522 + return $this->sendResetPassResponse();
523 + }
524 +
525 + // Redefining user_login ensures we return the right case in the email.
526 + $user_login = $user_data->user_login;
527 +
528 + do_action('retrieve_password', $user_login);
529 +
530 + $allow = apply_filters('allow_password_reset', true, $user_data->ID);
531 +
532 + if (!$allow || is_wp_error($allow)) {
533 + return $this->sendResetPassResponse();
534 + }
535 +
536 +
537 + /*
538 + * Filter reset password link text
539 + *
540 + * @since v1.5.7
541 + * @param string $linkText
542 + */
543 + // translators: %s is the site name
544 + $linkText = apply_filters("fluent_support/reset_password_link", sprintf(__('Reset your password for %s', 'fluent-support'), get_bloginfo('name')));
545 +
546 + // Issuance cooldown. get_password_reset_key() rotates the stored key, invalidating
547 + // any link already sitting in the account owner's inbox, so an unthrottled caller
548 + // could deny password recovery indefinitely. Suppressing the duplicate issuance is
549 + // safe: reset mail only ever goes to the account owner, so whoever triggered the
550 + // first send has already put a working link in that inbox.
551 + $cooldownKey = 'fs_reset_pass_sent_' . wp_hash($user_data->ID);
552 +
553 + if (get_transient($cooldownKey)) {
554 + return $this->sendResetPassResponse();
555 + }
556 +
557 + set_transient($cooldownKey, 1, 5 * MINUTE_IN_SECONDS);
558 +
559 + $resetUrl = add_query_arg([
560 + 'action' => 'rp',
561 + 'key' => get_password_reset_key($user_data),
562 + 'login' => rawurlencode($user_data->user_login)
563 + ], wp_login_url());
564 +
565 + $resetLink = '<a href="' . $resetUrl . '">' . $linkText . '</a>';
566 +
567 + /*
568 + * Filter reset password email subject
569 + *
570 + * @since v1.5.7
571 + * @param string $mailSubject
572 + */
573 + // translators: %s is the site name
574 + $mailSubject = apply_filters("fluent_support/reset_password_mail_subject", sprintf(__('Reset your password for %s support portal', 'fluent-support'), get_bloginfo('name')));
575 +
576 + // translators: %s is the user's first name
577 + $message = '<p>' . sprintf(__('Hi %s,', 'fluent-support'), $user_data->first_name) . '</p>' .
578 + '<p>' . __('Someone has requested a new password for the following account on WordPress:', 'fluent-support') . '</p>' .
579 + // translators: %s is the username
580 + '<p>' . sprintf(__('Username: %s', 'fluent-support'), $user_login) . '</p>' .
581 + '<p>' . $resetLink . '</p>' .
582 + '<p>' . __('If you did not request to reset your password, please ignore this email.', 'fluent-support') . '</p>';
583 +
584 + /*
585 + * Filter reset password email body text
586 + *
587 + * @since v1.5.7
588 + * @param string $message
589 + * @param object $user
590 + * @param string $resetLink
591 + */
592 + $message = apply_filters('fluent_support/reset_password_message', $message, $user_data, $resetLink);
593 +
594 + $headers = array('Content-Type: text/html; charset=UTF-8');
595 +
596 + wp_mail($user_data->user_email, $mailSubject, $message, $headers);
597 +
598 + return $this->sendResetPassResponse();
71 599 }
72 600
601 + /**
602 + * Single response for every password reset outcome.
603 + *
604 + * Whether the account exists, is disallowed, is not a member of this site or is
605 + * inside the resend cooldown, the caller sees the same thing — otherwise the form
606 + * confirms which usernames and email addresses are real.
607 + *
608 + * @return mixed
609 + */
610 + protected function sendResetPassResponse()
611 + {
612 + return $this->sendSuccess([
613 + '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')
614 + ]);
615 + }
616 +
617 + /**
618 + * getMessages message will return the validation message regarding sign up or sign in
619 + * @param array $rules
620 + * @return mixed
621 + */
73 622 protected function getMessages($rules = [])
74 623 {
624 + /*
625 + * Filter user signup validation message
626 + *
627 + * @since v1.0.0
628 + * @param array $arg
629 + * @param array $rules
630 + */
75 631 return apply_filters('fluent_support/signup_validation_messages', [], $rules);
76 632 }
77 633
78 - protected function createUser($formData = [])
634 + /**
635 + * createUser method will create new user
636 + * @param array $formData
637 + * @return mixed
638 + */
639 + public function createUser($formData = [])
79 640 {
641 + /*
642 + * Filter user signup email
643 + *
644 + * @since v1.0.0
645 + * @param string $email
646 + */
80 647 $email = apply_filters('fluent_support/signup_email', Arr::get($formData, 'email'));
648 +
649 + /*
650 + * Filter user signup username
651 + *
652 + * @since v1.0.0
653 + * @param string $username
654 + */
81 655 $userName = apply_filters('fluent_support/signup_username', Arr::get($formData, 'username'));
82 656
83 657 if (empty($formData['password'])) {
84 - $password = wp_generate_password(8);
658 + $password = wp_generate_password(16, true, true);
85 659 } else {
86 660 $password = $formData['password'];
87 661 }
88 662
663 + /*
664 + * Filter user signup password
665 + *
666 + * @since v1.0.0
667 + * @param string $password
668 + */
89 669 $password = apply_filters('fluent_support/signup_password', $password);
90 670
671 + /*
672 + * Action before creating WP user using Fluent Support signup form
673 + *
674 + * @since v1.0.0
675 + * @param string $userName
676 + * @param string $password
677 + * @param string $email
678 + */
91 679 do_action('fluent_support/before_creating_user', $userName, $password, $email);
92 680
93 - return wp_create_user($userName, $password, $email);
681 + $userId = wp_create_user($userName, $password, $email);
682 +
683 + if (is_wp_error($userId)) {
684 + return false;
685 + }
686 +
687 + return $userId;
688 +
94 689 }
95 690
96 - protected function maybeUpdateUser($userId, $formData)
691 + /**
692 + * maybeUpdateUser method will update user information if exists
693 + * @param $userId
694 + * @param $formData
695 + */
696 + public function maybeUpdateUser($userId, $formData)
97 697 {
98 - $name = trim(Arr::get($formData, 'first_name') . ' ' . Arr::get($formData, 'last_name'));
698 + $firstName = Arr::get($formData, 'first_name', '');
699 + $lastName = Arr::get($formData, 'last_name', '');
700 + $name = trim($firstName . ' ' . $lastName);
99 701
100 702 $data = array_filter([
101 - 'ID' => $userId,
703 + 'ID' => $userId,
102 704 'user_nicename' => $name,
103 - 'display_name' => $name
705 + 'display_name' => $name,
706 + 'first_name' => $firstName,
707 + 'last_name' => $lastName,
104 708 ]);
105 709
106 710 if ($name) {
711 + /*
712 + * Action before updating a customer/user
713 + *
714 + * @since v1.0.0
715 + * @param array $data
716 + */
107 717 do_action('fluent_support/before_updating_user', $data);
108 718
109 - wp_update_user(apply_filters('fluent_support/update_user_data', $data));
719 + /*
720 + * Filter user updatable data
721 + *
722 + * @since v1.0.0
723 + * @param $data
724 + */
725 + $updateUserData = apply_filters('fluent_support/update_user_data', $data);
726 + wp_update_user($updateUserData);
110 727
728 + /*
729 + * Action after updating a customer/user
730 + *
731 + * @since v1.0.0
732 + * @param array $data
733 + */
111 734 do_action('fluent_support/after_updating_user', $data);
112 735 }
113 736 }
114 737
738 + public function addUserMetaData($userId, $formData) {
739 + $customFieldsKey = apply_filters('fluent_support/custom_registration_form_fields_key', Helper::getBusinessSettings('custom_registration_form_field'));
740 +
741 + if (empty($customFieldsKey)) {
742 + return;
743 + }
744 +
745 + foreach ($customFieldsKey as $key) {
746 + if (isset($formData[$key])) {
747 + $fieldValue = $formData[$key];
748 + update_user_meta($userId, $key, $fieldValue);
749 + }
750 + }
751 + }
752 +
753 + /**
754 + * assignRole method will assign role to a given user id
755 + * @param $userId
756 + */
115 757 protected function assignRole($userId)
116 758 {
117 759 $user = new \WP_User($userId);
118 760
761 + /*
762 + * Action before assigning role to registered user
763 + *
764 + * @since v1.0.0
765 + * @param array $data
766 + */
119 767 do_action('fluent_support/before_assigning_role', $user);
768 + /*
769 + * Filter user assignable role after signup
770 + *
771 + * @since v1.0.0
772 + * @param string $setRole WordPress user role key
773 + */
774 + $setRole = apply_filters('fluent_support/user_role', 'subscriber');
775 + $user->set_role($setRole);
120 776
121 - $user->set_role(apply_filters('fluent_support/user_role', 'subscriber'));
122 -
777 + /*
778 + * Action after assigning role to registered user
779 + *
780 + * @since v1.0.0
781 + * @param array $data
782 + */
123 783 do_action('fluent_support/after_assigning_role', $user);
124 784 }
125 785
786 +
787 + /**
788 + * login method will clear existing cookies and set new cookie for a given user id
789 + * @param $userId
790 + */
126 791 protected function login($userId)
127 792 {
793 + /*
794 + * Action before login
795 + *
796 + * @since v1.0.0
797 + * @param integer $userId
798 + */
128 799 do_action('fluent_support/before_logging_in_user', $userId);
129 800
130 801 wp_clear_auth_cookie();
131 802 wp_set_current_user($userId);
@@ -130,7 +801,14 @@
130 801 wp_clear_auth_cookie();
131 802 wp_set_current_user($userId);
132 803 wp_set_auth_cookie($userId);
133 804
805 + /*
806 + * Action after login
807 + *
808 + * @since v1.0.0
809 + * @param integer $userId
810 + */
134 811 do_action('fluent_support/after_logging_in_user', $userId);
135 812 }
813 +
136 814 }