wp-login.php 46.8 KB
Newer Older
godog's avatar
godog committed
1 2 3 4 5 6 7 8 9 10 11
<?php
/**
 * WordPress User Page
 *
 * Handles authentication, registering, resetting passwords, forgot password,
 * and other user handling.
 *
 * @package WordPress
 */

/** Make sure that the WordPress bootstrap has run before continuing. */
agata's avatar
agata committed
12
require __DIR__ . '/wp-load.php';
godog's avatar
godog committed
13

samba's avatar
samba committed
14
// Redirect to HTTPS login if forced to use SSL.
lechuck's avatar
lechuck committed
15
if ( force_ssl_admin() && ! is_ssl() ) {
samba's avatar
samba committed
16
	if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
kiki's avatar
kiki committed
17
		wp_safe_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
godog's avatar
godog committed
18 19
		exit();
	} else {
kiki's avatar
kiki committed
20
		wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
godog's avatar
godog committed
21 22 23 24 25
		exit();
	}
}

/**
lucha's avatar
lucha committed
26
 * Output the login page header.
godog's avatar
godog committed
27
 *
samba's avatar
samba committed
28 29
 * @since 2.1.0
 *
agata's avatar
agata committed
30 31 32 33 34 35
 * @global string      $error         Login error message set by deprecated pluggable wp_login() function
 *                                    or plugins replacing it.
 * @global bool|string $interim_login Whether interim login modal is being displayed. String 'success'
 *                                    upon successful login.
 * @global string      $action        The action that brought the visitor to the login page.
 *
lechuck's avatar
lechuck committed
36 37
 * @param string   $title    Optional. WordPress login Page title to display in the `<title>` element.
 *                           Default 'Log In'.
lucha's avatar
lucha committed
38
 * @param string   $message  Optional. Message to display in header. Default empty.
lucha's avatar
lucha committed
39
 * @param WP_Error $wp_error Optional. The error to pass. Default is a WP_Error instance.
godog's avatar
godog committed
40
 */
lucha's avatar
lucha committed
41
function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
lucha's avatar
lucha committed
42
	global $error, $interim_login, $action;
godog's avatar
godog committed
43

agata's avatar
agata committed
44
	// Don't index any of these forms.
lucha's avatar
lucha committed
45
	add_action( 'login_head', 'wp_sensitive_page_meta' );
godog's avatar
godog committed
46

lucha's avatar
lucha committed
47
	add_action( 'login_head', 'wp_login_viewport_meta' );
lucha's avatar
lucha committed
48

lucha's avatar
lucha committed
49
	if ( ! is_wp_error( $wp_error ) ) {
godog's avatar
godog committed
50
		$wp_error = new WP_Error();
lucha's avatar
lucha committed
51
	}
godog's avatar
godog committed
52 53

	// Shake it!
agata's avatar
agata committed
54
	$shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure' );
lucha's avatar
lucha committed
55
	/**
lucha's avatar
lucha committed
56
	 * Filters the error codes array for shaking the login form.
lucha's avatar
lucha committed
57 58 59 60 61
	 *
	 * @since 3.0.0
	 *
	 * @param array $shake_error_codes Error codes that shake the login form.
	 */
godog's avatar
godog committed
62 63
	$shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );

agata's avatar
agata committed
64
	if ( $shake_error_codes && $wp_error->has_errors() && in_array( $wp_error->get_error_code(), $shake_error_codes, true ) ) {
agata's avatar
agata committed
65
		add_action( 'login_footer', 'wp_shake_js', 12 );
samba's avatar
samba committed
66
	}
godog's avatar
godog committed
67

lucha's avatar
lucha committed
68 69
	$login_title = get_bloginfo( 'name', 'display' );

agata's avatar
agata committed
70
	/* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
lucha's avatar
lucha committed
71 72
	$login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );

agata's avatar
agata committed
73 74 75 76 77
	if ( wp_is_recovery_mode() ) {
		/* translators: %s: Login screen title. */
		$login_title = sprintf( __( 'Recovery Mode &#8212; %s' ), $login_title );
	}

lucha's avatar
lucha committed
78 79 80 81 82 83 84 85 86
	/**
	 * Filters the title tag content for login page.
	 *
	 * @since 4.9.0
	 *
	 * @param string $login_title The page title, with extra context added.
	 * @param string $title       The original page title.
	 */
	$login_title = apply_filters( 'login_title', $login_title, $title );
lechuck's avatar
lechuck committed
87

lechuck's avatar
lechuck committed
88
	?><!DOCTYPE html>
lucha's avatar
lucha committed
89 90 91 92 93 94
	<!--[if IE 8]>
		<html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php language_attributes(); ?>>
	<![endif]-->
	<!--[if !(IE 8) ]><!-->
		<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
	<!--<![endif]-->
lechuck's avatar
lechuck committed
95
	<head>
samba's avatar
samba committed
96
	<meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
lucha's avatar
lucha committed
97
	<title><?php echo $login_title; ?></title>
lechuck's avatar
lechuck committed
98 99
	<?php

lechuck's avatar
lechuck committed
100
	wp_enqueue_style( 'login' );
godog's avatar
godog committed
101

lucha's avatar
lucha committed
102 103 104
	/*
	 * Remove all stored post data on logging out.
	 * This could be added by add_action('login_head'...) like wp_shake_js(),
samba's avatar
samba committed
105
	 * but maybe better if it's not removable by plugins.
lucha's avatar
lucha committed
106
	 */
agata's avatar
agata committed
107
	if ( 'loggedout' === $wp_error->get_error_code() ) {
lechuck's avatar
lechuck committed
108 109 110
		?>
		<script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
		<?php
godog's avatar
godog committed
111 112
	}

lucha's avatar
lucha committed
113 114 115 116 117
	/**
	 * Enqueue scripts and styles for the login page.
	 *
	 * @since 3.1.0
	 */
root's avatar
root committed
118
	do_action( 'login_enqueue_scripts' );
lechuck's avatar
lechuck committed
119

lucha's avatar
lucha committed
120 121 122 123 124
	/**
	 * Fires in the login page header after scripts are enqueued.
	 *
	 * @since 2.1.0
	 */
lechuck's avatar
lechuck committed
125 126
	do_action( 'login_head' );

agata's avatar
agata committed
127
	$login_header_url = __( 'https://wordpress.org/' );
lechuck's avatar
lechuck committed
128

lucha's avatar
lucha committed
129
	/**
lucha's avatar
lucha committed
130
	 * Filters link URL of the header logo above login form.
lucha's avatar
lucha committed
131 132 133 134 135 136
	 *
	 * @since 2.1.0
	 *
	 * @param string $login_header_url Login header logo URL.
	 */
	$login_header_url = apply_filters( 'login_headerurl', $login_header_url );
lucha's avatar
lucha committed
137

