PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.5.1
Forumax – AI Powered Advanced Community Forum Plugin v2.5.1
2.5.1 2.5.0 2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 trunk 1.0.8 1.1.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 All 31 releases
← All changes | includes/login-form.php +103 -26 2.4.4 → 2.5.1 View file →
@@ -7,8 +7,10 @@
7 7 *
8 8 * @package Forumax
9 9 */
10 10
11 +defined( 'ABSPATH' ) || exit;
12 +
11 13 /**
12 14 * Render the tabbed login and registration form.
13 15 *
14 16 * @param array $atts Shortcode attributes.
@@ -20,14 +22,14 @@
20 22 if ( is_user_logged_in() ) {
21 23 return '<div class="frmx-auth-logged-in">' . esc_html__( 'You are already logged in.', 'forumax' ) . '</div>';
22 24 }
23 25
24 - // One login form per page — same shortcode on another page still works.
25 - static $frmx_login_form_rendered = false;
26 - if ( $frmx_login_form_rendered ) {
27 - return '';
28 - }
29 - $frmx_login_form_rendered = true;
26 + // Same shortcode is used on several spots of one page (reply prompt, topic
27 + // prompt, subscribe modal, page content). Each instance needs its own IDs
28 + // so a later form is not dropped and tabs/labels stay wired to that form.
29 + static $frmx_login_form_instance = 0;
30 + $frmx_login_form_instance++;
31 + $uid = 'frmx-auth-' . $frmx_login_form_instance;
30 32
31 33 // Extract shortcode attributes with defaults.
32 34 $atts = shortcode_atts( array(
33 35 'redirect' => '',
@@ -36,10 +38,17 @@
36 38 // Set redirect URL.
37 39 $redirect_url = ! empty( $atts['redirect'] ) ? $atts['redirect'] : get_permalink();
38 40
39 41 $can_register = get_option( 'users_can_register' );
40 - $wrapper_id = 'frmx-auth-tabs';
42 + $wrapper_id = $uid;
41 43
44 + // Errors passed back by forumax_login_failed_redirect() / forumax_handle_registration().
45 + // phpcs:disable WordPress.Security.NonceVerification.Recommended -- read-only display flags.
46 + $login_failed = isset( $_GET['login'] ) && 'failed' === sanitize_key( wp_unslash( $_GET['login'] ) );
47 + $reg_errors = isset( $_GET['reg_error'] ) ? array_filter( array_map( 'sanitize_key', explode( ',', sanitize_text_field( wp_unslash( $_GET['reg_error'] ) ) ) ) ) : array();
48 + // phpcs:enable
49 + $active_tab = ( $can_register && ! empty( $reg_errors ) ) ? 'register' : 'login';
50 +
42 51 ob_start();
43 52 ?>
44 53 <div class="frmx-auth-tabs" id="<?php echo esc_attr( $wrapper_id ); ?>">
45 54
@@ -44,12 +53,12 @@
44 53 <div class="frmx-auth-tabs" id="<?php echo esc_attr( $wrapper_id ); ?>">
45 54
46 55 <?php if ( $can_register ) : ?>
47 56 <div class="frmx-auth-tabs-header">
48 - <button type="button" class="frmx-auth-tab frmx-auth-tab-active" data-frmx-tab="login">
57 + <button type="button" class="frmx-auth-tab<?php echo 'login' === $active_tab ? ' frmx-auth-tab-active' : ''; ?>" data-frmx-tab="login">
49 58 <?php esc_html_e( 'Sign In', 'forumax' ); ?>
50 59 </button>
51 - <button type="button" class="frmx-auth-tab" data-frmx-tab="register">
60 + <button type="button" class="frmx-auth-tab<?php echo 'register' === $active_tab ? ' frmx-auth-tab-active' : ''; ?>" data-frmx-tab="register">
52 61 <?php esc_html_e( 'Create Account', 'forumax' ); ?>
53 62 </button>
54 63 </div>
55 64 <?php endif; ?>
@@ -54,9 +63,14 @@
54 63 </div>
55 64 <?php endif; ?>
56 65
57 66 <!-- Login Tab -->
58 - <div class="frmx-auth-panel frmx-auth-panel-active" data-frmx-panel="login">
67 + <div class="frmx-auth-panel<?php echo 'login' === $active_tab ? ' frmx-auth-panel-active' : ''; ?>" data-frmx-panel="login">
68 + <?php if ( $login_failed ) : ?>
69 + <div class="frmx-auth-error bbp-template-notice error" role="alert">
70 + <p><?php esc_html_e( 'Invalid username, email address or password. Please try again.', 'forumax' ); ?></p>
71 + </div>
72 + <?php endif; ?>
59 73 <?php
60 74 $form_html = wp_login_form( array(
61 75 'redirect' => $redirect_url,
62 76 'label_username' => esc_html__( 'Username or Email', 'forumax' ),
@@ -62,9 +76,13 @@
62 76 'label_username' => esc_html__( 'Username or Email', 'forumax' ),
63 77 'label_password' => esc_html__( 'Password', 'forumax' ),
64 78 'label_remember' => esc_html__( 'Remember Me', 'forumax' ),
65 79 'label_log_in' => esc_html__( 'Sign In', 'forumax' ),
66 - 'form_id' => 'forumax_login_form',
80 + 'form_id' => $uid . '-login',
81 + 'id_username' => $uid . '-user',
82 + 'id_password' => $uid . '-pass',
83 + 'id_remember' => $uid . '-remember',
84 + 'id_submit' => $uid . '-submit',
67 85 'remember' => true,
68 86 'echo' => false,
69 87 ) );
70 88
@@ -90,8 +108,11 @@
90 108 '$1 placeholder="' . $password_placeholder . '"$2',
91 109 $form_html
92 110 );
93 111
112 + // Marks submissions from this form so only they are redirected back on failure.
113 + $form_html = preg_replace( '/<\/form>/i', '<input type="hidden" name="forumax_login" value="1" /></form>', $form_html, 1 );
114 +
94 115 echo $form_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
95 116 ?>
96 117
97 118 <?php
@@ -103,31 +124,38 @@
103 124 </div>
104 125
105 126 <?php if ( $can_register ) : ?>
106 127 <!-- Registration Tab -->
107 - <div class="frmx-auth-panel" data-frmx-panel="register">
128 + <div class="frmx-auth-panel<?php echo 'register' === $active_tab ? ' frmx-auth-panel-active' : ''; ?>" data-frmx-panel="register">
129 + <?php if ( ! empty( $reg_errors ) ) : ?>
130 + <div class="frmx-auth-error bbp-template-notice error" role="alert">
131 + <?php foreach ( $reg_errors as $reg_error ) : ?>
132 + <p><?php echo esc_html( forumax_registration_error_message( $reg_error ) ); ?></p>
133 + <?php endforeach; ?>
134 + </div>
135 + <?php endif; ?>
108 136 <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="frmx-auth-register-form">
109 137 <input type="hidden" name="action" value="forumax_register" />
110 138 <input type="hidden" name="redirect_to" value="<?php echo esc_url( $redirect_url ); ?>" />
111 139
112 140 <div class="frmx-auth-field">
113 - <label for="frmx_reg_user_login"><?php esc_html_e( 'Username', 'forumax' ); ?></label>
114 - <input type="text" name="user_login" id="frmx_reg_user_login" placeholder="<?php esc_attr_e( 'Username', 'forumax' ); ?>" autocomplete="username" required />
141 + <label for="<?php echo esc_attr( $uid ); ?>-reg-login"><?php esc_html_e( 'Username', 'forumax' ); ?></label>
142 + <input type="text" name="user_login" id="<?php echo esc_attr( $uid ); ?>-reg-login" placeholder="<?php esc_attr_e( 'Username', 'forumax' ); ?>" autocomplete="username" required />
115 143 </div>
116 144
117 145 <div class="frmx-auth-field">
118 - <label for="frmx_reg_user_email"><?php esc_html_e( 'Email', 'forumax' ); ?></label>
119 - <input type="email" name="user_email" id="frmx_reg_user_email" placeholder="<?php esc_attr_e( 'Email', 'forumax' ); ?>" autocomplete="email" required />
146 + <label for="<?php echo esc_attr( $uid ); ?>-reg-email"><?php esc_html_e( 'Email', 'forumax' ); ?></label>
147 + <input type="email" name="user_email" id="<?php echo esc_attr( $uid ); ?>-reg-email" placeholder="<?php esc_attr_e( 'Email', 'forumax' ); ?>" autocomplete="email" required />
120 148 </div>
121 149
122 150 <div class="frmx-auth-field">
123 - <label for="frmx_reg_user_pass"><?php esc_html_e( 'Password', 'forumax' ); ?></label>
124 - <input type="password" name="user_pass" id="frmx_reg_user_pass" placeholder="<?php esc_attr_e( 'Password', 'forumax' ); ?>" autocomplete="new-password" required />
151 + <label for="<?php echo esc_attr( $uid ); ?>-reg-pass"><?php esc_html_e( 'Password', 'forumax' ); ?></label>
152 + <input type="password" name="user_pass" id="<?php echo esc_attr( $uid ); ?>-reg-pass" placeholder="<?php esc_attr_e( 'Password', 'forumax' ); ?>" autocomplete="new-password" required />
125 153 </div>
126 154
127 155 <div class="frmx-auth-field">
128 - <label for="frmx_reg_user_pass_confirm"><?php esc_html_e( 'Confirm Password', 'forumax' ); ?></label>
129 - <input type="password" name="user_pass_confirm" id="frmx_reg_user_pass_confirm" placeholder="<?php esc_attr_e( 'Confirm Password', 'forumax' ); ?>" autocomplete="new-password" required />
156 + <label for="<?php echo esc_attr( $uid ); ?>-reg-pass-confirm"><?php esc_html_e( 'Confirm Password', 'forumax' ); ?></label>
157 + <input type="password" name="user_pass_confirm" id="<?php echo esc_attr( $uid ); ?>-reg-pass-confirm" placeholder="<?php esc_attr_e( 'Confirm Password', 'forumax' ); ?>" autocomplete="new-password" required />
130 158 </div>
131 159
132 160 <?php
133 161 /**
@@ -139,9 +167,9 @@
139 167 do_action( 'register_form' );
140 168 ?>
141 169
142 170 <div class="frmx-auth-submit">
143 - <button type="submit" id="frmx-register-submit" name="wp-submit" class="button submit fill-brand">
171 + <button type="submit" id="<?php echo esc_attr( $uid ); ?>-register" name="wp-submit" class="button submit fill-brand">
144 172 <?php esc_html_e( 'Register', 'forumax' ); ?>
145 173 </button>
146 174 </div>
147 175
@@ -221,11 +249,18 @@
221 249 *
222 250 * @return void
223 251 */
224 252 function forumax_login_failed_redirect( $username ) {
253 + // Only handle the Forumax form; other login forms (WooCommerce, REST,
254 + // XML-RPC, wp-login.php) keep their own error handling.
255 + // phpcs:ignore WordPress.Security.NonceVerification.Missing -- core login has no nonce; this only picks the redirect target.
256 + if ( empty( $_POST['forumax_login'] ) ) {
257 + return;
258 + }
259 +
225 260 $referrer = wp_get_referer();
226 261 if ( ! empty( $referrer ) && ! str_contains( $referrer, 'wp-login.php' ) ) {
227 - wp_redirect( add_query_arg( 'login', 'failed', $referrer ) );
262 + wp_safe_redirect( add_query_arg( 'login', 'failed', remove_query_arg( array( 'login', 'reg_error' ), $referrer ) ) );
228 263 exit;
229 264 }
230 265 }
231 266
@@ -231,8 +266,29 @@
231 266
232 267 add_action( 'wp_login_failed', 'forumax_login_failed_redirect' );
233 268
234 269 /**
270 + * Human readable message for a registration error code.
271 + *
272 + * @param string $code Error code.
273 + * @return string
274 + */
275 +function forumax_registration_error_message( $code ) {
276 + $messages = array(
277 + 'empty_username' => __( 'Please enter a username.', 'forumax' ),
278 + 'invalid_username' => __( 'This username is invalid. Please use letters, numbers and - _ . @ only.', 'forumax' ),
279 + 'existing_user_login' => __( 'This username is already registered. Please choose another one.', 'forumax' ),
280 + 'invalid_email' => __( 'Please enter a valid email address.', 'forumax' ),
281 + 'email_exists' => __( 'This email address is already registered.', 'forumax' ),
282 + 'existing_user_email' => __( 'This email address is already registered.', 'forumax' ),
283 + 'empty_password' => __( 'Please enter a password.', 'forumax' ),
284 + 'password_mismatch' => __( 'The passwords do not match.', 'forumax' ),
285 + );
286 +
287 + return $messages[ $code ] ?? __( 'Registration failed. Please check the form and try again.', 'forumax' );
288 +}
289 +
290 +/**
235 291 * Handle the custom registration form submission.
236 292 *
237 293 * Creates a new user with the provided username, email, and password,
238 294 * auto-logs them in, and redirects to the referring page.
@@ -279,10 +335,34 @@
279 335 if ( $user_pass !== $user_pass_confirm ) {
280 336 $errors[] = 'password_mismatch';
281 337 }
282 338
339 + if ( empty( $errors ) ) {
340 + if ( ! validate_username( $user_login ) ) {
341 + $errors[] = 'invalid_username';
342 + } elseif ( username_exists( $user_login ) ) {
343 + $errors[] = 'existing_user_login';
344 + }
345 +
346 + if ( email_exists( $user_email ) ) {
347 + $errors[] = 'email_exists';
348 + }
349 + }
350 +
351 + // Let CAPTCHA / anti-spam plugins that print into `register_form`
352 + // validate the submission too, as core registration does.
353 + if ( empty( $errors ) ) {
354 + $wp_errors = new WP_Error();
355 + do_action( 'register_post', $user_login, $user_email, $wp_errors );
356 + $wp_errors = apply_filters( 'registration_errors', $wp_errors, $user_login, $user_email );
357 +
358 + if ( is_wp_error( $wp_errors ) && $wp_errors->has_errors() ) {
359 + $errors = array_merge( $errors, $wp_errors->get_error_codes() );
360 + }
361 + }
362 +
283 363 if ( ! empty( $errors ) ) {
284 - wp_safe_redirect( add_query_arg( 'reg_error', implode( ',', $errors ), $referrer ) );
364 + wp_safe_redirect( add_query_arg( 'reg_error', implode( ',', array_unique( $errors ) ), remove_query_arg( array( 'login', 'reg_error' ), $referrer ) ) );
285 365 exit;
286 366 }
287 367
288 368 // Let external plugins validate registration (e.g. Envato license check).
@@ -299,11 +379,8 @@
299 379 $error_code = $user_id->get_error_code();
300 380 wp_safe_redirect( add_query_arg( 'reg_error', $error_code, $referrer ) );
301 381 exit;
302 382 }
303 -
304 - // Fire standard WordPress registration action.
305 - do_action( 'user_register', $user_id );
306 383
307 384 // Auto-login the new user.
308 385 wp_set_current_user( $user_id );
309 386 wp_set_auth_cookie( $user_id, true );