| @@ -4,14 +4,19 @@ | ||
| 4 | 4 | namespace FluentCommunity\Modules\Auth; |
| 5 | 5 | |
| 6 | 6 | use FluentAuth\App\Hooks\Handlers\CustomAuthHandler; |
| 7 | 7 | use FluentCommunity\App\App; |
| 8 | +use FluentCommunity\App\Functions\Utility; | |
| 9 | +use FluentCommunity\App\Services\AuthenticationService; | |
| 8 | 10 | use FluentCommunity\App\Models\BaseSpace; |
| 9 | 11 | use FluentCommunity\App\Models\User; |
| 12 | +use FluentCommunity\App\Services\FeedsHelper; | |
| 10 | 13 | use FluentCommunity\App\Services\Helper; |
| 11 | 14 | use FluentCommunity\App\Services\ProfileHelper; |
| 12 | 15 | use FluentCommunity\App\Vite; |
| 13 | 16 | use FluentCommunity\Framework\Support\Arr; |
| 17 | +use FluentCommunity\Modules\Auth\Classes\Invitation; | |
| 18 | +use FluentCommunity\Modules\Auth\Classes\InvitationHandler; | |
| 14 | 19 | use FluentCommunity\Modules\Auth\Classes\InvitationService; |
| 15 | 20 | |
| 16 | 21 | class AuthModdule |
| 17 | 22 | { |
| @@ -22,64 +27,167 @@ | ||
| 22 | 27 | add_action('wp_ajax_nopriv_fcom_user_registration', [$this, 'handleUserSignup']); |
| 23 | 28 | add_action('wp_ajax_fcom_user_registration', [$this, 'handleUserSignup']); |
| 24 | 29 | add_action('wp_ajax_nopriv_fcom_user_login_form', [$this, 'handleUserLogin']); |
| 25 | 30 | add_action('wp_ajax_fcom_user_login_form', [$this, 'handleUserLogin']); |
| 31 | + | |
| 32 | + add_filter('fluent_auth/login_redirect_url', function ($redirectUrl, $user) { | |
| 33 | + if (empty($_REQUEST['is_fcom_auth']) || empty($_REQUEST['fcom_redirect'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 34 | + return $redirectUrl; | |
| 35 | + } | |
| 36 | + | |
| 37 | + // validate the url | |
| 38 | + $redirectUrl = wp_validate_redirect(sanitize_url(wp_unslash($_REQUEST['fcom_redirect'])), Helper::baseUrl()); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 39 | + | |
| 40 | + $redirectUrl = apply_filters('fluent_community/auth/after_login_redirect_url', $redirectUrl, $user); | |
| 41 | + return $redirectUrl; | |
| 42 | + }, 10, 2); | |
| 26 | 43 | } |
| 27 | 44 | |
| 28 | 45 | public function maybeAutoLogin($requestData) |
| 29 | 46 | { |
| 30 | 47 | $urlHash = Arr::get($requestData, 'fcom_url_hash'); |
| 31 | - if ($urlHash) { | |
| 48 | + if ($urlHash && !get_current_user_id()) { | |
| 32 | 49 | $tagetUser = ProfileHelper::getUserByUrlHash($urlHash); |
| 33 | - | |
| 34 | 50 | if ($tagetUser) { |
| 35 | 51 | $willAtoLogin = apply_filters('fluent_community/allow_auto_login_by_url', !user_can($tagetUser, 'delete_pages'), $tagetUser); |
| 36 | - // $willAtoLogin = true; | |
| 37 | 52 | if ($willAtoLogin) { |
| 38 | - InvitationService::makeLogin($tagetUser); | |
| 53 | + try { | |
| 54 | + InvitationService::makeLogin($tagetUser); | |
| 55 | + } catch (\Throwable $e) { | |
| 56 | + if (defined('WP_DEBUG') && WP_DEBUG) { | |
| 57 | + error_log('FluentCommunity: Auto-login failed for user #' . $tagetUser->ID . ': ' . $e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log | |
| 58 | + } | |
| 59 | + } | |
| 39 | 60 | } |
| 40 | 61 | } |
| 41 | 62 | } |
| 42 | 63 | |
| 43 | 64 | // Remove fcom_action and fcom_url_hash from the current url |
| 44 | - $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); | |
| 65 | + $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 45 | 66 | $url = remove_query_arg(['fcom_action', 'fcom_url_hash'], $currentUrl); |
| 46 | - wp_redirect($url); | |
| 67 | + $this->redirectAndExit($url); | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * Send a redirect and stop. | |
| 72 | + * | |
| 73 | + * Extracted only so it can be observed: a bare `exit()` terminates the PHP | |
| 74 | + * process, which in a test run kills the whole suite with no result (see | |
| 75 | + * FIX-PLAN item 22 for the same problem on PortalHandler). A test subclass | |
| 76 | + * overrides this and the two methods below to record what was about to | |
| 77 | + * happen and throw instead. Behaviour in production is unchanged — this is | |
| 78 | + * the original call, moved. | |
| 79 | + * | |
| 80 | + * This one keeps the UNSAFE variant its single caller already used. That | |
| 81 | + * caller builds its target with home_url(), so it is same-host by | |
| 82 | + * construction rather than by validation. Kept as a separate method from | |
| 83 | + * safeRedirectAndExit(), rather than a $safe flag, so the distinction stays | |
| 84 | + * visible to anyone grepping for wp_redirect. | |
| 85 | + */ | |
| 86 | + protected function redirectAndExit($url, $status = 302) | |
| 87 | + { | |
| 88 | + wp_redirect($url, $status); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect | |
| 47 | 89 | exit(); |
| 48 | 90 | } |
| 49 | 91 | |
| 92 | + /** | |
| 93 | + * Send a host-confined redirect and stop. See redirectAndExit(). | |
| 94 | + */ | |
| 95 | + protected function safeRedirectAndExit($url) | |
| 96 | + { | |
| 97 | + wp_safe_redirect($url); | |
| 98 | + exit(); | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * Render the headless page and stop. See redirectAndExit(). | |
| 103 | + */ | |
| 104 | + protected function renderPageAndExit($template, $pageVars) | |
| 105 | + { | |
| 106 | + status_header(200); | |
| 107 | + App::make('view')->render($template, $pageVars); | |
| 108 | + exit(200); | |
| 109 | + } | |
| 110 | + | |
| 50 | 111 | public function viewAuthPage() |
| 51 | 112 | { |
| 113 | + | |
| 114 | + add_filter('login_form_defaults', function ($defaults) { | |
| 115 | + $defaults['label_username'] = __('Email Address', 'fluent-community'); | |
| 116 | + return $defaults; | |
| 117 | + }); | |
| 118 | + | |
| 119 | + add_filter('fluent_community/has_color_scheme', '__return_false'); | |
| 120 | + | |
| 52 | 121 | $currentUserId = get_current_user_id(); |
| 53 | 122 | // check if there has any invitation token |
| 54 | - $inivtationToken = Arr::get($_GET, 'invitation_token'); | |
| 123 | + $inivtationToken = Arr::get($_GET, 'invitation_token'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 55 | 124 | |
| 56 | 125 | $inviation = null; |
| 57 | 126 | if ($inivtationToken) { |
| 58 | 127 | $inviation = apply_filters('fluent_community/auth/invitation', null, $inivtationToken); |
| 128 | + if ($inviation && !$inviation->isValid()) { | |
| 129 | + $inviation = null; | |
| 130 | + } | |
| 59 | 131 | } |
| 60 | 132 | |
| 61 | 133 | if ($currentUserId && !$inviation) { |
| 62 | - wp_redirect(Helper::baseUrl()); | |
| 63 | - exit(); | |
| 134 | + $redirectUrl = null; | |
| 135 | + if (!empty($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 136 | + $redirectUrl = sanitize_url(wp_unslash($_REQUEST['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 137 | + } | |
| 138 | + if (!$redirectUrl) { | |
| 139 | + $redirectUrl = Helper::baseUrl(); | |
| 140 | + } | |
| 141 | + | |
| 142 | + $this->safeRedirectAndExit($redirectUrl); | |
| 64 | 143 | } |
| 65 | 144 | |
| 145 | + if ($currentUserId && $inviation) { | |
| 146 | + /** @var BaseSpace|null $space */ | |
| 147 | + $space = BaseSpace::withoutGlobalScopes()->find($inviation->post_id); | |
| 148 | + if ($space) { | |
| 149 | + if (Helper::isUserInSpace($currentUserId, $inviation->post_id)) { | |
| 150 | + // let's redirect the user to the space | |
| 151 | + $redirectUrl = $space->getPermalink(); | |
| 152 | + $this->safeRedirectAndExit($redirectUrl); | |
| 153 | + } | |
| 154 | + | |
| 155 | + if (!empty($_REQUEST['auto_accept'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 156 | + $redirectUrl = (new InvitationHandler())->handleInvitationLogin(Helper::baseUrl(), get_user_by('ID', $currentUserId), $inviation->message_rendered); | |
| 157 | + if (is_wp_error($redirectUrl) || !$redirectUrl) { | |
| 158 | + $redirectUrl = Helper::baseUrl(); | |
| 159 | + } | |
| 160 | + $this->safeRedirectAndExit($redirectUrl); | |
| 161 | + } | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 66 | 165 | do_action('fluent_community/auth/before_auth_page_process', $currentUserId, $inviation); |
| 67 | 166 | |
| 68 | 167 | $acceptedForms = ['login', 'register', 'reset_password']; |
| 69 | - $targetForm = Arr::get($_GET, 'form'); | |
| 70 | - if (!in_array($targetForm, $acceptedForms)) { | |
| 168 | + $targetForm = Arr::get($_GET, 'form'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 169 | + $explicitForm = in_array($targetForm, $acceptedForms, true); | |
| 170 | + if (!$explicitForm) { | |
| 71 | 171 | $targetForm = 'login'; |
| 72 | 172 | } |
| 73 | 173 | |
| 74 | - if ($inviation && $targetForm != 'reset_password') { | |
| 75 | - $isUserAvailable = get_user_by('email', $inviation->message); | |
| 76 | - $targetForm = $isUserAvailable ? 'login' : 'register'; | |
| 174 | + if ($inviation && !$explicitForm) { | |
| 175 | + if ($inviation->message) { | |
| 176 | + $isUserAvailable = get_user_by('email', $inviation->message); | |
| 177 | + $targetForm = $isUserAvailable ? 'login' : 'register'; | |
| 178 | + } else { | |
| 179 | + $targetForm = 'register'; | |
| 180 | + } | |
| 77 | 181 | } |
| 78 | 182 | |
| 79 | - if ($inviation && $currentUserId) { | |
| 80 | - $invitedUser = get_user_by('email', $inviation->message); | |
| 81 | - if ($invitedUser && $invitedUser->ID == $currentUserId) { | |
| 183 | + if ($inviation && $currentUserId && $inviation->isValid()) { | |
| 184 | + if ($inviation->message) { | |
| 185 | + $invitedUser = get_user_by('email', $inviation->message); | |
| 186 | + if ($invitedUser && $invitedUser->ID == $currentUserId) { | |
| 187 | + $targetForm = 'accept_invitation'; | |
| 188 | + } | |
| 189 | + } else { | |
| 82 | 190 | $targetForm = 'accept_invitation'; |
| 83 | 191 | } |
| 84 | 192 | } |
| 85 | 193 | |
| @@ -84,10 +192,9 @@ | ||
| 84 | 192 | } |
| 85 | 193 | |
| 86 | 194 | $isFluentAuth = AuthHelper::isFluentAuthAvailable(); |
| 87 | 195 | if (!$isFluentAuth && $targetForm == 'reset_password') { |
| 88 | - wp_redirect(wp_lostpassword_url(Helper::baseUrl())); | |
| 89 | - exit(); | |
| 196 | + $this->safeRedirectAndExit(wp_lostpassword_url(Helper::baseUrl())); | |
| 90 | 197 | } |
| 91 | 198 | |
| 92 | 199 | $portalSettings = Helper::generalSettings(); |
| 93 | 200 | $titleVar = Arr::get($portalSettings, 'site_title'); |
| @@ -92,60 +199,86 @@ | ||
| 92 | 199 | $portalSettings = Helper::generalSettings(); |
| 93 | 200 | $titleVar = Arr::get($portalSettings, 'site_title'); |
| 94 | 201 | |
| 95 | 202 | $frameData = [ |
| 96 | - 'logo' => Arr::get($portalSettings, 'logo', ''), | |
| 97 | - 'title' => sprintf(__('Join %s', 'fluent-community'), $titleVar), | |
| 98 | - 'description' => __('Login or Signup to join the community', 'fluent-community'), | |
| 99 | - 'loginBtnText' => __('Login', 'fluent-community'), | |
| 100 | - 'signupBtnText' => __('Signup', 'fluent-community'), | |
| 203 | + 'logo' => Arr::get($portalSettings, 'logo', ''), | |
| 204 | + /* translators: %s is replaced by the title of the site */ | |
| 205 | + 'title' => sprintf(__('Join %s', 'fluent-community'), $titleVar), | |
| 206 | + 'description' => __('Login or Signup to join the community', 'fluent-community'), | |
| 207 | + 'button_label' => __('Login', 'fluent-community'), | |
| 101 | 208 | ]; |
| 102 | 209 | |
| 103 | - $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); | |
| 210 | + if ($targetForm == 'register') { | |
| 211 | + $frameData['button_label'] = __('Signup', 'fluent-community'); | |
| 212 | + if (!$inviation) { | |
| 213 | + $customSignupUrl = Arr::get($portalSettings, 'custom_signup_url'); | |
| 214 | + if ($customSignupUrl) { | |
| 215 | + $this->safeRedirectAndExit($customSignupUrl); | |
| 216 | + } | |
| 217 | + } | |
| 218 | + } | |
| 104 | 219 | |
| 220 | + $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 221 | + | |
| 222 | + do_action('fluent_community/enqueue_global_assets', true); | |
| 223 | + add_action('wp_enqueue_scripts', function () use ($isFluentAuth, $targetForm, $inviation) { | |
| 224 | + wp_enqueue_style('fluent_auth_styles', Vite::getStaticSrcUrl('user_registration.css'), [], FLUENT_COMMUNITY_PLUGIN_VERSION); | |
| 225 | + if(!$isFluentAuth || $targetForm == 'register' || $inviation) { | |
| 226 | + wp_enqueue_script('fluent_auth_scripts', Vite::getStaticSrcUrl('user_registration.js'), [], FLUENT_COMMUNITY_PLUGIN_VERSION, true); | |
| 227 | + wp_localize_script('fluent_auth_scripts', 'fluentComRegistration', array( | |
| 228 | + 'ajax_url' => admin_url('admin-ajax.php'), | |
| 229 | + 'is_logged_in' => is_user_logged_in(), | |
| 230 | + 'redirecting_text' => __('Redirecting...', 'fluent-community'), | |
| 231 | + 'i18n' => [ | |
| 232 | + 'generic_error' => esc_html__('Something went wrong. Please try again later', 'fluent-community'), | |
| 233 | + 'network_error' => esc_html__('Could not reach the server. Please check your connection and try again.', 'fluent-community'), | |
| 234 | + ] | |
| 235 | + )); | |
| 236 | + } | |
| 237 | + }, 10); | |
| 238 | + | |
| 105 | 239 | $pageVars = [ |
| 106 | 240 | 'title' => $frameData['title'], |
| 241 | + 'og_title' => $frameData['title'], | |
| 107 | 242 | 'description' => $frameData['description'], |
| 108 | 243 | 'url' => $currentUrl, |
| 109 | 244 | 'featured_image' => '', |
| 110 | - 'css_files' => [ | |
| 111 | - Vite::getDynamicSrcUrl('theme-default.scss'), | |
| 112 | - Vite::getDynamicSrcUrl('public/scss/user_registration.scss') | |
| 113 | - ], | |
| 114 | - 'js_files' => [ | |
| 115 | - Vite::getDynamicSrcUrl('public/js/user_registration.js') | |
| 116 | - ], | |
| 117 | - 'js_vars' => [ | |
| 118 | - 'fluentComRegistration' => [ | |
| 119 | - 'ajax_url' => admin_url('admin-ajax.php'), | |
| 120 | - 'is_logged_in' => is_user_logged_in(), | |
| 121 | - ] | |
| 122 | - ], | |
| 245 | + 'css_files' => [], | |
| 246 | + 'js_files' => [], | |
| 247 | + 'js_vars' => [], | |
| 123 | 248 | 'scope' => 'user_registration', |
| 124 | 249 | 'layout' => 'signup', |
| 125 | 250 | 'portal' => [ |
| 126 | 251 | 'logo' => Arr::get($portalSettings, 'logo', ''), |
| 127 | - 'title' => __(sprintf('Welcome to %s', Arr::get($portalSettings, 'site_title')), 'fluent-community'), | |
| 252 | + /* translators: %s is replaced by the title of the site */ | |
| 253 | + 'title' => \sprintf(__('Welcome to %s', 'fluent-community'), Arr::get($portalSettings, 'site_title')), | |
| 128 | 254 | 'description' => get_bloginfo('description') |
| 129 | 255 | ] |
| 130 | 256 | ]; |
| 131 | 257 | |
| 132 | - if ($isFluentAuth) { | |
| 133 | - $pageVars['js_files'][] = FLUENT_AUTH_PLUGIN_URL . 'dist/public/login_helper.js'; | |
| 134 | - $pageVars['js_vars']['fluentAuthPublic'] = [ | |
| 135 | - 'hide' => false, | |
| 136 | - 'redirect_fallback' => site_url(), | |
| 137 | - 'fls_login_nonce' => wp_create_nonce('fsecurity_login_nonce'), | |
| 138 | - 'ajax_url' => admin_url('admin-ajax.php'), | |
| 139 | - 'i18n' => [ | |
| 140 | - 'Username_or_Email' => __('Email Address', 'fluent-community'), | |
| 141 | - 'Password' => __('Password', 'fluent-community') | |
| 142 | - ] | |
| 258 | + if (Utility::isDev()) { | |
| 259 | + $pageVars['js_files'] = [ | |
| 260 | + Vite::getStaticSrcUrl('public/js/user_registration.js') | |
| 143 | 261 | ]; |
| 144 | 262 | } |
| 145 | 263 | |
| 146 | - add_action('fluent_community/headless/content', function ($context) use ($targetForm, $currentUrl, $frameData, $inviation) { | |
| 264 | + $formType = ($targetForm == 'register') ? 'signup' : 'login'; | |
| 265 | + | |
| 266 | + $formSettings = AuthenticationService::getFormattedAuthSettings($formType); | |
| 267 | + | |
| 268 | + if ($formSettings) { | |
| 269 | + $pageVars['portal'] = Arr::get($formSettings, 'banner'); | |
| 270 | + $pageVars['portal']['form'] = Arr::get($formSettings, 'form'); | |
| 271 | + } | |
| 272 | + | |
| 273 | + add_action('fluent_community/headless/content', function ($context) use ($targetForm, $currentUrl, $frameData, $inviation, $formSettings) { | |
| 274 | + $preContent = apply_filters('fluent_community/auth/pre_content', '', $context, $targetForm, $frameData); | |
| 275 | + if ($preContent) { | |
| 276 | + return; | |
| 277 | + } | |
| 278 | + | |
| 147 | 279 | if ($targetForm == 'login') { |
| 280 | + $frameData['button_label'] = Arr::get($formSettings, 'form.button_label', __('Login', 'fluent-community')); | |
| 148 | 281 | $this->showLoginForm($frameData, $inviation); |
| 149 | 282 | } else if ($targetForm == 'reset_password') { |
| 150 | 283 | $frameData['title'] = __('Reset your password', 'fluent-community'); |
| 151 | 284 | ?> |
| @@ -153,8 +286,11 @@ | ||
| 153 | 286 | <div class="fcom_onboard_header"> |
| 154 | 287 | <div class="fcom_onboard_header_title"> |
| 155 | 288 | <h2><?php echo esc_html($frameData['title']); ?></h2> |
| 156 | 289 | </div> |
| 290 | + <div class="fcom_onboard_sub"> | |
| 291 | + <p><?php esc_html_e('Please enter your email address. You will receive an email message with instructions on how to reset your password.', 'fluent-community'); ?></p> | |
| 292 | + </div> | |
| 157 | 293 | </div> |
| 158 | 294 | <div class="fcom_onboard_body"> |
| 159 | 295 | <div class="fcom_onboard_form"> |
| 160 | 296 | <?php echo do_shortcode('[fluent_auth_reset_password redirect_to="' . esc_url($currentUrl) . '"]'); ?> |
| @@ -160,9 +296,9 @@ | ||
| 160 | 296 | <?php echo do_shortcode('[fluent_auth_reset_password redirect_to="' . esc_url($currentUrl) . '"]'); ?> |
| 161 | 297 | <div class="fcom_spaced_divider"> |
| 162 | 298 | <div class="fcom_alt_auth_text"> |
| 163 | 299 | <a href="<?php echo esc_url(add_query_arg('form', 'login', $currentUrl)); ?>"> |
| 164 | - <?php _e('Back to Login', 'fluent-community'); ?> | |
| 300 | + <?php esc_html_e('Back to Login', 'fluent-community'); ?> | |
| 165 | 301 | </a> |
| 166 | 302 | </div> |
| 167 | 303 | </div> |
| 168 | 304 | </div> |
| @@ -169,13 +305,13 @@ | ||
| 169 | 305 | </div> |
| 170 | 306 | </div> |
| 171 | 307 | <?php |
| 172 | 308 | } else if ($targetForm == 'accept_invitation') { |
| 173 | - do_action('fluent_community/auth/show_inviration_for_user', $inviation, $frameData); | |
| 309 | + do_action('fluent_community/auth/show_invitation_for_user', $inviation, $frameData); | |
| 174 | 310 | } else { |
| 175 | - //check if the registration is disabled | |
| 176 | - if (!AuthHelper::isRegistrationEnabled()) { | |
| 177 | - echo '<div class="fcom_completed"><div class="fcom_complted_header"><h4>' . __('Registration is disabled for this community', 'fluent-community') . '</h4>'; | |
| 311 | + //check if the registration is disabled (a valid invitation still allows signup) | |
| 312 | + if (!$inviation && !AuthHelper::isRegistrationEnabled()) { | |
| 313 | + echo '<div class="fcom_completed"><div class="fcom_complted_header"><h4>' . esc_html__('Registration is disabled for this community', 'fluent-community') . '</h4>'; | |
| 178 | 314 | return; |
| 179 | 315 | } |
| 180 | 316 | |
| 181 | 317 | $frameData['hiddenFields'] = [ |
| @@ -180,20 +316,45 @@ | ||
| 180 | 316 | |
| 181 | 317 | $frameData['hiddenFields'] = [ |
| 182 | 318 | 'register' => 'yes', |
| 183 | 319 | 'action' => 'fcom_user_signup', |
| 184 | - '_fls_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce') | |
| 320 | + '_fcom_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce') | |
| 185 | 321 | ]; |
| 186 | 322 | |
| 187 | 323 | $frameData['loginUrl'] = add_query_arg('form', 'login', $currentUrl); |
| 188 | - $frameData['description'] = __('Create an account to join the community', 'fluent-community'); | |
| 324 | + $frameData = wp_parse_args(Arr::get($formSettings, 'form'), $frameData); | |
| 325 | + | |
| 189 | 326 | $this->renderRegistrationForm($frameData, $inviation); |
| 190 | 327 | } |
| 191 | 328 | }, 10, 1); |
| 192 | 329 | |
| 193 | - status_header(200); | |
| 194 | - App::make('view')->render('headless_page', $pageVars); | |
| 195 | - exit(200); | |
| 330 | + add_action('fluent_community/headless/head_early', function ($scope) use ($formSettings) { | |
| 331 | + $bannerColors = array_filter(Arr::only($formSettings['banner'], ['title_color', 'text_color', 'background_color'])); | |
| 332 | + $css = Utility::getColorCssVariables(); | |
| 333 | + | |
| 334 | + $sideVars = ''; | |
| 335 | + foreach ($bannerColors as $colorKey => $colorValue) { | |
| 336 | + $sideVars .= '--fcom_' . $colorKey . ': ' . $colorValue . ';'; | |
| 337 | + } | |
| 338 | + ?> | |
| 339 | + <?php // the auth screen renders with load_wp, which skips headless_page's noindex ?> | |
| 340 | + <meta name="robots" content="noindex, noarchive" /> | |
| 341 | + <link rel="canonical" href="<?php echo esc_url(Helper::getAuthUrl()); ?>" /> | |
| 342 | + <style> | |
| 343 | + .fcom_layout_side { <?php echo esc_html($sideVars); ?> } | |
| 344 | + <?php echo esc_html($css); ?> | |
| 345 | + </style> | |
| 346 | + <?php | |
| 347 | + }); | |
| 348 | + | |
| 349 | + $pageVars['load_wp'] = 'yes'; | |
| 350 | + | |
| 351 | + // document title hook | |
| 352 | + add_filter('pre_get_document_title', function ($title) use ($frameData) { | |
| 353 | + return $frameData['title']; | |
| 354 | + }, 9999, 1); | |
| 355 | + | |
| 356 | + $this->renderPageAndExit('headless_page', $pageVars); | |
| 196 | 357 | } |
| 197 | 358 | |
| 198 | 359 | public function handleUserSignup() |
| 199 | 360 | { |
| @@ -200,11 +361,26 @@ | ||
| 200 | 361 | if (is_user_logged_in()) { |
| 201 | 362 | return $this->handleSignupCompleted(get_current_user_id()); |
| 202 | 363 | } |
| 203 | 364 | |
| 204 | - if (!AuthHelper::isRegistrationEnabled()) { | |
| 365 | + $signupNonce = isset($_POST['_fcom_signup_nonce']) ? sanitize_text_field(wp_unslash($_POST['_fcom_signup_nonce'])) : ''; | |
| 366 | + if (!$signupNonce || !wp_verify_nonce($signupNonce, 'fluent_auth_signup_nonce')) { | |
| 205 | 367 | wp_send_json([ |
| 206 | - 'message' => __('Registration is disabled for this community', 'fluent-community') | |
| 368 | + 'message' => esc_html__('Invalid request. Please refresh the page and try again.', 'fluent-community') | |
| 369 | + ], 403); | |
| 370 | + } | |
| 371 | + | |
| 372 | + $invitationToken = isset($_POST['invitation_token']) ? sanitize_text_field(wp_unslash($_POST['invitation_token'])) : ''; | |
| 373 | + $hasValidInvitation = false; | |
| 374 | + if ($invitationToken) { | |
| 375 | + $pendingInvitation = Invitation::where('message_rendered', $invitationToken)->first(); | |
| 376 | + $hasValidInvitation = $pendingInvitation && $pendingInvitation->isValid(); | |
| 377 | + } | |
| 378 | + | |
| 379 | + // A valid invitation must still allow signup even when public registration is disabled. | |
| 380 | + if (!$hasValidInvitation && !AuthHelper::isRegistrationEnabled()) { | |
| 381 | + wp_send_json([ | |
| 382 | + 'message' => esc_html__('Registration is disabled for this community', 'fluent-community') | |
| 207 | 383 | ], 422); |
| 208 | 384 | } |
| 209 | 385 | |
| 210 | 386 | $app = App::make('app'); |
| @@ -210,10 +386,15 @@ | ||
| 210 | 386 | $app = App::make('app'); |
| 211 | 387 | $request = $app->make('request'); |
| 212 | 388 | $fields = AuthHelper::getFormFields(); |
| 213 | 389 | |
| 390 | + $authSettings = AuthenticationService::getAuthSettings(); | |
| 391 | + $termsField = Arr::get($authSettings, 'signup.form.fields.terms'); | |
| 392 | + | |
| 393 | + $fields['terms'] = $termsField ?: $fields['terms']; | |
| 394 | + | |
| 214 | 395 | $requiredFields = array_filter($fields, function ($field) { |
| 215 | - return $field['required'] ?? false; | |
| 396 | + return ($field['required'] && empty($field['disabled'])) ?? false; | |
| 216 | 397 | }); |
| 217 | 398 | |
| 218 | 399 | $keys = array_keys($fields); |
| 219 | 400 | $data = Arr::only($request->all(), $keys); |
| @@ -222,9 +403,9 @@ | ||
| 222 | 403 | $data['username'] = sanitize_user(strtolower(preg_replace('/[^A-Za-z0-9_]/', '', $data['username']))); |
| 223 | 404 | |
| 224 | 405 | if (empty($data['username'])) { |
| 225 | 406 | wp_send_json([ |
| 226 | - 'message' => __('Username is not valid', 'fluent-community'), | |
| 407 | + 'message' => esc_html__('Username is not valid', 'fluent-community'), | |
| 227 | 408 | 'errors' => [ |
| 228 | 409 | 'username' => __('Please provide a valid username', 'fluent-community') |
| 229 | 410 | ] |
| 230 | 411 | ], 422); |
| @@ -231,9 +412,9 @@ | ||
| 231 | 412 | } |
| 232 | 413 | |
| 233 | 414 | if (!ProfileHelper::isUsernameAvailable($data['username'])) { |
| 234 | 415 | wp_send_json([ |
| 235 | - 'message' => __('Username is already taken', 'fluent-community'), | |
| 416 | + 'message' => esc_html__('Username is already taken', 'fluent-community'), | |
| 236 | 417 | 'errors' => [ |
| 237 | 418 | 'username' => __('Username is already taken. Please use a different username', 'fluent-community') |
| 238 | 419 | ] |
| 239 | 420 | ], 422); |
| @@ -238,8 +419,37 @@ | ||
| 238 | 419 | ] |
| 239 | 420 | ], 422); |
| 240 | 421 | } |
| 241 | 422 | |
| 423 | + $invitationToken = $request->get('invitation_token'); | |
| 424 | + $invitation = null; | |
| 425 | + if ($invitationToken) { | |
| 426 | + $invitation = Invitation::where('message_rendered', $invitationToken)->first(); | |
| 427 | + if (!$invitation) { | |
| 428 | + wp_send_json([ | |
| 429 | + 'message' => __('Invalid invitation token', 'fluent-community') | |
| 430 | + ], 422); | |
| 431 | + } | |
| 432 | + | |
| 433 | + if ($invitation->message && $invitation->message != $data['email']) { | |
| 434 | + wp_send_json([ | |
| 435 | + 'message' => esc_html__('Email does not match with the invitation', 'fluent-community') | |
| 436 | + ], 422); | |
| 437 | + } | |
| 438 | + | |
| 439 | + if ($invitation->message) { | |
| 440 | + add_filter('fluent_community/auth/two_factor_enabled', '__return_false'); | |
| 441 | + add_filter('fluent_auth/verify_signup_email', '__return_false'); | |
| 442 | + } | |
| 443 | + } | |
| 444 | + | |
| 445 | + if (!$invitation && AuthenticationService::getCustomSignupPageUrl()) { | |
| 446 | + // we have custom signup page enabled | |
| 447 | + wp_send_json([ | |
| 448 | + 'message' => esc_html__('Direct Registration is disabled for this community', 'fluent-community') | |
| 449 | + ], 422); | |
| 450 | + } | |
| 451 | + | |
| 242 | 452 | $data['email'] = sanitize_email($data['email']); |
| 243 | 453 | |
| 244 | 454 | $validations = [ |
| 245 | 455 | 'full_name' => 'required|max:100|string', |
| @@ -275,9 +485,9 @@ | ||
| 275 | 485 | ]); |
| 276 | 486 | |
| 277 | 487 | if ($validator->fails()) { |
| 278 | 488 | wp_send_json([ |
| 279 | - 'message' => __('Please fill all the required fields correctly', 'fluent-community'), | |
| 489 | + 'message' => __('Please fill in all required fields correctly.', 'fluent-community'), | |
| 280 | 490 | 'errors' => $validator->errors() |
| 281 | 491 | ], 422); |
| 282 | 492 | } |
| 283 | 493 | |
| @@ -297,16 +507,8 @@ | ||
| 297 | 507 | unset($data['full_name']); |
| 298 | 508 | $data = array_filter($data); |
| 299 | 509 | } |
| 300 | 510 | |
| 301 | - if (AuthHelper::isFluentAuthAvailable()) { | |
| 302 | - $data = wp_parse_args($data, $request->all()); | |
| 303 | - $this->handleSignupViaFlentAuth($data); | |
| 304 | - wp_send_json([ | |
| 305 | - 'message' => __('Something is not working! Please try again', 'fluent-community') | |
| 306 | - ], 422); | |
| 307 | - } | |
| 308 | - | |
| 309 | 511 | $rateLimit = AuthHelper::isAuthRateLimit(); |
| 310 | 512 | |
| 311 | 513 | if (is_wp_error($rateLimit)) { |
| 312 | 514 | wp_send_json([ |
| @@ -358,16 +560,14 @@ | ||
| 358 | 560 | } |
| 359 | 561 | |
| 360 | 562 | private function handleSignupViaFlentAuth($data) |
| 361 | 563 | { |
| 362 | - add_filter('fluent_auth/signup_form_data', function ($requestData) use ($data) { | |
| 363 | - return $data; | |
| 364 | - }); | |
| 365 | - | |
| 366 | 564 | add_action('fluent_auth/after_creating_user', function ($userId) { |
| 367 | 565 | $this->handleSignupCompleted($userId); |
| 368 | 566 | }, 1, 1); |
| 369 | 567 | |
| 568 | + add_filter('fluent_auth/signup_enabled', '__return_true'); | |
| 569 | + | |
| 370 | 570 | (new CustomAuthHandler())->handleSignupAjax(); |
| 371 | 571 | } |
| 372 | 572 | |
| 373 | 573 | private function handleSignupCompleted($userId) |
| @@ -373,18 +573,22 @@ | ||
| 373 | 573 | private function handleSignupCompleted($userId) |
| 374 | 574 | { |
| 375 | 575 | // We have the user now let's set the community membership |
| 376 | 576 | $user = User::find($userId); |
| 377 | - $user->syncXProfile(true); | |
| 577 | + $user->syncXProfile(true, true); | |
| 378 | 578 | |
| 379 | 579 | $redirectUrl = Helper::baseUrl(); |
| 380 | 580 | |
| 381 | - $redirectUrl = apply_filters('fluent_community/auth/after_signup_redirect_url', $redirectUrl, $user, $_REQUEST); | |
| 581 | + if (!empty($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 582 | + $redirectUrl = wp_validate_redirect(sanitize_url(wp_unslash($_REQUEST['redirect_to'])), Helper::baseUrl()); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 583 | + } | |
| 584 | + | |
| 585 | + $redirectUrl = apply_filters('fluent_community/auth/after_signup_redirect_url', $redirectUrl, $user, $_REQUEST); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 382 | 586 | $btnText = __('Continue to the community', 'fluent-community'); |
| 383 | 587 | |
| 384 | 588 | $html = '<div class="fcom_completed"><div class="fcom_complted_header"><h2>' . __('Congratulations!', 'fluent-community') . '</h2>'; |
| 385 | 589 | $html .= '<p>' . __('You have successfully registered to the community', 'fluent-community') . '</p></div>'; |
| 386 | - $html .= '<a href="' . $redirectUrl . '" class="fcom_btn fcom_btn_success">' . $btnText . '</a>'; | |
| 590 | + $html .= '<a href="' . esc_url($redirectUrl) . '" class="fcom_btn fcom_btn_success">' . $btnText . '</a>'; | |
| 387 | 591 | $html .= '</div>'; |
| 388 | 592 | |
| 389 | 593 | if (!get_current_user_id()) { |
| 390 | 594 | $wpUser = get_user_by('ID', $userId); |
| @@ -405,12 +609,19 @@ | ||
| 405 | 609 | } |
| 406 | 610 | |
| 407 | 611 | if (AuthHelper::isFluentAuthAvailable()) { |
| 408 | 612 | wp_send_json([ |
| 409 | - 'message' => __('This form can not be used to login. Please reload the page and try again', 'fluent-community') | |
| 613 | + 'message' => __('This form cannot be used to log in. Please reload the page and try again.', 'fluent-community') | |
| 410 | 614 | ], 422); |
| 411 | 615 | } |
| 412 | 616 | |
| 617 | + $loginNonce = isset($_POST['_fcom_login_nonce']) ? sanitize_text_field(wp_unslash($_POST['_fcom_login_nonce'])) : ''; | |
| 618 | + if (!$loginNonce || !wp_verify_nonce($loginNonce, 'fcom_user_login_nonce')) { | |
| 619 | + wp_send_json([ | |
| 620 | + 'message' => esc_html__('Invalid request. Please refresh the page and try again.', 'fluent-community') | |
| 621 | + ], 403); | |
| 622 | + } | |
| 623 | + | |
| 413 | 624 | $app = App::make('app'); |
| 414 | 625 | $request = $app->make('request'); |
| 415 | 626 | |
| 416 | 627 | $data = $request->all(); |
| @@ -439,10 +650,16 @@ | ||
| 439 | 650 | |
| 440 | 651 | $user = wp_authenticate($data['log'], $data['pwd']); |
| 441 | 652 | |
| 442 | 653 | if (is_wp_error($user)) { |
| 654 | + $enumerationCodes = ['invalid_username', 'invalid_email', 'incorrect_password']; | |
| 655 | + if (in_array($user->get_error_code(), $enumerationCodes, true)) { | |
| 656 | + $message = __('Email or password is incorrect.', 'fluent-community'); | |
| 657 | + } else { | |
| 658 | + $message = $user->get_error_message(); | |
| 659 | + } | |
| 443 | 660 | wp_send_json([ |
| 444 | - 'message' => $user->get_error_message() | |
| 661 | + 'message' => $message | |
| 445 | 662 | ], 422); |
| 446 | 663 | } |
| 447 | 664 | |
| 448 | 665 | InvitationService::makeLogin($user); |
| @@ -447,13 +664,13 @@ | ||
| 447 | 664 | |
| 448 | 665 | InvitationService::makeLogin($user); |
| 449 | 666 | |
| 450 | 667 | $redirectUrl = null; |
| 451 | - if(!empty($_REQUEST['redirect_to'])) { | |
| 452 | - $redirectUrl = sanitize_url($_REQUEST['redirect_to']); | |
| 668 | + if (!empty($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 669 | + $redirectUrl = wp_validate_redirect(sanitize_url(wp_unslash($_REQUEST['redirect_to'])), Helper::baseUrl()); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 453 | 670 | } |
| 454 | 671 | |
| 455 | - if(!$redirectUrl) { | |
| 672 | + if (!$redirectUrl) { | |
| 456 | 673 | $redirectUrl = Helper::baseUrl(); |
| 457 | 674 | } |
| 458 | 675 | |
| 459 | 676 | if ($invitationToken = $request->get('invitation_token')) { |
| @@ -476,9 +693,9 @@ | ||
| 476 | 693 | $btnText = __('Continue to the community', 'fluent-community'); |
| 477 | 694 | |
| 478 | 695 | $html = '<div class="fcom_completed"><div class="fcom_complted_header"><h2>' . __('Welcome back!', 'fluent-community') . '</h2>'; |
| 479 | 696 | $html .= '<p>' . __('You have successfully logged in to the community', 'fluent-community') . '</p></div>'; |
| 480 | - $html .= '<a href="' . $redirectUrl . '" class="fcom_btn fcom_btn_success">' . $btnText . '</a>'; | |
| 697 | + $html .= '<a href="' . esc_url($redirectUrl) . '" class="fcom_btn fcom_btn_success">' . $btnText . '</a>'; | |
| 481 | 698 | $html .= '</div>'; |
| 482 | 699 | |
| 483 | 700 | wp_send_json([ |
| 484 | 701 | 'success_html' => $html, |
| @@ -489,9 +706,12 @@ | ||
| 489 | 706 | public function showLoginForm($frameData, $invitation = null) |
| 490 | 707 | { |
| 491 | 708 | $portalSettings = Helper::generalSettings(); |
| 492 | 709 | $isFluentAuth = AuthHelper::isFluentAuthAvailable(); |
| 493 | - $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); | |
| 710 | + $loginSettings = AuthenticationService::getFormattedAuthSettings('login'); | |
| 711 | + $formSettings = Arr::get($loginSettings, 'form'); | |
| 712 | + $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 713 | + /* translators: %s is replaced by the title of the site */ | |
| 494 | 714 | $title = sprintf(__('Login to %s', 'fluent-community'), Arr::get($portalSettings, 'site_title')); |
| 495 | 715 | |
| 496 | 716 | $description = ''; |
| 497 | 717 | if ($invitation) { |
| @@ -501,21 +721,62 @@ | ||
| 501 | 721 | if ($space) { |
| 502 | 722 | $title = $space->title . ' - ' . Arr::get($portalSettings, 'site_title'); |
| 503 | 723 | } |
| 504 | 724 | } |
| 505 | - $description = sprintf(__('%s has invited you to join this community. Please login to accept your invitation.', 'fluent-community'), $invitationBy); | |
| 725 | + /* translators: %s is replaced by the name of the inviter */ | |
| 726 | + $inviteDescription = \sprintf(__('%s has invited you to join this community. Please login to accept your invitation.', 'fluent-community'), $invitationBy); | |
| 727 | + add_action('fluent_community/before_auth_form_header', function ($formType) use ($inviteDescription) { | |
| 728 | + ?> | |
| 729 | + <div class="fcom_highlight_message"> | |
| 730 | + <?php echo wp_kses_post($inviteDescription); ?> | |
| 731 | + </div> | |
| 732 | + <?php | |
| 733 | + }); | |
| 506 | 734 | } |
| 507 | 735 | |
| 736 | + $signupUrl = add_query_arg('form', 'register', $currentUrl); | |
| 737 | + | |
| 738 | + if (!$invitation) { | |
| 739 | + if ($customSignupUrl = AuthenticationService::getCustomSignupPageUrl()) { | |
| 740 | + $signupUrl = $customSignupUrl; | |
| 741 | + } | |
| 742 | + } | |
| 743 | + | |
| 744 | + add_filter('login_form_defaults', function ($defaults) use ($invitation, $frameData) { | |
| 745 | + $defaults['label_log_in'] = Arr::get($frameData, 'button_label'); | |
| 746 | + return $defaults; | |
| 747 | + }); | |
| 748 | + | |
| 508 | 749 | if ($isFluentAuth) { |
| 750 | + add_filter('login_form_top', function () use ($invitation) { | |
| 751 | + $reditectUrl = Arr::get($_GET, 'redirect_to'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 752 | + if (!$reditectUrl) { | |
| 753 | + $reditectUrl = apply_filters('fluent_community/default_redirect_url', Helper::baseUrl()); | |
| 754 | + } | |
| 755 | + ob_start(); | |
| 756 | + ?> | |
| 757 | + <?php if ($invitation) { ?> | |
| 758 | + <input type="hidden" name="invitation_token" value="<?php echo esc_attr($invitation->message_rendered); ?>"/> | |
| 759 | + <?php } ?> | |
| 760 | + <input name="is_fcom_auth" type="hidden" value="yes"/> | |
| 761 | + <input type="hidden" name="fcom_redirect" value="<?php echo esc_url($reditectUrl); ?>"/> | |
| 762 | + <?php | |
| 763 | + return ob_get_clean(); | |
| 764 | + }); | |
| 509 | 765 | ?> |
| 510 | 766 | <div id="fcom_user_onboard_wrap" class="fcom_user_onboard"> |
| 511 | 767 | <div class="fcom_onboard_header"> |
| 768 | + <?php do_action('fluent_community/before_auth_form_header', 'login'); ?> | |
| 512 | 769 | <div class="fcom_onboard_header_title"> |
| 513 | - <h2><?php echo esc_html($title); ?></h2> | |
| 770 | + <?php if (!empty($formSettings['title'])): ?> | |
| 771 | + <h2> | |
| 772 | + <?php echo esc_html($formSettings['title']); ?> | |
| 773 | + </h2> | |
| 774 | + <?php endif; ?> | |
| 514 | 775 | </div> |
| 515 | - <?php if ($description): ?> | |
| 776 | + <?php if (!empty($formSettings['description'])): ?> | |
| 516 | 777 | <div class="fcom_onboard_sub"> |
| 517 | - <p><?php echo wp_kses_post($description); ?></p> | |
| 778 | + <?php echo wp_kses_post(trim($formSettings['description'])); ?> | |
| 518 | 779 | </div> |
| 519 | 780 | <?php endif; ?> |
| 520 | 781 | </div> |
| 521 | 782 | <div class="fcom_onboard_body"> |
| @@ -521,19 +782,19 @@ | ||
| 521 | 782 | <div class="fcom_onboard_body"> |
| 522 | 783 | <div class="fcom_onboard_form"> |
| 523 | 784 | <?php echo do_shortcode('[fluent_auth_login redirect_to="' . esc_url($currentUrl) . '"]'); ?> |
| 524 | 785 | <div class="fcom_spaced_divider"> |
| 525 | - <?php if (AuthHelper::isRegistrationEnabled()): ?> | |
| 786 | + <?php if ($invitation || AuthHelper::isRegistrationEnabled()): ?> | |
| 526 | 787 | <div class="fcom_alt_auth_text"> |
| 527 | - <?php _e('Don\'t have an account?', 'fluent-community'); ?> | |
| 528 | - <a href="<?php echo esc_url(add_query_arg('form', 'register', $currentUrl)); ?>"> | |
| 529 | - <?php _e('Signup', 'fluent-community'); ?> | |
| 788 | + <?php esc_html_e('Don\'t have an account?', 'fluent-community'); ?> | |
| 789 | + <a href="<?php echo esc_url($signupUrl); ?>"> | |
| 790 | + <?php esc_html_e('Signup', 'fluent-community'); ?> | |
| 530 | 791 | </a> |
| 531 | 792 | </div> |
| 532 | 793 | <?php endif; ?> |
| 533 | 794 | <p class="fcom_reset_pass_text"> |
| 534 | - <a href="<?php echo esc_url(add_query_arg('form', 'reset_password', $currentUrl)); ?>"> | |
| 535 | - <?php _e('Lost your password?', 'fluent-community'); ?> | |
| 795 | + <a href="<?php echo esc_url(AuthHelper::getLostPasswordUrl($currentUrl)); ?>"> | |
| 796 | + <?php esc_html_e('Lost your password?', 'fluent-community'); ?> | |
| 536 | 797 | </a> |
| 537 | 798 | </p> |
| 538 | 799 | </div> |
| 539 | 800 | </div> |
| @@ -544,11 +805,14 @@ | ||
| 544 | 805 | } |
| 545 | 806 | |
| 546 | 807 | $frameData['redirect'] = $currentUrl; |
| 547 | 808 | |
| 548 | - $frameData['hiddenFields'] = []; | |
| 809 | + $frameData['hiddenFields'] = [ | |
| 810 | + 'action' => 'fcom_user_login_form', | |
| 811 | + '_fcom_login_nonce' => wp_create_nonce('fcom_user_login_nonce'), | |
| 812 | + ]; | |
| 549 | 813 | if ($invitation) { |
| 550 | - $frameData['loginBtnText'] = __('Log In & Accept Invitation', 'fluent-community'); | |
| 814 | + $frameData['button_label'] = __('Log In & Accept Invitation', 'fluent-community'); | |
| 551 | 815 | $frameData['hiddenFields']['invitation_token'] = $invitation->message_rendered; |
| 552 | 816 | } |
| 553 | 817 | |
| 554 | 818 | $frameData['title'] = $title; |
| @@ -557,14 +821,16 @@ | ||
| 557 | 821 | $frameData['defaults'] = [ |
| 558 | 822 | 'email' => $invitation ? $invitation->message : '' |
| 559 | 823 | ]; |
| 560 | 824 | |
| 561 | - if (AuthHelper::isRegistrationEnabled()) { | |
| 562 | - $frameData['signupUrl'] = add_query_arg('form', 'register', $currentUrl); | |
| 825 | + if ($invitation || AuthHelper::isRegistrationEnabled()) { | |
| 826 | + $frameData['signupUrl'] = $signupUrl; | |
| 563 | 827 | } |
| 564 | 828 | |
| 565 | - if(isset($_GET['redirect_to'])) { | |
| 566 | - $frameData['redirect_to'] = sanitize_url($_GET['redirect_to']); | |
| 829 | + $frameData['settings'] = $formSettings; | |
| 830 | + | |
| 831 | + if (isset($_GET['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 832 | + $frameData['redirect_to'] = sanitize_url(wp_unslash($_GET['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 567 | 833 | } |
| 568 | 834 | |
| 569 | 835 | App::make('view')->render('auth.login_form', $frameData); |
| 570 | 836 | } |
| @@ -572,8 +838,28 @@ | ||
| 572 | 838 | public function renderRegistrationForm($frameData, $invitation = null) |
| 573 | 839 | { |
| 574 | 840 | $formFields = AuthHelper::getFormFields($invitation); |
| 575 | 841 | |
| 842 | + // Prefill the name from the invitation link's query param when present. | |
| 843 | + $inviteName = isset($_GET['invite_name']) ? sanitize_text_field(wp_unslash($_GET['invite_name'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 844 | + if ($inviteName && isset($formFields['full_name']) && empty($formFields['full_name']['value'])) { | |
| 845 | + $formFields['full_name']['value'] = $inviteName; | |
| 846 | + } | |
| 847 | + | |
| 848 | + $authSettings = AuthenticationService::getAuthSettings(); | |
| 849 | + | |
| 850 | + $termsField = Arr::get($authSettings, 'signup.form.fields.terms'); | |
| 851 | + | |
| 852 | + | |
| 853 | + if ($termsField) { | |
| 854 | + unset($termsField['label']); | |
| 855 | + | |
| 856 | + // add new tab on the link for $termsField['inline_label'] | |
| 857 | + $termsField['inline_label'] = FeedsHelper::addNewTabToLinks($termsField['inline_label']); | |
| 858 | + | |
| 859 | + $formFields['terms'] = $termsField; | |
| 860 | + } | |
| 861 | + | |
| 576 | 862 | $frameData['formFields'] = $formFields; |
| 577 | 863 | |
| 578 | 864 | if ($invitation) { |
| 579 | 865 | $frameData['hiddenFields'] = [ |
| @@ -578,21 +864,50 @@ | ||
| 578 | 864 | if ($invitation) { |
| 579 | 865 | $frameData['hiddenFields'] = [ |
| 580 | 866 | 'invitation_token' => $invitation->message_rendered, |
| 581 | 867 | 'action' => 'fcom_user_registration', |
| 582 | - '_fls_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce') | |
| 868 | + '_fcom_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce') | |
| 583 | 869 | ]; |
| 584 | 870 | |
| 585 | 871 | $invitationBy = $invitation->xprofile ? $invitation->xprofile->display_name : __('Someone', 'fluent-community'); |
| 586 | - $frameData['description'] = sprintf(__('%s has invited you to join this community. Please create an account to accept your invitation.', 'fluent-community'), $invitationBy); | |
| 587 | - $frameData['signupBtnText'] = __('Register & Accept invitation', 'fluent-community'); | |
| 872 | + /* translators: %s is replaced by the name of the inviter */ | |
| 873 | + $inviteDescription = sprintf(__('%s has invited you to join this community. Please create an account to accept your invitation.', 'fluent-community'), $invitationBy); | |
| 874 | + | |
| 875 | + add_action('fluent_community/before_auth_form_header', function ($formType) use ($inviteDescription) { | |
| 876 | + ?> | |
| 877 | + <div class="fcom_highlight_message"> | |
| 878 | + <?php echo wp_kses_post($inviteDescription); ?> | |
| 879 | + </div> | |
| 880 | + <?php | |
| 881 | + }); | |
| 882 | + | |
| 883 | + $frameData['button_label'] = __('Register & Accept invitation', 'fluent-community'); | |
| 588 | 884 | } else { |
| 589 | 885 | $frameData['hiddenFields'] = [ |
| 590 | 886 | 'register' => 'yes', |
| 591 | 887 | 'action' => 'fcom_user_registration', |
| 592 | - '_fls_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce') | |
| 888 | + '_fcom_signup_nonce' => wp_create_nonce('fluent_auth_signup_nonce'), | |
| 593 | 889 | ]; |
| 890 | + | |
| 891 | + if (!empty($_GET['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 892 | + $frameData['hiddenFields']['redirect_to'] = sanitize_url(wp_unslash($_GET['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 893 | + } | |
| 594 | 894 | } |
| 895 | + | |
| 896 | + add_action('fluent_community/before_registration_form', function ($frameData) { | |
| 897 | + if (AuthHelper::isFluentAuthAvailable()) { | |
| 898 | + $currentUrl = esc_url(home_url(add_query_arg($_GET, $GLOBALS['wp']->request))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 899 | + | |
| 900 | + $titlePrefix = __('Signup with', 'fluent-community'); | |
| 901 | + $html = do_shortcode('[fs_auth_buttons redirect="' . $currentUrl . '" title_prefix="' . $titlePrefix . ' " title=""]'); | |
| 902 | + | |
| 903 | + if ($html) { | |
| 904 | + echo '<div class="fcom_social_auth_wrap">'; | |
| 905 | + echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 906 | + echo '</div>'; | |
| 907 | + } | |
| 908 | + } | |
| 909 | + }); | |
| 595 | 910 | |
| 596 | 911 | App::make('view')->render('auth.user_invitation', $frameData); |
| 597 | 912 | } |
| 598 | 913 | } |