agata's avatar
agata committed
138 139
	$login_header_title = '';

lucha's avatar
lucha committed
140
	/**
lucha's avatar
lucha committed
141
	 * Filters the title attribute of the header logo above login form.
lucha's avatar
lucha committed
142 143
	 *
	 * @since 2.1.0
agata's avatar
agata committed
144
	 * @deprecated 5.2.0 Use {@see 'login_headertext'} instead.
lucha's avatar
lucha committed
145 146 147
	 *
	 * @param string $login_header_title Login header logo title attribute.
	 */
agata's avatar
agata committed
148 149 150 151 152 153 154
	$login_header_title = apply_filters_deprecated(
		'login_headertitle',
		array( $login_header_title ),
		'5.2.0',
		'login_headertext',
		__( 'Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.' )
	);
lechuck's avatar
lechuck committed
155

agata's avatar
agata committed
156 157 158 159 160 161 162 163
	$login_header_text = empty( $login_header_title ) ? __( 'Powered by WordPress' ) : $login_header_title;

	/**
	 * Filters the link text of the header logo above the login form.
	 *
	 * @since 5.2.0
	 *
	 * @param string $login_header_text The login header logo link text.
lucha's avatar
lucha committed
164
	 */
agata's avatar
agata committed
165
	$login_header_text = apply_filters( 'login_headertext', $login_header_text );
lucha's avatar
lucha committed
166

lechuck's avatar
lechuck committed
167
	$classes = array( 'login-action-' . $action, 'wp-core-ui' );
agata's avatar
agata committed
168

samba's avatar
samba committed
169
	if ( is_rtl() ) {
lechuck's avatar
lechuck committed
170
		$classes[] = 'rtl';
samba's avatar
samba committed
171
	}
agata's avatar
agata committed
172

lechuck's avatar
lechuck committed
173 174
	if ( $interim_login ) {
		$classes[] = 'interim-login';
agata's avatar
agata committed
175

lechuck's avatar
lechuck committed
176 177 178 179
		?>
		<style type="text/css">html{background-color: transparent;}</style>
		<?php

samba's avatar
samba committed
180
		if ( 'success' === $interim_login ) {
lechuck's avatar
lechuck committed
181
			$classes[] = 'interim-login-success';
samba's avatar
samba committed
182
		}
lechuck's avatar
lechuck committed
183
	}
agata's avatar
agata committed
184

samba's avatar
samba committed
185
	$classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
lechuck's avatar
lechuck committed
186

lucha's avatar
lucha committed
187
	/**
lucha's avatar
lucha committed
188
	 * Filters the login page body classes.
lucha's avatar
lucha committed
189 190 191 192 193 194
	 *
	 * @since 3.5.0
	 *
	 * @param array  $classes An array of body classes.
	 * @param string $action  The action that brought the visitor to the login page.
	 */
lechuck's avatar
lechuck committed
195
	$classes = apply_filters( 'login_body_class', $classes, $action );
lechuck's avatar
lechuck committed
196

lechuck's avatar
lechuck committed
197 198
	?>
	</head>
agata's avatar
agata committed
199 200 201 202
	<body class="login no-js <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
	<script type="text/javascript">
		document.body.className = document.body.className.replace('no-js','js');
	</script>
lucha's avatar
lucha committed
203 204 205 206 207 208 209
	<?php
	/**
	 * Fires in the login page header after the body tag is opened.
	 *
	 * @since 4.6.0
	 */
	do_action( 'login_header' );
agata's avatar
agata committed
210

lucha's avatar
lucha committed
211
	?>
lechuck's avatar
lechuck committed
212
	<div id="login">
agata's avatar
agata committed
213
		<h1><a href="<?php echo esc_url( $login_header_url ); ?>"><?php echo $login_header_text; ?></a></h1>
lechuck's avatar
lechuck committed
214
	<?php
lucha's avatar
lucha committed
215
	/**
lucha's avatar
lucha committed
216
	 * Filters the message to display above the login form.
lucha's avatar
lucha committed
217 218 219 220 221 222
	 *
	 * @since 2.1.0
	 *
	 * @param string $message Login message text.
	 */
	$message = apply_filters( 'login_message', $message );
agata's avatar
agata committed
223

samba's avatar
samba committed
224
	if ( ! empty( $message ) ) {
lechuck's avatar
lechuck committed
225
		echo $message . "\n";
samba's avatar
samba committed
226
	}
godog's avatar
godog committed
227

samba's avatar
samba committed
228 229 230 231
	// In case a plugin uses $error rather than the $wp_errors object.
	if ( ! empty( $error ) ) {
		$wp_error->add( 'error', $error );
		unset( $error );
godog's avatar
godog committed
232 233
	}

samba's avatar
samba committed
234 235
	if ( $wp_error->has_errors() ) {
		$errors   = '';
godog's avatar
godog committed
236
		$messages = '';
agata's avatar
agata committed
237

godog's avatar
godog committed
238
		foreach ( $wp_error->get_error_codes() as $code ) {
lucha's avatar
lucha committed
239 240
			$severity = $wp_error->get_error_data( $code );
			foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
agata's avatar
agata committed
241
				if ( 'message' === $severity ) {
lucha's avatar
lucha committed
242
					$messages .= '	' . $error_message . "<br />\n";
samba's avatar
samba committed
243
				} else {
lucha's avatar
lucha committed
244
					$errors .= '	' . $error_message . "<br />\n";
samba's avatar
samba committed
245
				}
godog's avatar
godog committed
246 247
			}
		}
agata's avatar
agata committed
248

lucha's avatar
lucha committed
249 250
		if ( ! empty( $errors ) ) {
			/**
lucha's avatar
lucha committed
251
			 * Filters the error messages displayed above the login form.
lucha's avatar
lucha committed
252 253 254 255 256 257 258
			 *
			 * @since 2.1.0
			 *
			 * @param string $errors Login error message.
			 */
			echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
		}
agata's avatar
agata committed
259

lucha's avatar
lucha committed
260 261
		if ( ! empty( $messages ) ) {
			/**
lucha's avatar
lucha committed
262
			 * Filters instructional messages displayed above the login form.
lucha's avatar
lucha committed
263 264 265 266 267 268 269
			 *
			 * @since 2.5.0
			 *
			 * @param string $messages Login messages.
			 */
			echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
		}
godog's avatar
godog committed
270
	}
agata's avatar
agata committed
271
} // End of login_header().
root's avatar
root committed
272 273 274 275

/**
 * Outputs the footer for the login page.
 *
samba's avatar
samba committed
276 277
 * @since 3.1.0
 *
agata's avatar
agata committed
278 279 280
 * @global bool|string $interim_login Whether interim login modal is being displayed. String 'success'
 *                                    upon successful login.
 *
samba's avatar
samba committed
281
 * @param string $input_id Which input to auto-focus.
root's avatar
root committed
282
 */
