PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.5.0
Forumax – AI Powered Advanced Community Forum Plugin v2.5.0
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 2.0.0 All 30 releases
← All changes | includes/login-form.php +320 -73 2.0.0 → 2.5.0 View file →
@@ -1,73 +1,320 @@
1 -<?php
2 -function forumax_login_form_shortcode( $atts ) {
3 - // If user already logged in, return a message or redirect
4 - if ( is_user_logged_in() ) {
5 - return '<div class="login-already" style="color: green; margin-bottom: 15px;">' . esc_html__( 'You are already logged in.', 'forumax' ) . '</div>';
6 - }
7 -
8 - // Extract shortcode attributes with defaults
9 - $atts = shortcode_atts( array(
10 - 'redirect' => '',
11 - 'submit_label' => esc_html__( 'Sign in', 'forumax' ),
12 - 'username_label' => esc_html__( 'Username', 'forumax' ),
13 - 'password_label' => esc_html__( 'Password', 'forumax' ),
14 - 'error_notice' => esc_html__( 'Invalid username or password. Please try again.', 'forumax' ),
15 - 'username_placeholder' => esc_attr__( 'Enter your username', 'forumax' ),
16 - 'password_placeholder' => esc_attr__( 'Enter your password', 'forumax' ),
17 - 'button_color' => '#1e73be', // Default button background color
18 - 'button_text_color' => '#ffffff', // default text color
19 - 'button_position' => 'left', // left, center, right
20 - 'signup_link' => '', // attribute for signup link
21 - ), $atts );
22 -
23 - // Set redirect URL
24 - $redirect_url = ! empty( $atts['redirect'] ) ? $atts['redirect'] : get_permalink();
25 -
26 - // Determine button alignment based on 'button_position' attribute
27 - $button_alignment = 'text-align: center;'; // default
28 - if ( $atts['button_position'] === 'left' ) {
29 - $button_alignment = 'text-align: left;';
30 - } elseif ( $atts['button_position'] === 'right' ) {
31 - $button_alignment = 'text-align: right;';
32 - }
33 -
34 - ob_start();
35 -
36 - $form_args = array(
37 - 'redirect' => $redirect_url,
38 - 'label_username' => $atts['username_label'],
39 - 'label_password' => $atts['password_label'],
40 - 'label_remember' => esc_html__( 'Remember Me', 'forumax' ),
41 - 'label_log_in' => $atts['submit_label'],
42 - 'form_id' => 'forumax_login_form',
43 - 'remember' => true,
44 - ''
45 - );
46 -
47 - wp_login_form($form_args);
48 -
49 - if ( ! empty( $atts['signup_link'] ) ) : ?>
50 - <div class="signup-text">
51 - <?php esc_html_e( 'Don’t have an account yet?', 'forumax' ); ?>
52 - <a href="<?php echo esc_url( $atts['signup_link'] ); ?>">
53 - <?php esc_html_e( 'Sign up here', 'forumax' ); ?>
54 - </a>
55 - </div>
56 - <?php endif; ?>
57 - <?php
58 -
59 - return ob_get_clean();
60 -}
61 -
62 -add_shortcode( 'forumax_login_form', 'forumax_login_form_shortcode' );
63 -
64 -// Redirect to the referrer page after login
65 -add_action( 'wp_login_failed', 'forumax_login_failed_redirect' );
66 -
67 -function forumax_login_failed_redirect( $username ) {
68 - $referrer = wp_get_referer();
69 - if ( ! empty( $referrer ) && ! str_contains( $referrer, 'wp-login.php' ) ) {
70 - wp_redirect( add_query_arg( 'login', 'failed', $referrer ) );
71 - exit;
72 - }
73 -}
1 +<?php
2 +/**
3 + * Forumax Login & Registration Form Shortcode
4 + *
5 + * Renders a tabbed Login / Sign Up form. Uses wp_login_form() to ensure
6 + * Google Site Kit (and any plugin that hooks into `login_form`) works.
7 + *
8 + * @package Forumax
9 + */
10 +
11 +/**
12 + * Render the tabbed login and registration form.
13 + *
14 + * @param array $atts Shortcode attributes.
15 + *
16 + * @return string HTML output.
17 + */
18 +function forumax_login_form_shortcode( $atts ) {
19 + // If user already logged in, return a message.
20 + if ( is_user_logged_in() ) {
21 + return '<div class="frmx-auth-logged-in">' . esc_html__( 'You are already logged in.', 'forumax' ) . '</div>';
22 + }
23 +
24 + // Same shortcode is used on several spots of one page (reply prompt, topic
25 + // prompt, subscribe modal, page content). Each instance needs its own IDs
26 + // so a later form is not dropped and tabs/labels stay wired to that form.
27 + static $frmx_login_form_instance = 0;
28 + $frmx_login_form_instance++;
29 + $uid = 'frmx-auth-' . $frmx_login_form_instance;
30 +
31 + // Extract shortcode attributes with defaults.
32 + $atts = shortcode_atts( array(
33 + 'redirect' => '',
34 + ), $atts );
35 +
36 + // Set redirect URL.
37 + $redirect_url = ! empty( $atts['redirect'] ) ? $atts['redirect'] : get_permalink();
38 +
39 + $can_register = get_option( 'users_can_register' );
40 + $wrapper_id = $uid;
41 +
42 + ob_start();
43 + ?>
44 + <div class="frmx-auth-tabs" id="<?php echo esc_attr( $wrapper_id ); ?>">
45 +
46 + <?php if ( $can_register ) : ?>
47 + <div class="frmx-auth-tabs-header">
48 + <button type="button" class="frmx-auth-tab frmx-auth-tab-active" data-frmx-tab="login">
49 + <?php esc_html_e( 'Sign In', 'forumax' ); ?>
50 + </button>
51 + <button type="button" class="frmx-auth-tab" data-frmx-tab="register">
52 + <?php esc_html_e( 'Create Account', 'forumax' ); ?>
53 + </button>
54 + </div>
55 + <?php endif; ?>
56 +
57 + <!-- Login Tab -->
58 + <div class="frmx-auth-panel frmx-auth-panel-active" data-frmx-panel="login">
59 + <?php
60 + $form_html = wp_login_form( array(
61 + 'redirect' => $redirect_url,
62 + 'label_username' => esc_html__( 'Username or Email', 'forumax' ),
63 + 'label_password' => esc_html__( 'Password', 'forumax' ),
64 + 'label_remember' => esc_html__( 'Remember Me', 'forumax' ),
65 + 'label_log_in' => esc_html__( 'Sign In', 'forumax' ),
66 + 'form_id' => $uid . '-login',
67 + 'id_username' => $uid . '-user',
68 + 'id_password' => $uid . '-pass',
69 + 'id_remember' => $uid . '-remember',
70 + 'id_submit' => $uid . '-submit',
71 + 'remember' => true,
72 + 'echo' => false,
73 + ) );
74 +
75 + // Class hook for styling (keeps a stable selector with form_id).
76 + $form_html = preg_replace(
77 + '/<form\b/i',
78 + '<form class="forumax_login_form"',
79 + $form_html,
80 + 1
81 + );
82 +
83 + // Add placeholders to core login form fields.
84 + $username_placeholder = esc_attr__( 'Username or Email', 'forumax' );
85 + $password_placeholder = esc_attr__( 'Password', 'forumax' );
86 +
87 + $form_html = preg_replace(
88 + '/(<input\b(?![^>]*\bplaceholder=)[^>]*\bname=["\']log["\'][^>]*)(\/?\s*>)/i',
89 + '$1 placeholder="' . $username_placeholder . '"$2',
90 + $form_html
91 + );
92 + $form_html = preg_replace(
93 + '/(<input\b(?![^>]*\bplaceholder=)[^>]*\bname=["\']pwd["\'][^>]*)(\/?\s*>)/i',
94 + '$1 placeholder="' . $password_placeholder . '"$2',
95 + $form_html
96 + );
97 +
98 + echo $form_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
99 + ?>
100 +
101 + <?php
102 + /**
103 + * Hook to display social login buttons (e.g. Google Site Kit).
104 + */
105 + do_action( 'forumax_login_form_social_buttons' );
106 + ?>
107 + </div>
108 +
109 + <?php if ( $can_register ) : ?>
110 + <!-- Registration Tab -->
111 + <div class="frmx-auth-panel" data-frmx-panel="register">
112 + <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="frmx-auth-register-form">
113 + <input type="hidden" name="action" value="forumax_register" />
114 + <input type="hidden" name="redirect_to" value="<?php echo esc_url( $redirect_url ); ?>" />
115 +
116 + <div class="frmx-auth-field">
117 + <label for="<?php echo esc_attr( $uid ); ?>-reg-login"><?php esc_html_e( 'Username', 'forumax' ); ?></label>
118 + <input type="text" name="user_login" id="<?php echo esc_attr( $uid ); ?>-reg-login" placeholder="<?php esc_attr_e( 'Username', 'forumax' ); ?>" autocomplete="username" required />
119 + </div>
120 +
121 + <div class="frmx-auth-field">
122 + <label for="<?php echo esc_attr( $uid ); ?>-reg-email"><?php esc_html_e( 'Email', 'forumax' ); ?></label>
123 + <input type="email" name="user_email" id="<?php echo esc_attr( $uid ); ?>-reg-email" placeholder="<?php esc_attr_e( 'Email', 'forumax' ); ?>" autocomplete="email" required />
124 + </div>
125 +
126 + <div class="frmx-auth-field">
127 + <label for="<?php echo esc_attr( $uid ); ?>-reg-pass"><?php esc_html_e( 'Password', 'forumax' ); ?></label>
128 + <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 />
129 + </div>
130 +
131 + <div class="frmx-auth-field">
132 + <label for="<?php echo esc_attr( $uid ); ?>-reg-pass-confirm"><?php esc_html_e( 'Confirm Password', 'forumax' ); ?></label>
133 + <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 />
134 + </div>
135 +
136 + <?php
137 + /**
138 + * Fires inside the registration form.
139 + *
140 + * This is the standard WordPress hook that plugins (e.g. CAPTCHA,
141 + * custom fields) use to inject content into registration forms.
142 + */
143 + do_action( 'register_form' );
144 + ?>
145 +
146 + <div class="frmx-auth-submit">
147 + <button type="submit" id="<?php echo esc_attr( $uid ); ?>-register" name="wp-submit" class="button submit fill-brand">
148 + <?php esc_html_e( 'Register', 'forumax' ); ?>
149 + </button>
150 + </div>
151 +
152 + <?php wp_nonce_field( 'forumax_register', 'forumax_register_nonce' ); ?>
153 + </form>
154 + </div>
155 + <?php endif; ?>
156 +
157 + </div>
158 +
159 + <script>
160 + ( function() {
161 + var wrapper = document.getElementById( '<?php echo esc_js( $wrapper_id ); ?>' );
162 + if ( ! wrapper ) {
163 + return;
164 + }
165 +
166 + var tabs = wrapper.querySelectorAll( '.frmx-auth-tab' );
167 + var panels = wrapper.querySelectorAll( '.frmx-auth-panel' );
168 +
169 + tabs.forEach( function( tab ) {
170 + tab.addEventListener( 'click', function() {
171 + var target = this.getAttribute( 'data-frmx-tab' );
172 +
173 + tabs.forEach( function( t ) {
174 + t.classList.remove( 'frmx-auth-tab-active' );
175 + } );
176 + this.classList.add( 'frmx-auth-tab-active' );
177 +
178 + panels.forEach( function( p ) {
179 + if ( p.getAttribute( 'data-frmx-panel' ) === target ) {
180 + p.classList.add( 'frmx-auth-panel-active' );
181 + } else {
182 + p.classList.remove( 'frmx-auth-panel-active' );
183 + }
184 + } );
185 + } );
186 + } );
187 +
188 + /* Password visibility toggle */
189 + var eyeShow = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>';
190 + var eyeHide = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>';
191 +
192 + wrapper.querySelectorAll( 'input[type="password"]' ).forEach( function( input ) {
193 + var container = document.createElement( 'div' );
194 + container.className = 'frmx-auth-password-wrap';
195 + input.parentNode.insertBefore( container, input );
196 + container.appendChild( input );
197 +
198 + var toggleBtn = document.createElement( 'button' );
199 + toggleBtn.type = 'button';
200 + toggleBtn.className = 'frmx-auth-eye-toggle';
201 + toggleBtn.setAttribute( 'aria-label', 'Toggle password visibility' );
202 + toggleBtn.innerHTML = eyeShow;
203 + container.appendChild( toggleBtn );
204 +
205 + toggleBtn.addEventListener( 'click', function() {
206 + var isPassword = input.type === 'password';
207 + input.type = isPassword ? 'text' : 'password';
208 + this.innerHTML = isPassword ? eyeHide : eyeShow;
209 + input.focus();
210 + } );
211 + } );
212 + } )();
213 + </script>
214 + <?php
215 +
216 + return ob_get_clean();
217 +}
218 +
219 +add_shortcode( 'forumax_login_form', 'forumax_login_form_shortcode' );
220 +
221 +/**
222 + * Redirect to the referrer page after a failed login attempt.
223 + *
224 + * @param string $username The username that failed login.
225 + *
226 + * @return void
227 + */
228 +function forumax_login_failed_redirect( $username ) {
229 + $referrer = wp_get_referer();
230 + if ( ! empty( $referrer ) && ! str_contains( $referrer, 'wp-login.php' ) ) {
231 + wp_redirect( add_query_arg( 'login', 'failed', $referrer ) );
232 + exit;
233 + }
234 +}
235 +
236 +add_action( 'wp_login_failed', 'forumax_login_failed_redirect' );
237 +
238 +/**
239 + * Handle the custom registration form submission.
240 + *
241 + * Creates a new user with the provided username, email, and password,
242 + * auto-logs them in, and redirects to the referring page.
243 + *
244 + * @return void
245 + */
246 +function forumax_handle_registration() {
247 + // Verify nonce.
248 + if ( ! isset( $_POST['forumax_register_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['forumax_register_nonce'] ) ), 'forumax_register' ) ) {
249 + wp_die( esc_html__( 'Security check failed.', 'forumax' ), 403 );
250 + }
251 +
252 + // Check registration is allowed.
253 + if ( ! get_option( 'users_can_register' ) ) {
254 + wp_die( esc_html__( 'Registration is currently disabled.', 'forumax' ), 403 );
255 + }
256 +
257 + $redirect = ! empty( $_POST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_POST['redirect_to'] ) ) : home_url();
258 + $referrer = wp_get_referer();
259 + if ( empty( $referrer ) ) {
260 + $referrer = $redirect;
261 + }
262 +
263 + $user_login = isset( $_POST['user_login'] ) ? sanitize_user( wp_unslash( $_POST['user_login'] ) ) : '';
264 + $user_email = isset( $_POST['user_email'] ) ? sanitize_email( wp_unslash( $_POST['user_email'] ) ) : '';
265 + $user_pass = isset( $_POST['user_pass'] ) ? $_POST['user_pass'] : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- password must not be sanitized.
266 + $user_pass_confirm = isset( $_POST['user_pass_confirm'] ) ? $_POST['user_pass_confirm'] : ''; // phpcs:ignore
267 +
268 + // Validate fields.
269 + $errors = array();
270 +
271 + if ( empty( $user_login ) ) {
272 + $errors[] = 'empty_username';
273 + }
274 +
275 + if ( empty( $user_email ) || ! is_email( $user_email ) ) {
276 + $errors[] = 'invalid_email';
277 + }
278 +
279 + if ( empty( $user_pass ) ) {
280 + $errors[] = 'empty_password';
281 + }
282 +
283 + if ( $user_pass !== $user_pass_confirm ) {
284 + $errors[] = 'password_mismatch';
285 + }
286 +
287 + if ( ! empty( $errors ) ) {
288 + wp_safe_redirect( add_query_arg( 'reg_error', implode( ',', $errors ), $referrer ) );
289 + exit;
290 + }
291 +
292 + // Let external plugins validate registration (e.g. Envato license check).
293 + $sbv_valid = apply_filters( 'sbv_validate_registration', true );
294 + if ( is_wp_error( $sbv_valid ) ) {
295 + wp_safe_redirect( add_query_arg( 'reg_error', $sbv_valid->get_error_code(), $referrer ) );
296 + exit;
297 + }
298 +
299 + // Create the user.
300 + $user_id = wp_create_user( $user_login, $user_pass, $user_email );
301 +
302 + if ( is_wp_error( $user_id ) ) {
303 + $error_code = $user_id->get_error_code();
304 + wp_safe_redirect( add_query_arg( 'reg_error', $error_code, $referrer ) );
305 + exit;
306 + }
307 +
308 + // Fire standard WordPress registration action.
309 + do_action( 'user_register', $user_id );
310 +
311 + // Auto-login the new user.
312 + wp_set_current_user( $user_id );
313 + wp_set_auth_cookie( $user_id, true );
314 +
315 + wp_safe_redirect( $redirect );
316 + exit;
317 +}
318 +
319 +add_action( 'admin_post_nopriv_forumax_register', 'forumax_handle_registration' );
320 +add_action( 'admin_post_forumax_register', 'forumax_handle_registration' );