| @@ -2,10 +2,15 @@ | ||
| 2 | 2 | |
| 3 | 3 | namespace FluentSupport\App\Hooks\Handlers; |
| 4 | 4 | |
| 5 | 5 | use FluentSupport\App\App; |
| 6 | +use FluentSupport\App\Modules\PermissionManager; | |
| 7 | +use FluentSupport\App\Services\FluentAuthBridge; | |
| 6 | 8 | use FluentSupport\App\Services\Helper; |
| 9 | +use FluentSupport\App\Services\Includes\CountryNames; | |
| 10 | +use FluentSupport\App\Vite; | |
| 7 | 11 | use FluentSupport\Framework\Support\Arr; |
| 12 | +use FluentSupport\App\Models\Meta; | |
| 8 | 13 | |
| 9 | 14 | class AuthHandler |
| 10 | 15 | { |
| 11 | 16 | |
| @@ -15,25 +20,55 @@ | ||
| 15 | 20 | { |
| 16 | 21 | add_shortcode('fluent_support_login', array($this, 'loginForm')); |
| 17 | 22 | add_shortcode('fluent_support_signup', array($this, 'registrationForm')); |
| 18 | 23 | add_shortcode('fluent_support_auth', array($this, 'authForm')); |
| 24 | + add_shortcode('fluent_support_reset_password', array($this, 'restPasswordForm')); | |
| 25 | + add_action('wp_ajax_fluent_support_renew_rest_nonce', [$this, 'maybeRenewNonce']); | |
| 26 | + | |
| 27 | + FluentAuthBridge::register(); | |
| 19 | 28 | } |
| 20 | 29 | |
| 30 | + /** | |
| 31 | + * @param $attributes | |
| 32 | + * @return string | |
| 33 | + */ | |
| 21 | 34 | public function loginForm($attributes) |
| 22 | 35 | { |
| 23 | 36 | if (get_current_user_id()) { |
| 24 | - return ''; | |
| 37 | + return '<p>' . __('You are already logged in.', 'fluent-support') . '</p>'; | |
| 25 | 38 | } |
| 26 | 39 | |
| 27 | - $this->loadAssets(); | |
| 28 | 40 | $attributes = $this->getShortcodes($attributes); |
| 41 | + if (!empty($attributes['redirect-to'])) { | |
| 42 | + $redirect = $attributes['redirect-to']; | |
| 43 | + } else { | |
| 44 | + $redirect = Helper::getPortalBaseUrl(); | |
| 45 | + } | |
| 46 | + | |
| 47 | + | |
| 29 | 48 | $this->handleAlreadyLoggedIn($attributes); |
| 30 | 49 | |
| 31 | - $return = '<div id="fst_login_form" class="fst_login_wrapper">'; | |
| 50 | + if ($this->authProvider() == 'fluent_auth') { | |
| 51 | + $attributes['redirect_to'] = $redirect; | |
| 52 | + return $this->renderFluentAuthForms($attributes); | |
| 53 | + } | |
| 32 | 54 | |
| 55 | + $this->loadAssets(); | |
| 56 | + | |
| 57 | + $return = '<div class="fst_login_form_auth_wrapper">'; | |
| 58 | + $return .= '<div id="fst_login_form" class="fst_login_wrapper">'; | |
| 59 | + | |
| 60 | + | |
| 61 | + /* | |
| 62 | + * Filter login form | |
| 63 | + * | |
| 64 | + * @since v1.0.0 | |
| 65 | + * | |
| 66 | + * @param array $loginArgs | |
| 67 | + */ | |
| 33 | 68 | $loginArgs = apply_filters('fluent_support/login_form_args', [ |
| 34 | 69 | 'echo' => false, |
| 35 | - 'redirect' => Helper::getPortalBaseUrl(), | |
| 70 | + 'redirect' => $redirect, | |
| 36 | 71 | 'remember' => true, |
| 37 | 72 | 'value_remember' => true, |
| 38 | 73 | ]); |
| 39 | 74 | |
| @@ -42,30 +77,79 @@ | ||
| 42 | 77 | if ($attributes['show-signup'] == 'true') { |
| 43 | 78 | $return .= '<p style="text-align: center">' |
| 44 | 79 | . __('Not registered?', 'fluent-support') |
| 45 | 80 | . ' <a href="#" id="fs_show_signup">' |
| 46 | - . __('Create an Account', 'fluent-support') | |
| 81 | + . __('Create an account', 'fluent-support') | |
| 47 | 82 | . '</a></p>'; |
| 48 | 83 | } |
| 49 | 84 | |
| 85 | + if ($attributes['show-reset-password'] == 'true') { | |
| 86 | + $return .= '<p style="text-align: center">' | |
| 87 | + . __('Forgot your password?', 'fluent-support') | |
| 88 | + . ' <a href="#" id="fs_show_reset_password">' | |
| 89 | + . __('Reset password', 'fluent-support') | |
| 90 | + . '</a></p>'; | |
| 91 | + } | |
| 92 | + | |
| 50 | 93 | $return .= '</div>'; |
| 94 | + | |
| 95 | + if ($attributes['show-signup'] == 'true') { | |
| 96 | + $return .= do_shortcode('[fluent_support_signup hide=true]'); | |
| 97 | + } | |
| 98 | + | |
| 99 | + if ($attributes['show-reset-password'] == 'true') { | |
| 100 | + $return .= do_shortcode('[fluent_support_reset_password hide=true]'); | |
| 101 | + } | |
| 102 | + | |
| 103 | + $return .= '</div>'; | |
| 51 | 104 | return $return; |
| 52 | 105 | } |
| 53 | 106 | |
| 107 | + /** | |
| 108 | + * @param $attributes | |
| 109 | + * @return string | |
| 110 | + */ | |
| 54 | 111 | public function registrationForm($attributes) |
| 55 | 112 | { |
| 56 | 113 | if (get_current_user_id()) { |
| 57 | - return ''; | |
| 114 | + return '<p>' . __('You are already logged in.', 'fluent-support') . '</p>'; | |
| 58 | 115 | } |
| 59 | 116 | |
| 60 | 117 | $attributes = $this->getShortcodes($attributes); |
| 61 | 118 | $this->handleAlreadyLoggedIn($attributes); |
| 62 | 119 | |
| 120 | + if (!Helper::isSignupEnabled()) { | |
| 121 | + if ($attributes['hide'] == 'true') { | |
| 122 | + return ''; | |
| 123 | + } | |
| 124 | + | |
| 125 | + return '<p>' . __('User registration is not enabled on this site.', 'fluent-support') . '</p>'; | |
| 126 | + } | |
| 127 | + | |
| 128 | + if ($this->authProvider() == 'fluent_auth') { | |
| 129 | + return FluentAuthBridge::render(function () use ($attributes) { | |
| 130 | + return (new \FluentAuth\App\Hooks\Handlers\CustomAuthHandler())->registrationForm($attributes); | |
| 131 | + }, $attributes['redirect_to']); | |
| 132 | + } | |
| 133 | + | |
| 134 | + $customFieldsKey = Helper::getCustomRegistrationFieldKeys(); | |
| 135 | + | |
| 136 | + if (!empty($customFieldsKey)) { | |
| 137 | + add_filter('fluent_support/registration_form_fields', function($fields) use ($customFieldsKey) { | |
| 138 | + return $this->addCustomFieldsToRegistrationForm($fields,$customFieldsKey); | |
| 139 | + }); | |
| 140 | + } | |
| 141 | + | |
| 63 | 142 | $registrationFields = static::getSignupFields(); |
| 64 | 143 | $hide = $attributes['hide'] == 'true' ? 'hide' : ''; |
| 65 | 144 | |
| 66 | 145 | $this->loadAssets($hide); |
| 67 | 146 | |
| 147 | + return $this->buildRegistrationForm($registrationFields, $hide, $attributes); | |
| 148 | + } | |
| 149 | + | |
| 150 | + private function buildRegistrationForm($registrationFields, $hide, $attributes) | |
| 151 | + { | |
| 68 | 152 | $registrationForm = '<div class="fst_registration_wrapper ' . $hide . '"><form id="fstRegistrationForm" class="fs_registration_form" method="post" name="fs_registration_form">'; |
| 69 | 153 | |
| 70 | 154 | foreach ($registrationFields as $fieldName => $registrationField) { |
| 71 | 155 | $registrationForm .= $this->renderField($fieldName, $registrationField); |
| @@ -70,14 +154,16 @@ | ||
| 70 | 154 | foreach ($registrationFields as $fieldName => $registrationField) { |
| 71 | 155 | $registrationForm .= $this->renderField($fieldName, $registrationField); |
| 72 | 156 | } |
| 73 | 157 | |
| 74 | - $registrationForm .= '<input type="hidden" name="__redirect_to" value="' . $attributes['redirect-to'] . '">'; | |
| 158 | + $registrationForm .= '<input type="hidden" name="__redirect_to" value="' . esc_url($attributes['redirect-to']) . '">'; | |
| 75 | 159 | $registrationForm .= '<input type="hidden" name="_fsupport_signup_nonce" value="' . wp_create_nonce('fluent_support_signup_nonce') . '">'; |
| 76 | 160 | $registrationForm .= '<button type="submit" id="fst_submit">' . $this->submitBtnLoadingSvg() . '<span>' . __('Signup', 'fluent-support') . '</span></button>'; |
| 77 | 161 | |
| 78 | 162 | $registrationForm .= '</form>'; |
| 79 | 163 | |
| 164 | + $registrationForm .= apply_filters('fluent_support/before_registration_form_close', '', $registrationFields, $attributes); | |
| 165 | + | |
| 80 | 166 | if ($hide) { |
| 81 | 167 | $registrationForm .= '<p style="text-align: center">' |
| 82 | 168 | . __('Already have an account?', 'fluent-support') |
| 83 | 169 | . ' <a href="#" id="fs_show_login">' |
| @@ -89,20 +175,107 @@ | ||
| 89 | 175 | |
| 90 | 176 | return $registrationForm; |
| 91 | 177 | } |
| 92 | 178 | |
| 179 | + public function restPasswordForm($attributes) | |
| 180 | + { | |
| 181 | + if (get_current_user_id()) { | |
| 182 | + return '<p>' . __('You are already logged in.', 'fluent-support') . '</p>'; | |
| 183 | + } | |
| 184 | + | |
| 185 | + $attributes = $this->getShortcodes($attributes); | |
| 186 | + | |
| 187 | + if ($this->authProvider() == 'fluent_auth') { | |
| 188 | + return FluentAuthBridge::render(function () use ($attributes) { | |
| 189 | + return (new \FluentAuth\App\Hooks\Handlers\CustomAuthHandler())->restPasswordForm($attributes); | |
| 190 | + }, $attributes['redirect_to']); | |
| 191 | + } | |
| 192 | + | |
| 193 | + $this->handleAlreadyLoggedIn($attributes); | |
| 194 | + | |
| 195 | + $resetPasswordFields = static::resetPasswordFields(); | |
| 196 | + $hide = $attributes['hide'] == 'true' ? 'hide' : ''; | |
| 197 | + | |
| 198 | + $this->loadAssets($hide); | |
| 199 | + | |
| 200 | + return $this->buildResetPassForm($resetPasswordFields, $hide, $attributes); | |
| 201 | + } | |
| 202 | + | |
| 203 | + private function buildResetPassForm($resetPasswordFields, $hide, $attributes) | |
| 204 | + { | |
| 205 | + $restePasswordForm = '<div class="fst_reset_pass_wrapper ' . $hide . '"><form id="fstResetPasswordForm" class="fs_reset_pass_form" method="post" name="fs_reset_pass_form">'; | |
| 206 | + | |
| 207 | + foreach ($resetPasswordFields as $fieldName => $resetPasswordField) { | |
| 208 | + $restePasswordForm .= $this->renderField($fieldName, $resetPasswordField); | |
| 209 | + } | |
| 210 | + | |
| 211 | + $restePasswordForm .= '<input type="hidden" name="__redirect_to" value="' . esc_url($attributes['redirect-to']) . '">'; | |
| 212 | + $restePasswordForm .= '<input type="hidden" name="_fsupport_reset_pass_nonce" value="' . wp_create_nonce('fluent_support_reset_pass_nonce') . '">'; | |
| 213 | + $restePasswordForm .= '<button type="submit" id="fst_reset_pass">' . $this->submitBtnLoadingSvg() . '<span>' . __('Reset Password', 'fluent-support') . '</span></button>'; | |
| 214 | + | |
| 215 | + $restePasswordForm .= '</form>'; | |
| 216 | + | |
| 217 | + $restePasswordForm .= '</div>'; | |
| 218 | + | |
| 219 | + return $restePasswordForm; | |
| 220 | + } | |
| 221 | + | |
| 222 | + /** | |
| 223 | + * Login form with signup and reset links, or FluentAuth's form when it is the provider. | |
| 224 | + * | |
| 225 | + * @param $attributes | |
| 226 | + * @return string | |
| 227 | + */ | |
| 93 | 228 | public function authForm($attributes) |
| 94 | 229 | { |
| 95 | - $authForm = '<div class="fst_auth_wrapper">'; | |
| 230 | + if (get_current_user_id()) { | |
| 231 | + // translators: %s is the URL to the support portal | |
| 232 | + return '<p>' . sprintf(__('You are already logged in. <a href="%s">Go to support portal</a>', 'fluent-support'), Helper::getPortalBaseUrl()) . '</p>'; | |
| 233 | + } | |
| 96 | 234 | |
| 97 | - $authForm .= do_shortcode('[fluent_support_login show-signup=true]'); | |
| 98 | - $authForm .= do_shortcode('[fluent_support_signup hide=true]'); | |
| 235 | + $attributes = $this->getShortcodes($attributes, true); | |
| 99 | 236 | |
| 100 | - $authForm .= '</div>'; | |
| 237 | + if ($this->authProvider() == 'fluent_auth') { | |
| 238 | + return $this->renderFluentAuthForms($attributes); | |
| 239 | + } | |
| 101 | 240 | |
| 102 | - return $authForm; | |
| 241 | + return $this->loginForm($attributes); | |
| 103 | 242 | } |
| 104 | 243 | |
| 244 | + /** | |
| 245 | + * FluentAuth's login form, plus its signup and reset forms (hidden) when the shortcode | |
| 246 | + * shows them. Its "Create an Account" and "Reset Password" links open a form that must | |
| 247 | + * already be on the page, and its own authForm() always adds reset, so we pick the | |
| 248 | + * forms here. FluentAuth renders and processes each one. | |
| 249 | + * | |
| 250 | + * @param array $attributes | |
| 251 | + * @return string | |
| 252 | + */ | |
| 253 | + private function renderFluentAuthForms($attributes) | |
| 254 | + { | |
| 255 | + return FluentAuthBridge::render(function () use ($attributes) { | |
| 256 | + $handler = new \FluentAuth\App\Hooks\Handlers\CustomAuthHandler(); | |
| 257 | + $hidden = array_merge($attributes, ['hide' => 'true']); | |
| 258 | + | |
| 259 | + $html = '<div class="fls_auth_wrapper">' . $handler->loginForm($attributes); | |
| 260 | + | |
| 261 | + if ($attributes['show-signup'] == 'true') { | |
| 262 | + $html .= $handler->registrationForm($hidden); | |
| 263 | + } | |
| 264 | + | |
| 265 | + if ($attributes['show-reset-password'] == 'true') { | |
| 266 | + $html .= $handler->restPasswordForm($hidden); | |
| 267 | + } | |
| 268 | + | |
| 269 | + return $html . '</div>'; | |
| 270 | + }, $attributes['redirect_to']); | |
| 271 | + } | |
| 272 | + | |
| 273 | + /** | |
| 274 | + * @param $fieldName | |
| 275 | + * @param $field | |
| 276 | + * @return string | |
| 277 | + */ | |
| 105 | 278 | private function renderField($fieldName, $field) |
| 106 | 279 | { |
| 107 | 280 | $fieldType = Arr::get($field, 'type'); |
| 108 | 281 | $isRequired = Arr::get($field, 'required'); |
| @@ -107,44 +280,99 @@ | ||
| 107 | 280 | $fieldType = Arr::get($field, 'type'); |
| 108 | 281 | $isRequired = Arr::get($field, 'required'); |
| 109 | 282 | $isRequired = $isRequired ? 'is-required' : ''; |
| 110 | 283 | |
| 111 | - $textTypes = ['text', 'email', 'password']; | |
| 284 | + $html = '<div class="fst_field_group fst_field_' . $fieldName . '">'; | |
| 112 | 285 | |
| 113 | - $html = '<div class="fst_field_group fst_field_' . $fieldName . '">'; | |
| 114 | 286 | if ($label = Arr::get($field, 'label')) { |
| 115 | 287 | $html .= '<div class="fst_field_label ' . $isRequired . '"><label for="' . Arr::get($field, 'id') . '">' . $label . '</label></div>'; |
| 116 | 288 | } |
| 117 | 289 | |
| 290 | + $textTypes = ['text', 'email', 'password', 'number', 'date']; | |
| 291 | + $selectTypes = ['select']; | |
| 292 | + | |
| 118 | 293 | if (in_array($fieldType, $textTypes)) { |
| 294 | + $html .= $this->renderTextInput($fieldName, $field); | |
| 295 | + } elseif (in_array($fieldType, $selectTypes)) { | |
| 296 | + $html .= $this->renderSelectInput($fieldName, $field); | |
| 297 | + } else { | |
| 298 | + return ''; | |
| 299 | + } | |
| 119 | 300 | |
| 120 | - $inputAtts = array_filter([ | |
| 121 | - 'type' => esc_attr($fieldType), | |
| 122 | - 'id' => esc_attr(Arr::get($field, 'id')), | |
| 123 | - 'placeholder' => esc_attr(Arr::get($field, 'placeholder')), | |
| 124 | - 'name' => esc_attr($fieldName) | |
| 125 | - ]); | |
| 301 | + $html = $html . '</div>'; | |
| 126 | 302 | |
| 127 | - $atts = ''; | |
| 303 | + return '<div class="fst_registration_fields">' . $html . '</div>'; | |
| 304 | + } | |
| 128 | 305 | |
| 129 | - foreach ($inputAtts as $attKey => $att) { | |
| 130 | - $atts .= $attKey . '="' . $att . '" '; | |
| 131 | - } | |
| 306 | + private function renderTextInput($fieldName, $field) | |
| 307 | + { | |
| 308 | + $inputAtts = array_filter([ | |
| 309 | + 'type' => esc_attr(Arr::get($field, 'type', '')), | |
| 310 | + 'id' => esc_attr(Arr::get($field, 'id', '')), | |
| 311 | + 'placeholder' => esc_attr(Arr::get($field, 'placeholder', '')), | |
| 312 | + 'name' => esc_attr($fieldName), | |
| 313 | + 'required' => Arr::get($field, 'required') ? 'required' : '', | |
| 314 | + ]); | |
| 132 | 315 | |
| 133 | - if (Arr::get($field, 'required')) { | |
| 134 | - $atts .= 'required'; | |
| 135 | - } | |
| 316 | + $atts = ''; | |
| 136 | 317 | |
| 137 | - $html .= '<div class="fs_input_wrap"><input ' . $atts . '/></div>'; | |
| 138 | - } else { | |
| 139 | - return ''; | |
| 318 | + foreach ($inputAtts as $attKey => $att) { | |
| 319 | + $atts .= $attKey . '="' . $att . '" '; | |
| 140 | 320 | } |
| 141 | 321 | |
| 142 | - return $html . '</div>'; | |
| 322 | + return '<div class="fs_input_wrap"><input ' . $atts . ' /></div>'; | |
| 143 | 323 | } |
| 144 | 324 | |
| 325 | + /** | |
| 326 | + * @param string $fieldName | |
| 327 | + * @param array $field Field config with options and attributes. | |
| 328 | + * @return string | |
| 329 | + */ | |
| 330 | + private function renderSelectInput($fieldName, $field) | |
| 331 | + { | |
| 332 | + $choices = Arr::get($field, 'options', []); | |
| 333 | + $placeholder = Arr::get($field, 'placeholder', ''); | |
| 334 | + | |
| 335 | + $options = '<option value="" disabled selected>' . esc_attr($placeholder) . '</option>'; | |
| 336 | + | |
| 337 | + foreach ($choices as $value => $optionData) { | |
| 338 | + $options .= '<option value="' . esc_attr($value) . '">' . esc_attr($optionData) . '</option>'; | |
| 339 | + } | |
| 340 | + | |
| 341 | + $selectAtts = [ | |
| 342 | + 'id' => esc_attr(Arr::get($field, 'id', '')), | |
| 343 | + 'name' => esc_attr($fieldName), | |
| 344 | + 'required' => Arr::get($field, 'required') ? 'required' : '', | |
| 345 | + ]; | |
| 346 | + | |
| 347 | + $select = '<div class="fs_input_wrap"><select ' . $this->renderAttributes($selectAtts) . '>' . $options . '</select></div>'; | |
| 348 | + | |
| 349 | + return $select; | |
| 350 | + } | |
| 351 | + | |
| 352 | + private function renderAttributes($attributes) | |
| 353 | + { | |
| 354 | + $atts = ''; | |
| 355 | + | |
| 356 | + foreach ($attributes as $attKey => $att) { | |
| 357 | + $atts .= $attKey . '="' . $att . '" '; | |
| 358 | + } | |
| 359 | + | |
| 360 | + return $atts; | |
| 361 | + } | |
| 362 | + | |
| 363 | + /** | |
| 364 | + * @return mixed | |
| 365 | + */ | |
| 145 | 366 | public static function getSignupFields() |
| 146 | 367 | { |
| 368 | + /* | |
| 369 | + * Filter signup form field | |
| 370 | + * | |
| 371 | + * @since v1.0.0 | |
| 372 | + * | |
| 373 | + * @param array $fields Form fields | |
| 374 | + */ | |
| 147 | 375 | return apply_filters('fluent_support/registration_form_fields', [ |
| 148 | 376 | 'first_name' => [ |
| 149 | 377 | 'required' => true, |
| 150 | 378 | 'type' => 'text', |
| @@ -181,8 +409,90 @@ | ||
| 181 | 409 | ] |
| 182 | 410 | ]); |
| 183 | 411 | } |
| 184 | 412 | |
| 413 | + private function addCustomFieldsToRegistrationForm($fields, $customFieldsKey) { | |
| 414 | + $customFields = $this->allCustomFields(); | |
| 415 | + | |
| 416 | + foreach ($customFieldsKey as $key) { | |
| 417 | + if (isset($customFields[$key])) { | |
| 418 | + $fields[$key] = $customFields[$key]; | |
| 419 | + } | |
| 420 | + } | |
| 421 | + | |
| 422 | + return $fields; | |
| 423 | + } | |
| 424 | + | |
| 425 | + public static function allCustomFields(): array { | |
| 426 | + $countryList = CountryNames::get(); | |
| 427 | + | |
| 428 | + return apply_filters('fluent_support/custom_registration_form_fields', [ | |
| 429 | + 'address_line_1' => [ | |
| 430 | + 'required' => false, | |
| 431 | + 'type' => 'text', | |
| 432 | + 'label' => __('Address Line 1', 'fluent-support'), | |
| 433 | + 'id' => 'fst_address_line_1', | |
| 434 | + 'placeholder' => __('Address Line 1', 'fluent-support'), | |
| 435 | + ], | |
| 436 | + 'address_line_2' => [ | |
| 437 | + 'required' => false, | |
| 438 | + 'type' => 'text', | |
| 439 | + 'label' => __('Address Line 2', 'fluent-support'), | |
| 440 | + 'id' => 'fst_address_line_2', | |
| 441 | + 'placeholder' => __('Address Line 2', 'fluent-support'), | |
| 442 | + ], | |
| 443 | + 'city' => [ | |
| 444 | + 'required' => false, | |
| 445 | + 'type' => 'text', | |
| 446 | + 'label' => __('City', 'fluent-support'), | |
| 447 | + 'id' => 'fst_city', | |
| 448 | + 'placeholder' => __('City', 'fluent-support'), | |
| 449 | + ], | |
| 450 | + 'zip' => [ | |
| 451 | + 'required' => false, | |
| 452 | + 'type' => 'text', | |
| 453 | + 'label' => __('Zip', 'fluent-support'), | |
| 454 | + 'id' => 'fst_zip', | |
| 455 | + 'placeholder' => __('Zip', 'fluent-support'), | |
| 456 | + ], | |
| 457 | + 'state' => [ | |
| 458 | + 'required' => false, | |
| 459 | + 'type' => 'text', | |
| 460 | + 'label' => __('State', 'fluent-support'), | |
| 461 | + 'id' => 'fst_state', | |
| 462 | + 'placeholder' => __('State', 'fluent-support'), | |
| 463 | + ], | |
| 464 | + 'country' => [ | |
| 465 | + 'required' => false, | |
| 466 | + 'type' => 'select', | |
| 467 | + 'label' => __('Country', 'fluent-support'), | |
| 468 | + 'id' => 'fst_country', | |
| 469 | + 'placeholder' => __('Select a Country', 'fluent-support'), | |
| 470 | + 'options' => $countryList, | |
| 471 | + ], | |
| 472 | + ]); | |
| 473 | + } | |
| 474 | + | |
| 475 | + public static function resetPasswordFields() | |
| 476 | + { | |
| 477 | + /* | |
| 478 | + * Filter reset password form field | |
| 479 | + * | |
| 480 | + * @since v1.5.7 | |
| 481 | + * | |
| 482 | + * @param array $fields Form fields | |
| 483 | + */ | |
| 484 | + return apply_filters('fluent_support/reset_password_form', [ | |
| 485 | + 'user_login' => [ | |
| 486 | + 'required' => true, | |
| 487 | + 'type' => 'text', | |
| 488 | + 'label' => __('Email Address', 'fluent-support'), | |
| 489 | + 'id' => 'fst_reset_email', | |
| 490 | + 'placeholder' => __('Your Email Address', 'fluent-support') | |
| 491 | + ] | |
| 492 | + ]); | |
| 493 | + } | |
| 494 | + | |
| 185 | 495 | protected function submitBtnLoadingSvg() |
| 186 | 496 | { |
| 187 | 497 | $loadingIcon = '<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" |
| 188 | 498 | width="40px" height="20px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"> |
| @@ -196,21 +506,49 @@ | ||
| 196 | 506 | repeatCount="indefinite"/> |
| 197 | 507 | </path> |
| 198 | 508 | </svg>'; |
| 199 | 509 | |
| 510 | + /* | |
| 511 | + * Filter signup form loading icon | |
| 512 | + * | |
| 513 | + * @since v1.0.0 | |
| 514 | + * | |
| 515 | + * @param string $loadingIcon this accepts html element | |
| 516 | + */ | |
| 200 | 517 | return apply_filters('fluent_support/signup_loading_icon', $loadingIcon); |
| 201 | 518 | } |
| 202 | 519 | |
| 203 | - protected function getShortcodes($attributes) | |
| 520 | + protected function getShortcodes($attributes, $isAuthForm = false) | |
| 204 | 521 | { |
| 522 | + /* | |
| 523 | + * Filter the default attributes of the auth shortcodes. | |
| 524 | + * | |
| 525 | + * @since v1.0.0 | |
| 526 | + * | |
| 527 | + * @param array $shortCodeDefaults | |
| 528 | + */ | |
| 205 | 529 | $shortCodeDefaults = apply_filters('fluent_support/auth_shortcode_defaults', [ |
| 206 | - 'auto-redirect' => false, | |
| 207 | - 'redirect-to' => Helper::getPortalBaseUrl(), | |
| 208 | - 'hide' => false, | |
| 209 | - 'show-signup' => false | |
| 530 | + 'auto-redirect' => false, | |
| 531 | + 'redirect-to' => Helper::getPortalBaseUrl(), | |
| 532 | + 'hide' => false, | |
| 533 | + 'show-signup' => $isAuthForm ? 'true' : 'false', | |
| 534 | + 'show-reset-password' => $isAuthForm ? 'true' : 'false', | |
| 210 | 535 | ]); |
| 211 | 536 | |
| 212 | - return shortcode_atts($shortCodeDefaults, $attributes); | |
| 537 | + $attributes = shortcode_atts($shortCodeDefaults, $attributes); | |
| 538 | + | |
| 539 | + // No signup form or link while the site does not allow registration. | |
| 540 | + if (!Helper::isSignupEnabled()) { | |
| 541 | + $attributes['show-signup'] = 'false'; | |
| 542 | + } | |
| 543 | + | |
| 544 | + if (isset($attributes['redirect-to'])) { | |
| 545 | + $attributes['redirect-to'] = esc_url_raw($attributes['redirect-to']); | |
| 546 | + $attributes['redirect_to'] = $attributes['redirect-to']; | |
| 547 | + } | |
| 548 | + | |
| 549 | + return $attributes; | |
| 550 | + | |
| 213 | 551 | } |
| 214 | 552 | |
| 215 | 553 | protected function handleAlreadyLoggedIn($attributes) |
| 216 | 554 | { |
| @@ -219,15 +557,14 @@ | ||
| 219 | 557 | $redirect = $attributes['redirect-to']; |
| 220 | 558 | ?> |
| 221 | 559 | <script type="text/javascript"> |
| 222 | 560 | document.addEventListener("DOMContentLoaded", function () { |
| 223 | - var redirect = "<?php echo $redirect; ?>"; | |
| 561 | + var redirect = "<?php echo esc_url($redirect); ?>"; | |
| 224 | 562 | window.location.replace(redirect); |
| 225 | 563 | }); |
| 226 | 564 | </script> |
| 227 | 565 | <?php |
| 228 | 566 | } |
| 229 | - | |
| 230 | 567 | die(); |
| 231 | 568 | } |
| 232 | 569 | } |
| 233 | 570 | |
| @@ -238,19 +575,62 @@ | ||
| 238 | 575 | } |
| 239 | 576 | |
| 240 | 577 | $app = App::getInstance(); |
| 241 | 578 | $assets = $app['url.assets']; |
| 242 | - wp_enqueue_style('fluent_support_login_style', $assets . 'admin/css/all_public.css', [], FLUENT_SUPPORT_VERSION); | |
| 243 | - wp_enqueue_script('fluent_support_login_helper', $assets . 'portal/js/login_helper.js', [], FLUENT_SUPPORT_VERSION); | |
| 244 | 579 | |
| 580 | + if (is_rtl()) { | |
| 581 | + wp_enqueue_style('fluent_support_login_style_rtl', $assets . 'admin/css/all_public-rtl.css', [], FLUENT_SUPPORT_VERSION); | |
| 582 | + } else { | |
| 583 | + wp_enqueue_style('fluent_support_login_style', Vite::getEnqueuePath('admin/css/all_public.css'), [], FLUENT_SUPPORT_VERSION); | |
| 584 | + } | |
| 585 | + | |
| 586 | + wp_enqueue_script('fluent_support_login_helper', Vite::getEnqueuePath('portal/js/login_helper.js'), [], FLUENT_SUPPORT_VERSION); | |
| 587 | + | |
| 588 | + $reCaptchaSettingsData = Meta::where('object_type', '_fs_recaptcha_settings')->first(); | |
| 589 | + $reCaptchaData = ($reCaptchaSettingsData) ? Helper::safeUnserialize($reCaptchaSettingsData->value, []) : ''; | |
| 590 | + | |
| 591 | + if (!empty($reCaptchaData) && isset($reCaptchaData['is_enabled']) && $reCaptchaData['is_enabled'] == "true") { | |
| 592 | + unset($reCaptchaData['secretKey']); | |
| 593 | + $recaptchaVersion = $reCaptchaData["reCaptcha_version"]; | |
| 594 | + $reCaptchaApiUrl = 'https://www.google.com/recaptcha/api.js'; | |
| 595 | + | |
| 596 | + if ("recaptcha_v3" === $recaptchaVersion) { | |
| 597 | + $reCaptchaApiUrl .= '?render=' . $reCaptchaData["siteKey"]; | |
| 598 | + } | |
| 599 | + | |
| 600 | + wp_enqueue_script('recaptcha', $reCaptchaApiUrl); | |
| 601 | + } | |
| 602 | + | |
| 245 | 603 | wp_localize_script('fluent_support_login_helper', 'fluentSupportPublic', [ |
| 246 | - 'signup' => rest_url($app->config->get('app.rest_namespace') . '/' . $app->config->get('app.rest_version')) . '/signup', | |
| 247 | - 'login' => rest_url($app->config->get('app.rest_namespace') . '/' . $app->config->get('app.rest_version')) . '/login', | |
| 248 | - 'nonce' => wp_create_nonce('wp_rest'), | |
| 249 | - 'hide' => $hide, | |
| 250 | - 'fsupport_login_nonce' => wp_create_nonce('fsupport_login_nonce') | |
| 604 | + 'signup' => rest_url($app->config->get('app.rest_namespace') . '/' . $app->config->get('app.rest_version')) . '/signup', | |
| 605 | + 'login' => rest_url($app->config->get('app.rest_namespace') . '/' . $app->config->get('app.rest_version')) . '/login', | |
| 606 | + 'nonce' => wp_create_nonce('wp_rest'), | |
| 607 | + 'hide' => $hide, | |
| 608 | + 'redirect_fallback' => Helper::getPortalBaseUrl(), | |
| 609 | + 'fsupport_login_nonce' => wp_create_nonce('fsupport_login_nonce'), | |
| 610 | + 'resetPass' => rest_url($app->config->get('app.rest_namespace') . '/' . $app->config->get('app.rest_version')) . '/reset_pass', | |
| 611 | + 'reCaptchaSettingsData' => $reCaptchaData, | |
| 612 | + 'fs_two_fa' => rest_url($app->config->get('app.rest_namespace') . '/' . $app->config->get('app.rest_version')) . '/two_fa' | |
| 251 | 613 | ]); |
| 252 | 614 | |
| 253 | 615 | |
| 254 | 616 | $this->loaded = true; |
| 617 | + } | |
| 618 | + | |
| 619 | + public function maybeRenewNonce() | |
| 620 | + { | |
| 621 | + if (!PermissionManager::currentUserPermissions()) { | |
| 622 | + wp_send_json([ | |
| 623 | + 'error' => __('You do not have permission to do this.', 'fluent-support') | |
| 624 | + ], 403); | |
| 625 | + } | |
| 626 | + | |
| 627 | + wp_send_json([ | |
| 628 | + 'nonce' => wp_create_nonce('wp_rest') | |
| 629 | + ], 200); | |
| 630 | + } | |
| 631 | + | |
| 632 | + private function authProvider() | |
| 633 | + { | |
| 634 | + return \FluentSupport\App\Services\Helper::getAuthProvider(); | |
| 255 | 635 | } |
| 256 | 636 | } |