samba's avatar
samba committed
283
function login_footer( $input_id = '' ) {
lechuck's avatar
lechuck committed
284 285 286
	global $interim_login;

	// Don't allow interim logins to navigate away from the page.
agata's avatar
agata committed
287
	if ( ! $interim_login ) {
samba's avatar
samba committed
288
		?>
agata's avatar
agata committed
289
		<p id="backtoblog"><a href="<?php echo esc_url( home_url( '/' ) ); ?>">
samba's avatar
samba committed
290
		<?php
agata's avatar
agata committed
291 292

		/* translators: %s: Site title. */
lucha's avatar
lucha committed
293
		printf( _x( '&larr; Back to %s', 'site' ), get_bloginfo( 'title', 'display' ) );
agata's avatar
agata committed
294

samba's avatar
samba committed
295
		?>
agata's avatar
agata committed
296 297
		</a></p>
		<?php
root's avatar
root committed
298

agata's avatar
agata committed
299 300
		the_privacy_policy_link( '<div class="privacy-policy-page-link">', '</div>' );
	}
shammash's avatar
shammash committed
301

agata's avatar
agata committed
302
	?>
agata's avatar
agata committed
303
	</div><?php // End of <div id="login">. ?>
lechuck's avatar
lechuck committed
304

lucha's avatar
lucha committed
305
	<?php
agata's avatar
agata committed
306 307 308 309 310 311 312 313 314 315

	if ( ! empty( $input_id ) ) {
		?>
		<script type="text/javascript">
		try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
		if(typeof wpOnload=='function')wpOnload();
		</script>
		<?php
	}

lucha's avatar
lucha committed
316 317 318 319 320
	/**
	 * Fires in the login page footer.
	 *
	 * @since 3.1.0
	 */
samba's avatar
samba committed
321
	do_action( 'login_footer' );
agata's avatar
agata committed
322

samba's avatar
samba committed
323
	?>
lechuck's avatar
lechuck committed
324 325 326 327
	<div class="clear"></div>
	</body>
	</html>
	<?php
root's avatar
root committed
328 329
}

lechuck's avatar
lechuck committed
330
/**
samba's avatar
samba committed
331 332
 * Outputs the Javascript to handle the form shaking.
 *
lechuck's avatar
lechuck committed
333 334
 * @since 3.0.0
 */
godog's avatar
godog committed
335
function wp_shake_js() {
samba's avatar
samba committed
336
	?>
agata's avatar
agata committed
337
	<script type="text/javascript">
agata's avatar
agata committed
338
	document.querySelector('form').classList.add('shake');
agata's avatar
agata committed
339
	</script>
samba's avatar
samba committed
340
	<?php
godog's avatar
godog committed
341 342
}

lechuck's avatar
lechuck committed
343
/**
samba's avatar
samba committed
344 345
 * Outputs the viewport meta tag.
 *
lechuck's avatar
lechuck committed
346 347
 * @since 3.7.0
 */
lucha's avatar
lucha committed
348 349 350 351 352 353
function wp_login_viewport_meta() {
	?>
	<meta name="viewport" content="width=device-width" />
	<?php
}

godog's avatar
godog committed
354 355 356
/**
 * Handles sending password retrieval email to user.
 *
samba's avatar
samba committed
357 358
 * @since 2.5.0
 *
godog's avatar
godog committed
359 360 361
 * @return bool|WP_Error True: when finish. WP_Error on error
 */
