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 +408 -23 1.5.52.4.0 View file →
@@ -1,13 +1,18 @@
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 {
12 17 /**
13 18 * signUp method will create new user submitted data from sign up form
@@ -17,10 +22,16 @@
17 22 */
18 23 public function signup(Request $request)
19 24 {
20 25
21 - if (!wp_verify_nonce($request->get('_fsupport_signup_nonce'), 'fluent_support_signup_nonce')) {
26 + if(Helper::getAuthProvider() !== 'fluent_support') {
22 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([
23 34 'message' => __('Security verification failed. Please try again', 'fluent-support')
24 35 ]);
25 36 }
26 37
@@ -45,10 +56,118 @@
45 56 * @param array $formData
46 57 */
47 58 do_action('fluent_support/before_signup_validation', $formData);
48 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 +
49 76 $this->validate($formData, $rules, $messages);
50 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 +
51 170 /*
52 171 * Action After validate user signup validation success
53 172 *
54 173 * @since v1.0.0
@@ -74,8 +193,9 @@
74 193 */
75 194 do_action('fluent_support/after_creating_user');
76 195
77 196 $this->maybeUpdateUser($userId, $formData);
197 + $this->addUserMetaData($userId, $formData);
78 198 $this->assignRole($userId);
79 199 $this->login($userId);
80 200
81 201 /*
@@ -84,9 +204,9 @@
84 204 * @since v1.0.0
85 205 * @param array $response
86 206 */
87 207 $response = apply_filters('fluent_support/signup_complete_response', [
88 - 'message' => __('Successfully registered to the site.', 'fluent-support'),
208 + 'message' => __('Successfully registered to the site.', 'fluent-support'),
89 209 'redirect' => Arr::get($formData, '__redirect_to', Helper::getPortalBaseUrl())
90 210 ]);
91 211
92 212 return $this->response($response);
@@ -98,9 +218,15 @@
98 218 * @return \WP_REST_Response
99 219 */
100 220 public function handleLogin(Request $request)
101 221 {
102 - if (!wp_verify_nonce($request->get('_support_login_nonce'), 'fsupport_login_nonce')) {
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')) {
103 229 return $this->response([
104 230 'message' => __('Security verification failed', 'fluent-support')
105 231 ], 403);
106 232 }
@@ -106,15 +232,28 @@
106 232 }
107 233
108 234 $data = $request->all();
109 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 +
110 247 if (empty($data['pwd']) || empty($data['log'])) {
111 248 return $this->response([
112 249 'message' => __('Email and Password is required', 'fluent-support')
113 250 ], 403);
114 251 }
115 -
116 252 $redirectUrl = Helper::getPortalBaseUrl();
253 + if ($redirect = $request->getSafe('redirect_to', 'sanitize_text_field')) {
254 + $redirectUrl = wp_validate_redirect($redirect, $redirectUrl);
255 + }
117 256
118 257 if (get_current_user_id()) { // user already registered
119 258 return $this->sendSuccess([
120 259 'redirect' => $redirectUrl
@@ -120,10 +259,10 @@
120 259 'redirect' => $redirectUrl
121 260 ]);
122 261 }
123 262
124 - $email = $data['log'];
125 - $password = $data['pwd'];
263 + $email = sanitize_user($data['log']);
264 + $password = trim($data['pwd'] ?? '');
126 265
127 266 if (is_email($email)) {
128 267 $user = get_user_by('email', $email);
129 268 } else {
@@ -129,25 +268,76 @@
129 268 } else {
130 269 $user = get_user_by('login', $email);
131 270 }
132 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 +
133 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 +
134 297 return $this->response([
135 298 'message' => __('Email or Password is not valid. Please try again', 'fluent-support')
136 299 ], 403);
300 +
137 301 }
138 302
139 - $info = array(
140 - 'user_login' => sanitize_text_field(trim($_POST['log'])),
141 - 'user_password' => trim($_POST['pwd']),
142 - 'remember' => isset($_POST['rememberme']),
143 - );
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);
144 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 +
145 317 if (apply_filters('fluent_support_use_native_login', true)) {
146 - return $this->nativeLoginHandler($user, $info, $redirectUrl);
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 + ]);
147 335 }
148 336
149 337 if (wp_check_password($password, $user->user_pass, $user->ID)) {
338 + delete_transient($ipKey);
339 + delete_transient($accountKey);
150 340 $this->login($user->ID);
151 341 return $this->sendSuccess([
152 342 'redirect' => $redirectUrl
153 343 ]);
@@ -152,13 +342,26 @@
152 342 'redirect' => $redirectUrl
153 343 ]);
154 344 }
155 345
346 + $this->incrementLoginAttempts($ipKey);
347 + $this->incrementLoginAttempts($accountKey);
348 +
156 349 return $this->response([
157 - 'message' => __('Email or Password is not valid. Please try again', 'fluent-support')
350 + 'message' => __('Invalid username, email address or incorrect password.', 'fluent-support')
158 351 ], 403);
159 352 }
160 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 +
161 364 private function nativeLoginHandler($user, $info, $redirectUrl = '')
162 365 {
163 366 if (!$redirectUrl) {
164 367 $redirectUrl = Helper::getPortalBaseUrl();
@@ -183,13 +386,15 @@
183 386 }
184 387
185 388 $user_signon = wp_signon($info, $secure_cookie);
186 389
390 + // Note: No sanitization needed here as we're only checking emptiness, not using the cookie value
187 391 if (!is_wp_error($user_signon) && empty($_COOKIE[LOGGED_IN_COOKIE])) {
188 392 if (headers_sent()) {
189 393 return $this->response([
190 - '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>.'),
191 - __('https://codex.wordpress.org/Cookies'), __('https://wordpress.org/support/'))
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/')
192 397 ], 403);
193 398 }
194 399 }
195 400
@@ -253,9 +458,164 @@
253 458 return apply_filters('fluent_support/signup_validation_rules', $rules);
254 459 }
255 460
256 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();
599 + }
600 +
257 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 + /**
258 618 * getMessages message will return the validation message regarding sign up or sign in
259 619 * @param array $rules
260 620 * @return mixed
261 621 */
@@ -294,9 +654,9 @@
294 654 */
295 655 $userName = apply_filters('fluent_support/signup_username', Arr::get($formData, 'username'));
296 656
297 657 if (empty($formData['password'])) {
298 - $password = wp_generate_password(8);
658 + $password = wp_generate_password(16, true, true);
299 659 } else {
300 660 $password = $formData['password'];
301 661 }
302 662
@@ -317,9 +677,16 @@
317 677 * @param string $email
318 678 */
319 679 do_action('fluent_support/before_creating_user', $userName, $password, $email);
320 680
321 - 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 +
322 689 }
323 690
324 691 /**
325 692 * maybeUpdateUser method will update user information if exists
@@ -327,16 +694,18 @@
327 694 * @param $formData
328 695 */
329 696 public function maybeUpdateUser($userId, $formData)
330 697 {
331 - $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);
332 701
333 702 $data = array_filter([
334 - 'ID' => $userId,
703 + 'ID' => $userId,
335 704 'user_nicename' => $name,
336 - 'display_name' => $name,
337 - 'first_name' => Arr::get($formData, 'first_name'),
338 - 'last_name' => Arr::get($formData, 'last_name'),
705 + 'display_name' => $name,
706 + 'first_name' => $firstName,
707 + 'last_name' => $lastName,
339 708 ]);
340 709
341 710 if ($name) {
342 711 /*
@@ -365,8 +734,23 @@
365 734 do_action('fluent_support/after_updating_user', $data);
366 735 }
367 736 }
368 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 +
369 753 /**
370 754 * assignRole method will assign role to a given user id
371 755 * @param $userId
372 756 */
@@ -425,5 +809,6 @@
425 809 * @param integer $userId
426 810 */
427 811 do_action('fluent_support/after_logging_in_user', $userId);
428 812 }
813 +
429 814 }