function retrieve_password() {
agata's avatar
agata committed
362 363
	$errors    = new WP_Error();
	$user_data = false;
godog's avatar
godog committed
364

lucha's avatar
lucha committed
365
	if ( empty( $_POST['user_login'] ) || ! is_string( $_POST['user_login'] ) ) {
agata's avatar
agata committed
366
		$errors->add( 'empty_username', __( '<strong>Error</strong>: Enter a username or email address.' ) );
ale's avatar
ale committed
367
	} elseif ( strpos( $_POST['user_login'], '@' ) ) {
lucha's avatar
lucha committed
368
		$user_data = get_user_by( 'email', trim( wp_unslash( $_POST['user_login'] ) ) );
samba's avatar
samba committed
369
		if ( empty( $user_data ) ) {
agata's avatar
agata committed
370
			$errors->add( 'invalid_email', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
samba's avatar
samba committed
371
		}
godog's avatar
godog committed
372
	} else {
agata's avatar
agata committed
373
		$login     = trim( wp_unslash( $_POST['user_login'] ) );
samba's avatar
samba committed
374
		$user_data = get_user_by( 'login', $login );
godog's avatar
godog committed
375 376
	}

lucha's avatar
lucha committed
377 378 379 380
	/**
	 * Fires before errors are returned from a password reset request.
	 *
	 * @since 2.1.0
lechuck's avatar
lechuck committed
381
	 * @since 4.4.0 Added the `$errors` parameter.
agata's avatar
agata committed
382
	 * @since 5.4.0 Added the `$user_data` parameter.
lechuck's avatar
lechuck committed
383 384 385
	 *
	 * @param WP_Error $errors A WP_Error object containing any errors generated
	 *                         by using invalid credentials.
agata's avatar
agata committed
386
	 * @param WP_User|false    WP_User object if found, false if the user does not exist.
lucha's avatar
lucha committed
387
	 */
agata's avatar
agata committed
388
	do_action( 'lostpassword_post', $errors, $user_data );
godog's avatar
godog committed
389

samba's avatar
samba committed
390
	if ( $errors->has_errors() ) {
godog's avatar
godog committed
391
		return $errors;
samba's avatar
samba committed
392
	}
godog's avatar
godog committed
393

samba's avatar
samba committed
394
	if ( ! $user_data ) {
agata's avatar
agata committed
395
		$errors->add( 'invalidcombo', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
godog's avatar
godog committed
396 397 398
		return $errors;
	}

lucha's avatar
lucha committed
399
	// Redefining user_login ensures we return the right case in the email.
godog's avatar
godog committed
400 401
	$user_login = $user_data->user_login;
	$user_email = $user_data->user_email;
samba's avatar
samba committed
402
	$key        = get_password_reset_key( $user_data );
godog's avatar
godog committed
403

lechuck's avatar
lechuck committed
404 405
	if ( is_wp_error( $key ) ) {
		return $key;
ale's avatar
ale committed
406
	}
godog's avatar
godog committed
407

lucha's avatar
lucha committed
408
	if ( is_multisite() ) {
lucha's avatar
lucha committed
409
		$site_name = get_network()->site_name;
lucha's avatar
lucha committed
410
	} else {
lucha's avatar
lucha committed
411 412 413 414
		/*
		 * The blogname option is escaped with esc_html on the way into the database
		 * in sanitize_option we want to reverse this for the plain text arena of emails.
		 */
lucha's avatar
lucha committed
415
		$site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
lucha's avatar
lucha committed
416
	}
godog's avatar
godog committed
417

lucha's avatar
lucha committed
418
	$message = __( 'Someone has requested a password reset for the following account:' ) . "\r\n\r\n";
agata's avatar
agata committed
419
	/* translators: %s: Site name. */
samba's avatar
samba committed
420
	$message .= sprintf( __( 'Site Name: %s' ), $site_name ) . "\r\n\r\n";
agata's avatar
agata committed
421
	/* translators: %s: User login. */
samba's avatar
samba committed
422
	$message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n";
lucha's avatar
lucha committed
423 424
	$message .= __( 'If this was a mistake, just ignore this email and nothing will happen.' ) . "\r\n\r\n";
	$message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
agata's avatar
agata committed
425
	$message .= network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . "\r\n";
lucha's avatar
lucha committed
426

agata's avatar
agata committed
427
	/* translators: Password reset notification email subject. %s: Site title. */
lucha's avatar
lucha committed
428
	$title = sprintf( __( '[%s] Password Reset' ), $site_name );
godog's avatar
godog committed
429

lucha's avatar
lucha committed
430
	/**
lucha's avatar
lucha committed
431
	 * Filters the subject of the password reset email.
lucha's avatar
lucha committed
432 433
	 *
	 * @since 2.8.0
lechuck's avatar
lechuck committed
434
	 * @since 4.4.0 Added the `$user_login` and `$user_data` parameters.
lucha's avatar
lucha committed
435
	 *
lechuck's avatar
lechuck committed
436 437 438
	 * @param string  $title      Default email title.
	 * @param string  $user_login The username for the user.
	 * @param WP_User $user_data  WP_User object.
lucha's avatar
lucha committed
439
	 */
lechuck's avatar
lechuck committed
440
	$title = apply_filters( 'retrieve_password_title', $title, $user_login, $user_data );
lechuck's avatar
lechuck committed
441

lucha's avatar
lucha committed
442
	/**
lucha's avatar
lucha committed
443
	 * Filters the message body of the password reset mail.
lucha's avatar
lucha committed
444
	 *
lucha's avatar
lucha committed
445 446
	 * If the filtered message is empty, the password reset email will not be sent.
	 *
lucha's avatar
lucha committed
447
	 * @since 2.8.0
lechuck's avatar
lechuck committed
448
	 * @since 4.1.0 Added `$user_login` and `$user_data` parameters.
lucha's avatar
lucha committed
449
	 *
lechuck's avatar
lechuck committed
450 451 452 453
	 * @param string  $message    Default mail message.
	 * @param string  $key        The activation key.
	 * @param string  $user_login The username for the user.
	 * @param WP_User $user_data  WP_User object.
lucha's avatar
lucha committed
454
	 */
lechuck's avatar
lechuck committed
455
	$message = apply_filters( 'retrieve_password_message', $message, $key, $user_login, $user_data );
godog's avatar
godog committed
456

samba's avatar
samba committed
457
	if ( $message && ! wp_mail( $user_email, wp_specialchars_decode( $title ), $message ) ) {
agata's avatar
agata committed
458 459 460 461
		$errors->add(
			'retrieve_password_email_failure',
			sprintf(
				/* translators: %s: Documentation URL. */
agata's avatar
agata committed
462
				__( '<strong>Error</strong>: The email could not be sent. Your site may not be correctly configured to send emails. <a href="%s">Get support for resetting your password</a>.' ),
agata's avatar
agata committed
463 464 465 466
				esc_url( __( 'https://wordpress.org/support/article/resetting-your-password/' ) )
			)
		);
		return $errors;
samba's avatar
samba committed
467
	}
godog's avatar
godog committed
468 469 470 471 472

	return true;
}

//
samba's avatar
samba committed
473
// Main.
godog's avatar
godog committed
474 475
//

samba's avatar
samba committed
476
$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
godog's avatar
godog committed
477 478
$errors = new WP_Error();

samba's avatar
samba committed
479
if ( isset( $_GET['key'] ) ) {
godog's avatar
godog committed
480
	$action = 'resetpass';
samba's avatar
samba committed
481
}
godog's avatar
godog committed
482

agata's avatar
agata committed
483 484 485 486 487 488 489 490 491 492 493 494 495 496
$default_actions = array(
	'confirm_admin_email',
	'postpass',
	'logout',
	'lostpassword',
	'retrievepassword',
	'resetpass',
	'rp',
	'register',
	'login',
	'confirmaction',
	WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED,
);

samba's avatar
samba committed
497
// Validate action so as to default to the login screen.
agata's avatar
agata committed
498
if ( ! in_array( $action, $default_actions, true ) && false === has_filter( 'login_form_' . $action ) ) {
godog's avatar
godog committed
499
	$action = 'login';
samba's avatar
samba committed
500
}
godog's avatar
godog committed
501 502 503

nocache_headers();

samba's avatar
samba committed
504
header( 'Content-Type: ' . get_bloginfo( 'html_type' ) . '; charset=' . get_bloginfo( 'charset' ) );
godog's avatar
godog committed
505

agata's avatar
agata committed
506
if ( defined( 'RELOCATE' ) && RELOCATE ) { // Move flag is set.
agata's avatar
agata committed
507
	if ( isset( $_SERVER['PATH_INFO'] ) && ( $_SERVER['PATH_INFO'] !== $_SERVER['PHP_SELF'] ) ) {
godog's avatar
godog committed
508
		$_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] );
samba's avatar
samba committed
509
	}
godog's avatar
godog committed
510

samba's avatar
samba committed
511
	$url = dirname( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] ) );
agata's avatar
agata committed
512

agata's avatar
agata committed
513
	if ( get_option( 'siteurl' ) !== $url ) {
lechuck's avatar
lechuck committed
514
		update_option( 'siteurl', $url );
samba's avatar
samba committed
515
	}
godog's avatar
godog committed
516 517
}

agata's avatar
agata committed
518
// Set a cookie now to see if they are supported by the browser.
lechuck's avatar
lechuck committed
519
$secure = ( 'https' === parse_url( wp_login_url(), PHP_URL_SCHEME ) );
lucha's avatar
lucha committed
520
setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure );
agata's avatar
agata committed
521

agata's avatar
agata committed
522
if ( SITECOOKIEPATH !== COOKIEPATH ) {
lucha's avatar
lucha committed
523
	setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure );
samba's avatar
samba committed
524
}
godog's avatar
godog committed
525

lucha's avatar
lucha committed
526 527 528 529 530
/**
 * Fires when the login form is initialized.
 *
 * @since 3.2.0
 */
shammash's avatar
shammash committed
531
do_action( 'login_init' );
lucha's avatar
lucha committed
532

lucha's avatar
lucha committed
533 534 535
/**
 * Fires before a specified login form action.
 *
lechuck's avatar
lechuck committed
536
 * The dynamic portion of the hook name, `$action`, refers to the action
lucha's avatar
lucha committed
537 538 539 540 541
 * that brought the visitor to the login form. Actions include 'postpass',
 * 'logout', 'lostpassword', etc.
 *
 * @since 2.8.0
 */
lucha's avatar
lucha committed
542
do_action( "login_form_{$action}" );
godog's avatar
godog committed
543

agata's avatar
agata committed
544
$http_post     = ( 'POST' === $_SERVER['REQUEST_METHOD'] );
samba's avatar
samba committed
545
$interim_login = isset( $_REQUEST['interim-login'] );
lechuck's avatar
lechuck committed
546

lucha's avatar
lucha committed
547 548 549 550 551 552 553 554 555
/**
 * Filters the separator used between login form navigation links.
 *
 * @since 4.9.0
 *
 * @param string $login_link_separator The separator used between login form navigation links.
 */
$login_link_separator = apply_filters( 'login_link_separator', ' | ' );

samba's avatar
samba committed
556
switch ( $action ) {
lechuck's avatar
lechuck committed
557

agata's avatar
agata committed
558
	case 'confirm_admin_email':
agata's avatar
agata committed
559 560 561 562 563
		/*
		 * Note that `is_user_logged_in()` will return false immediately after logging in
		 * as the current user is not set, see wp-includes/pluggable.php.
		 * However this action runs on a redirect after logging in.
		 */
agata's avatar
agata committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
		if ( ! is_user_logged_in() ) {
			wp_safe_redirect( wp_login_url() );
			exit;
		}

		if ( ! empty( $_REQUEST['redirect_to'] ) ) {
			$redirect_to = $_REQUEST['redirect_to'];
		} else {
			$redirect_to = admin_url();
		}

		if ( current_user_can( 'manage_options' ) ) {
			$admin_email = get_option( 'admin_email' );
		} else {
			wp_safe_redirect( $redirect_to );
			exit;
		}

		/**
		 * Filters the interval for dismissing the admin email confirmation screen.
		 *
		 * If `0` (zero) is returned, the "Remind me later" link will not be displayed.
		 *
		 * @since 5.3.1
		 *
		 * @param int $interval Interval time (in seconds). Default is 3 days.
		 */
		$remind_interval = (int) apply_filters( 'admin_email_remind_interval', 3 * DAY_IN_SECONDS );

		if ( ! empty( $_GET['remind_me_later'] ) ) {
			if ( ! wp_verify_nonce( $_GET['remind_me_later'], 'remind_me_later_nonce' ) ) {
				wp_safe_redirect( wp_login_url() );
				exit;
			}

			if ( $remind_interval > 0 ) {
				update_option( 'admin_email_lifespan', time() + $remind_interval );
			}

			wp_safe_redirect( $redirect_to );
			exit;
		}

		if ( ! empty( $_POST['correct-admin-email'] ) ) {
			if ( ! check_admin_referer( 'confirm_admin_email', 'confirm_admin_email_nonce' ) ) {
				wp_safe_redirect( wp_login_url() );
				exit;
			}

			/**
			 * Filters the interval for redirecting the user to the admin email confirmation screen.
			 *
			 * If `0` (zero) is returned, the user will not be redirected.
			 *
			 * @since 5.3.0
			 *
			 * @param int $interval Interval time (in seconds). Default is 6 months.
			 */
			$admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS );

			if ( $admin_email_check_interval > 0 ) {
				update_option( 'admin_email_lifespan', time() + $admin_email_check_interval );
			}

			wp_safe_redirect( $redirect_to );
			exit;
		}

		login_header( __( 'Confirm your administration email' ), '', $errors );

		/**
		 * Fires before the admin email confirm form.
		 *
		 * @since 5.3.0
		 *
		 * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
		 *                         credentials. Note that the error object may not contain any errors.
		 */
		do_action( 'admin_email_confirm', $errors );

		?>

		<form class="admin-email-confirm-form" name="admin-email-confirm-form" action="<?php echo esc_url( site_url( 'wp-login.php?action=confirm_admin_email', 'login_post' ) ); ?>" method="post">
			<?php
			/**
			 * Fires inside the admin-email-confirm-form form tags, before the hidden fields.
			 *
			 * @since 5.3.0
			 */
			do_action( 'admin_email_confirm_form' );

			wp_nonce_field( 'confirm_admin_email', 'confirm_admin_email_nonce' );

			?>
			<input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />

			<h1 class="admin-email__heading">
				<?php _e( 'Administration email verification' ); ?>
			</h1>
			<p class="admin-email__details">
				<?php _e( 'Please verify that the <strong>administration email</strong> for this website is still correct.' ); ?>
				<?php

				/* translators: URL to the WordPress help section about admin email. */
				$admin_email_help_url = __( 'https://wordpress.org/support/article/settings-general-screen/#email-address' );

				/* translators: accessibility text */
				$accessibility_text = sprintf( '<span class="screen-reader-text"> %s</span>', __( '(opens in a new tab)' ) );

				printf(
					'<a href="%s" rel="noopener noreferrer" target="_blank">%s%s</a>',
					esc_url( $admin_email_help_url ),
					__( 'Why is this important?' ),
					$accessibility_text
				);

				?>
			</p>
			<p class="admin-email__details">
				<?php

				printf(
					/* translators: %s: Admin email address. */
					__( 'Current administration email: %s' ),
					'<strong>' . esc_html( $admin_email ) . '</strong>'
				);

				?>
			</p>
			<p class="admin-email__details">
				<?php _e( 'This email may be different from your personal email address.' ); ?>
			</p>

			<div class="admin-email__actions">
				<div class="admin-email__actions-primary">
					<?php

					$change_link = admin_url( 'options-general.php' );
					$change_link = add_query_arg( 'highlight', 'confirm_admin_email', $change_link );

					?>
					<a class="button button-large" href="<?php echo esc_url( $change_link ); ?>"><?php _e( 'Update' ); ?></a>
					<input type="submit" name="correct-admin-email" id="correct-admin-email" class="button button-primary button-large" value="<?php esc_attr_e( 'The email is correct' ); ?>" />
				</div>
				<?php if ( $remind_interval > 0 ) : ?>
					<div class="admin-email__actions-secondary">
						<?php

						$remind_me_link = wp_login_url( $redirect_to );
						$remind_me_link = add_query_arg(
							array(
								'action'          => 'confirm_admin_email',
								'remind_me_later' => wp_create_nonce( 'remind_me_later_nonce' ),
							),
							$remind_me_link
						);

						?>
						<a href="<?php echo esc_url( $remind_me_link ); ?>"><?php _e( 'Remind me later' ); ?></a>
					</div>
				<?php endif; ?>
			</div>
		</form>

		<?php

		login_footer();
		break;

samba's avatar
samba committed
733 734 735
	case 'postpass':
		if ( ! array_key_exists( 'post_password', $_POST ) ) {
			wp_safe_redirect( wp_get_referer() );
agata's avatar
agata committed
736
			exit;
samba's avatar
samba committed
737
		}
lechuck's avatar
lechuck committed
738

samba's avatar
samba committed
739 740
		require_once ABSPATH . WPINC . '/class-phpass.php';
		$hasher = new PasswordHash( 8, true );
lechuck's avatar
lechuck committed
741

samba's avatar
samba committed
742 743 744 745 746 747 748 749 750 751 752 753
		/**
		 * Filters the life span of the post password cookie.
		 *
		 * By default, the cookie expires 10 days from creation. To turn this
		 * into a session cookie, return 0.
		 *
		 * @since 3.7.0
		 *
		 * @param int $expires The expiry time, as passed to setcookie().
		 */
		$expire  = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
		$referer = wp_get_referer();
agata's avatar
agata committed
754

samba's avatar
samba committed
755 756 757 758 759
		if ( $referer ) {
			$secure = ( 'https' === parse_url( $referer, PHP_URL_SCHEME ) );
		} else {
			$secure = false;
		}
agata's avatar
agata committed
760

samba's avatar
samba committed
761
		setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
lechuck's avatar
lechuck committed
762

samba's avatar
samba committed
763 764
		wp_safe_redirect( wp_get_referer() );
		exit();
ale's avatar
ale committed
765

samba's avatar
samba committed
766 767
	case 'logout':
		check_admin_referer( 'log-out' );
ale's avatar
ale committed
768

samba's avatar
samba committed
769
		$user = wp_get_current_user();
godog's avatar
godog committed
770

samba's avatar
samba committed
771
		wp_logout();
ale's avatar
ale committed
772

samba's avatar
samba committed
773
		if ( ! empty( $_REQUEST['redirect_to'] ) ) {
agata's avatar
agata committed
774 775
			$redirect_to           = $_REQUEST['redirect_to'];
			$requested_redirect_to = $redirect_to;
samba's avatar
samba committed
776
		} else {
agata's avatar
agata committed
777 778 779 780 781 782 783 784
			$redirect_to = add_query_arg(
				array(
					'loggedout' => 'true',
					'wp_lang'   => get_user_locale( $user ),
				),
				wp_login_url()
			);

samba's avatar
samba committed
785 786
			$requested_redirect_to = '';
		}
godog's avatar
godog committed
787

samba's avatar
samba committed
788 789 790 791 792 793 794 795 796 797
		/**
		 * Filters the log out redirect URL.
		 *
		 * @since 4.2.0
		 *
		 * @param string  $redirect_to           The redirect destination URL.
		 * @param string  $requested_redirect_to The requested redirect destination URL passed as a parameter.
		 * @param WP_User $user                  The WP_User object for the user that's logging out.
		 */
		$redirect_to = apply_filters( 'logout_redirect', $redirect_to, $requested_redirect_to, $user );
agata's avatar
agata committed
798

samba's avatar
samba committed
799 800
		wp_safe_redirect( $redirect_to );
		exit();
root's avatar
root committed
801

samba's avatar
samba committed
802 803 804 805
	case 'lostpassword':
	case 'retrievepassword':
		if ( $http_post ) {
			$errors = retrieve_password();
agata's avatar
agata committed
806

samba's avatar
samba committed
807 808 809 810 811
			if ( ! is_wp_error( $errors ) ) {
				$redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
				wp_safe_redirect( $redirect_to );
				exit();
			}
godog's avatar
godog committed
812 813
		}

samba's avatar
samba committed
814
		if ( isset( $_GET['error'] ) ) {
agata's avatar
agata committed
815
			if ( 'invalidkey' === $_GET['error'] ) {
samba's avatar
samba committed
816
				$errors->add( 'invalidkey', __( 'Your password reset link appears to be invalid. Please request a new link below.' ) );
agata's avatar
agata committed
817
			} elseif ( 'expiredkey' === $_GET['error'] ) {
samba's avatar
samba committed
818 819
				$errors->add( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) );
			}
lechuck's avatar
lechuck committed
820
		}
lucha's avatar
lucha committed
821

samba's avatar
samba committed
822 823 824 825 826 827 828 829 830
		$lostpassword_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
		/**
		 * Filters the URL redirected to after submitting the lostpassword/retrievepassword form.
		 *
		 * @since 3.0.0
		 *
		 * @param string $lostpassword_redirect The redirect destination URL.
		 */
		$redirect_to = apply_filters( 'lostpassword_redirect', $lostpassword_redirect );
lucha's avatar
lucha committed
831

samba's avatar
samba committed
832 833 834 835 836 837 838 839 840 841
		/**
		 * Fires before the lost password form.
		 *
		 * @since 1.5.1
		 * @since 5.1.0 Added the `$errors` parameter.
		 *
		 * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
		 *                         credentials. Note that the error object may not contain any errors.
		 */
		do_action( 'lost_password', $errors );
godog's avatar
godog committed
842

agata's avatar
agata committed
843
		login_header( __( 'Lost Password' ), '<p class="message">' . __( 'Please enter your username or email address. You will receive an email message with instructions on how to reset your password.' ) . '</p>', $errors );
godog's avatar
godog committed
844

samba's avatar
samba committed
845
		$user_login = '';
lucha's avatar
lucha committed
846

samba's avatar
samba committed
847 848 849
		if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
			$user_login = wp_unslash( $_POST['user_login'] );
		}
godog's avatar
godog committed
850

samba's avatar
samba committed
851
		?>
godog's avatar
godog committed
852

agata's avatar
agata committed
853 854 855 856 857 858
		<form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=lostpassword', 'login_post' ) ); ?>" method="post">
			<p>
				<label for="user_login"><?php _e( 'Username or Email Address' ); ?></label>
				<input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" />
			</p>
			<?php
lucha's avatar
lucha committed
859

agata's avatar
agata committed
860 861 862 863 864 865
			/**
			 * Fires inside the lostpassword form tags, before the hidden fields.
			 *
			 * @since 2.1.0
			 */
			do_action( 'lostpassword_form' );
lucha's avatar
lucha committed
866

agata's avatar
agata committed
867 868 869 870 871 872 873 874 875 876
			?>
			<input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
			<p class="submit">
				<input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Get New Password' ); ?>" />
			</p>
		</form>

		<p id="nav">
			<a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
			<?php
agata's avatar
agata committed
877

agata's avatar
agata committed
878 879 880 881 882 883 884 885
			if ( get_option( 'users_can_register' ) ) {
				$registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );

				echo esc_html( $login_link_separator );

				/** This filter is documented in wp-includes/general-template.php */
				echo apply_filters( 'register', $registration_url );
			}
godog's avatar
godog committed
886

agata's avatar
agata committed
887 888
			?>
		</p>
samba's avatar
samba committed
889
		<?php
agata's avatar
agata committed
890

agata's avatar
agata committed
891
		login_footer( 'user_login' );
samba's avatar
samba committed
892 893 894 895 896 897
		break;

	case 'resetpass':
	case 'rp':
		list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
		$rp_cookie       = 'wp-resetpass-' . COOKIEHASH;
agata's avatar
agata committed
898

samba's avatar
samba committed
899 900 901
		if ( isset( $_GET['key'] ) ) {
			$value = sprintf( '%s:%s', wp_unslash( $_GET['login'] ), wp_unslash( $_GET['key'] ) );
			setcookie( $rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
agata's avatar
agata committed
902

samba's avatar
samba committed
903 904 905
			wp_safe_redirect( remove_query_arg( array( 'key', 'login' ) ) );
			exit;
		}
lechuck's avatar
lechuck committed
906

samba's avatar
samba committed
907 908
		if ( isset( $_COOKIE[ $rp_cookie ] ) && 0 < strpos( $_COOKIE[ $rp_cookie ], ':' ) ) {
			list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ $rp_cookie ] ), 2 );
agata's avatar
agata committed
909 910 911

			$user = check_password_reset_key( $rp_key, $rp_login );

samba's avatar
samba committed
912 913 914 915
			if ( isset( $_POST['pass1'] ) && ! hash_equals( $rp_key, $_POST['rp_key'] ) ) {
				$user = false;
			}
		} else {
lechuck's avatar
lechuck committed
916 917
			$user = false;
		}
godog's avatar
godog committed
918

samba's avatar
samba committed
919 920
		if ( ! $user || is_wp_error( $user ) ) {
			setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
agata's avatar
agata committed
921

samba's avatar
samba committed
922 923 924 925 926
			if ( $user && $user->get_error_code() === 'expired_key' ) {
				wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=expiredkey' ) );
			} else {
				wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=invalidkey' ) );
			}
agata's avatar
agata committed
927

samba's avatar
samba committed
928 929
			exit;
		}
lechuck's avatar
lechuck committed
930

samba's avatar
samba committed
931
		$errors = new WP_Error();
lechuck's avatar
lechuck committed
932

agata's avatar
agata committed
933
		if ( isset( $_POST['pass1'] ) && $_POST['pass1'] !== $_POST['pass2'] ) {
samba's avatar
samba committed
934 935
			$errors->add( 'password_reset_mismatch', __( 'The passwords do not match.' ) );
		}
root's avatar
root committed
936

samba's avatar
samba committed
937 938 939 940 941
		/**
		 * Fires before the password reset procedure is validated.
		 *
		 * @since 3.5.0
		 *
agata's avatar
agata committed
942
		 * @param WP_Error         $errors WP Error object.
samba's avatar
samba committed
943 944 945 946 947 948 949 950 951 952 953
		 * @param WP_User|WP_Error $user   WP_User object if the login and reset key match. WP_Error object otherwise.
		 */
		do_action( 'validate_password_reset', $errors, $user );

		if ( ( ! $errors->has_errors() ) && isset( $_POST['pass1'] ) && ! empty( $_POST['pass1'] ) ) {
			reset_password( $user, $_POST['pass1'] );
			setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
			login_header( __( 'Password Reset' ), '<p class="message reset-pass">' . __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a></p>' );
			login_footer();
			exit;
		}
godog's avatar
godog committed
954

samba's avatar
samba committed
955 956
		wp_enqueue_script( 'utils' );
		wp_enqueue_script( 'user-profile' );
root's avatar
root committed
957

samba's avatar
samba committed
958
		login_header( __( 'Reset Password' ), '<p class="message reset-pass">' . __( 'Enter your new password below.' ) . '</p>', $errors );
root's avatar
root committed
959

samba's avatar
samba committed
960
		?>
agata's avatar
agata committed
961 962
		<form name="resetpassform" id="resetpassform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=resetpass', 'login_post' ) ); ?>" method="post" autocomplete="off">
			<input type="hidden" id="user_login" value="<?php echo esc_attr( $rp_login ); ?>" autocomplete="off" />
lechuck's avatar
lechuck committed
963

agata's avatar
agata committed
964 965 966 967 968 969 970
			<div class="user-pass1-wrap">
				<p>
					<label for="pass1"><?php _e( 'New password' ); ?></label>
				</p>

				<div class="wp-pwd">
					<input type="password" data-reveal="1" data-pw="<?php echo esc_attr( wp_generate_password( 16 ) ); ?>" name="pass1" id="pass1" class="input password-input" size="24" value="" autocomplete="off" aria-describedby="pass-strength-result" />
agata's avatar
agata committed
971

agata's avatar
agata committed
972 973 974 975 976 977 978 979 980
					<button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Hide password' ); ?>">
						<span class="dashicons dashicons-hidden" aria-hidden="true"></span>
					</button>
					<div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e( 'Strength indicator' ); ?></div>
				</div>
				<div class="pw-weak">
					<input type="checkbox" name="pw_weak" id="pw-weak" class="pw-checkbox" />
					<label for="pw-weak"><?php _e( 'Confirm use of weak password' ); ?></label>
				</div>
lucha's avatar
lucha committed
981
			</div>
lechuck's avatar
lechuck committed
982

agata's avatar
agata committed
983 984 985 986
			<p class="user-pass2-wrap">
				<label for="pass2"><?php _e( 'Confirm new password' ); ?></label>
				<input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" />
			</p>
agata's avatar
agata committed
987

agata's avatar
agata committed
988 989
			<p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
			<br class="clear" />
agata's avatar
agata committed
990

agata's avatar
agata committed
991
			<?php
agata's avatar
agata committed
992

agata's avatar
agata committed
993 994 995 996 997 998 999 1000
			/**
			 * Fires following the 'Strength indicator' meter in the user password reset form.
			 *
			 * @since 3.9.0
			 *
			 * @param WP_User $user User object of the user whose password is being reset.
			 */
			do_action( 'resetpass_form', $user );
agata's avatar
agata committed
1001

agata's avatar
agata committed
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
			?>
			<input type="hidden" name="rp_key" value="<?php echo esc_attr( $rp_key ); ?>" />
			<p class="submit">
				<input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Reset Password' ); ?>" />
			</p>
		</form>

		<p id="nav">
			<a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
			<?php

			if ( get_option( 'users_can_register' ) ) {
				$registration_url = sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );

				echo esc_html( $login_link_separator );

				/** This filter is documented in wp-includes/general-template.php */
				echo apply_filters( 'register', $registration_url );
			}

			?>
		</p>
samba's avatar
samba committed
1024
		<?php
agata's avatar
agata committed
1025

agata's avatar
agata committed
1026
		login_footer( 'user_pass' );
samba's avatar
samba committed
1027
		break;
godog's avatar
godog committed
1028

samba's avatar
samba committed
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
	case 'register':
		if ( is_multisite() ) {
			/**
			 * Filters the Multisite sign up URL.
			 *
			 * @since 3.0.0
			 *
			 * @param string $sign_up_url The sign up URL.
			 */
			wp_redirect( apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ) );
			exit;
		}
godog's avatar
godog committed
1041

samba's avatar
samba committed
1042 1043 1044 1045
		if ( ! get_option( 'users_can_register' ) ) {
			wp_redirect( site_url( 'wp-login.php?registration=disabled' ) );
			exit();
		}
godog's avatar
godog committed
1046

samba's avatar
samba committed
1047 1048
		$user_login = '';
		$user_email = '';
lucha's avatar
lucha committed
1049

samba's avatar
samba committed
1050 1051
		if ( $http_post ) {
			if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
agata's avatar
agata committed
1052
				$user_login = wp_unslash( $_POST['user_login'] );
samba's avatar
samba committed
1053
			}
lucha's avatar
lucha committed
1054

samba's avatar
samba committed
1055 1056 1057
			if ( isset( $_POST['user_email'] ) && is_string( $_POST['user_email'] ) ) {
				$user_email = wp_unslash( $_POST['user_email'] );
			}
lucha's avatar
lucha committed
1058

samba's avatar
samba committed
1059
			$errors = register_new_user( $user_login, $user_email );
agata's avatar
agata committed
1060

samba's avatar
samba committed
1061 1062 1063 1064 1065
			if ( ! is_wp_error( $errors ) ) {
				$redirect_to = ! empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
				wp_safe_redirect( $redirect_to );
				exit();
			}
godog's avatar
godog committed
1066 1067
		}

samba's avatar
samba committed
1068
		$registration_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
agata's avatar
agata committed
1069

samba's avatar
samba committed
1070 1071 1072 1073 1074 1075 1076 1077
		/**
		 * Filters the registration redirect URL.
		 *
		 * @since 3.0.0
		 *
		 * @param string $registration_redirect The redirect destination URL.
		 */
		$redirect_to = apply_filters( 'registration_redirect', $registration_redirect );
agata's avatar
agata committed
1078

samba's avatar
samba committed
1079
		login_header( __( 'Registration Form' ), '<p class="message register">' . __( 'Register For This Site' ) . '</p>', $errors );
agata's avatar
agata committed
1080

samba's avatar
samba committed
1081
		?>
agata's avatar
agata committed
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
		<form name="registerform" id="registerform" action="<?php echo esc_url( site_url( 'wp-login.php?action=register', 'login_post' ) ); ?>" method="post" novalidate="novalidate">
			<p>
				<label for="user_login"><?php _e( 'Username' ); ?></label>
				<input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr( wp_unslash( $user_login ) ); ?>" size="20" autocapitalize="off" />
			</p>
			<p>
				<label for="user_email"><?php _e( 'Email' ); ?></label>
				<input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr( wp_unslash( $user_email ) ); ?>" size="25" />
			</p>
			<?php

			/**
			 * Fires following the 'Email' field in the user registration form.
			 *
			 * @since 2.1.0
			 */
			do_action( 'register_form' );
kiki's avatar
kiki committed
1099

agata's avatar
agata committed
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
			?>
			<p id="reg_passmail">
				<?php _e( 'Registration confirmation will be emailed to you.' ); ?>
			</p>
			<br class="clear" />
			<input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
			<p class="submit">
				<input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Register' ); ?>" />
			</p>
		</form>

		<p id="nav">
			<a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
				<?php echo esc_html( $login_link_separator ); ?>
			<a href="<?php echo esc_url( wp_lostpassword_url() ); ?>"><?php _e( 'Lost your password?' ); ?></a>
		</p>
agata's avatar
agata committed
1116 1117
		<?php

agata's avatar
agata committed
1118
		login_footer( 'user_login' );
samba's avatar
samba committed
1119
		break;
kiki's avatar
kiki committed
1120

samba's avatar
samba committed
1121 1122
	case 'confirmaction':
		if ( ! isset( $_GET['request_id'] ) ) {
agata's avatar
agata committed
1123
			wp_die( __( 'Missing request ID.' ) );
samba's avatar
samba committed
1124
		}
kiki's avatar
kiki committed
1125

agata's avatar
agata committed
1126 1127
		if ( ! isset( $_GET['confirm_key'] ) ) {
			wp_die( __( 'Missing confirm key.' ) );
samba's avatar
samba committed
1128
		}
kiki's avatar
kiki committed
1129

agata's avatar
agata committed
1130 1131 1132 1133
		$request_id = (int) $_GET['request_id'];
		$key        = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) );
		$result     = wp_validate_user_request_key( $request_id, $key );

samba's avatar
samba committed
1134 1135 1136
		if ( is_wp_error( $result ) ) {
			wp_die( $result );
		}
kiki's avatar
kiki committed
1137

samba's avatar
samba committed
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
		/**
		 * Fires an action hook when the account action has been confirmed by the user.
		 *
		 * Using this you can assume the user has agreed to perform the action by
		 * clicking on the link in the confirmation email.
		 *
		 * After firing this action hook the page will redirect to wp-login a callback
		 * redirects or exits first.
		 *
		 * @since 4.9.6
		 *
		 * @param int $request_id Request ID.
		 */
		do_action( 'user_request_action_confirmed', $request_id );
godog's avatar
godog committed
1152

samba's avatar
samba committed
1153
		$message = _wp_privacy_account_request_confirmed_message( $request_id );
lechuck's avatar
lechuck committed
1154

samba's avatar
samba committed
1155 1156 1157
		login_header( __( 'User action confirmed.' ), $message );
		login_footer();
		exit;
lechuck's avatar
lechuck committed
1158

samba's avatar
samba committed
1159 1160 1161 1162
	case 'login':
	default:
		$secure_cookie   = '';
		$customize_login = isset( $_REQUEST['customize-login'] );
agata's avatar
agata committed
1163

samba's avatar
samba committed
1164 1165
		if ( $customize_login ) {
			wp_enqueue_script( 'customize-base' );
godog's avatar
godog committed
1166 1167
		}

samba's avatar
samba committed
1168 1169
		// If the user wants SSL but the session is not SSL, force a secure cookie.
		if ( ! empty( $_POST['log'] ) && ! force_ssl_admin() ) {
agata's avatar
agata committed
1170
			$user_name = sanitize_user( wp_unslash( $_POST['log'] ) );
samba's avatar
samba committed
1171
			$user      = get_user_by( 'login', $user_name );
godog's avatar
godog committed
1172

samba's avatar
samba committed
1173 1174 1175
			if ( ! $user && strpos( $user_name, '@' ) ) {
				$user = get_user_by( 'email', $user_name );
			}
godog's avatar
godog committed
1176

samba's avatar
samba committed