* Handles authentication, registering, resetting passwords, forgot password,
* and other user handling.
/** Make sure that the WordPress bootstrap has run before continuing. */
require __DIR__ . '/wp-load.php';
// Redirect to HTTPS login if forced to use SSL.
if ( force_ssl_admin() && ! is_ssl() ) {
if ( str_starts_with( $_SERVER['REQUEST_URI'], 'http' ) ) {
wp_safe_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
* Outputs the login page header.
* @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'
* @global string $action The action that brought the visitor to the login page.
* @param string|null $title Optional. WordPress login page title to display in the `<title>` element.
* @param string $message Optional. Message to display in header. Default empty.
* @param WP_Error|null $wp_error Optional. The error to pass. Defaults to a WP_Error instance.
function login_header( $title = null, $message = '', $wp_error = null ) {
global $error, $interim_login, $action;
// Don't index any of these forms.
add_filter( 'wp_robots', 'wp_robots_sensitive_page' );
add_action( 'login_head', 'wp_strict_cross_origin_referrer' );
add_action( 'login_head', 'wp_login_viewport_meta' );
if ( ! is_wp_error( $wp_error ) ) {
$wp_error = new WP_Error();
$shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure' );
* Filters the error codes array for shaking the login form.
* @param string[] $shake_error_codes Error codes that shake the login form.
$shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
if ( $shake_error_codes && $wp_error->has_errors() && in_array( $wp_error->get_error_code(), $shake_error_codes, true ) ) {
add_action( 'login_footer', 'wp_shake_js', 12 );
$login_title = get_bloginfo( 'name', 'display' );
/* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
$login_title = sprintf( __( '%1$s ‹ %2$s — WordPress' ), $title, $login_title );
if ( wp_is_recovery_mode() ) {
/* translators: %s: Login screen title. */
$login_title = sprintf( __( 'Recovery Mode — %s' ), $login_title );
* Filters the title tag content for login page.
* @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 );
<html <?php language_attributes(); ?>>
<meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
<title><?php echo $login_title; ?></title>
wp_enqueue_style( 'login' );
* Remove all stored post data on logging out.
* This could be added by add_action('login_head'...) like wp_shake_js(),
* but maybe better if it's not removable by plugins.
if ( 'loggedout' === $wp_error->get_error_code() ) {
<script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
* Enqueues scripts and styles for the login page.
do_action( 'login_enqueue_scripts' );
* Fires in the login page header after scripts are enqueued.
do_action( 'login_head' );
$login_header_url = __( 'https://wordpress.org/' );
* Filters link URL of the header logo above login form.
* @param string $login_header_url Login header logo URL.
$login_header_url = apply_filters( 'login_headerurl', $login_header_url );
$login_header_title = '';
* Filters the title attribute of the header logo above login form.
* @deprecated 5.2.0 Use {@see 'login_headertext'} instead.
* @param string $login_header_title Login header logo title attribute.
$login_header_title = apply_filters_deprecated(
array( $login_header_title ),
__( 'Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.' )
$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.
* @param string $login_header_text The login header logo link text.
$login_header_text = apply_filters( 'login_headertext', $login_header_text );
$classes = array( 'login-action-' . $action, 'wp-core-ui' );
$classes[] = 'interim-login';
<style type="text/css">html{background-color: transparent;}</style>
if ( 'success' === $interim_login ) {
$classes[] = 'interim-login-success';
$classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
* Filters the login page body classes.
* @param string[] $classes An array of body classes.
* @param string $action The action that brought the visitor to the login page.
$classes = apply_filters( 'login_body_class', $classes, $action );
<body class="login no-js <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
wp_print_inline_script_tag( "document.body.className = document.body.className.replace('no-js','js');" );
* Fires in the login page header after the body tag is opened.
do_action( 'login_header' );
if ( 'confirm_admin_email' !== $action && ! empty( $title ) ) :
<h1 class="screen-reader-text"><?php echo $title; ?></h1>
<h1 role="presentation" class="wp-login-logo"><a href="<?php echo esc_url( $login_header_url ); ?>"><?php echo $login_header_text; ?></a></h1>
* Filters the message to display above the login form.
* @param string $message Login message text.
$message = apply_filters( 'login_message', $message );
if ( ! empty( $message ) ) {
// In case a plugin uses $error rather than the $wp_errors object.
if ( ! empty( $error ) ) {
$wp_error->add( 'error', $error );
if ( $wp_error->has_errors() ) {
foreach ( $wp_error->get_error_codes() as $code ) {
$severity = $wp_error->get_error_data( $code );
foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
if ( 'message' === $severity ) {
$messages .= '<p>' . $error_message . '</p>';
$error_list[] = $error_message;
if ( ! empty( $error_list ) ) {
if ( count( $error_list ) > 1 ) {
$errors .= '<ul class="login-error-list">';
foreach ( $error_list as $item ) {
$errors .= '<li>' . $item . '</li>';
$errors .= '<p>' . $error_list[0] . '</p>';
* Filters the error messages displayed above the login form.
* @param string $errors Login error messages.
$errors = apply_filters( 'login_errors', $errors );
'paragraph_wrap' => false,
if ( ! empty( $messages ) ) {
* Filters instructional messages displayed above the login form.
* @param string $messages Login messages.
$messages = apply_filters( 'login_messages', $messages );
'additional_classes' => array( 'message' ),
'paragraph_wrap' => false,
} // End of login_header().
* Outputs the footer for the login page.
* @global bool|string $interim_login Whether interim login modal is being displayed. String 'success'
* @param string $input_id Which input to auto-focus.
function login_footer( $input_id = '' ) {
// Don't allow interim logins to navigate away from the page.
if ( ! $interim_login ) {
esc_url( home_url( '/' ) ),
/* translators: %s: Site title. */
_x( '← Go to %s', 'site' ),
get_bloginfo( 'title', 'display' )
* Filters the "Go to site" link displayed in the login page footer.
* @param string $link HTML link to the home URL of the current site.
echo apply_filters( 'login_site_html_link', $html_link );
the_privacy_policy_link( '<div class="privacy-policy-page-link">', '</div>' );
</div><?php // End of <div id="login">. ?>
* Filters whether to display the Language selector on the login screen.
* @param bool $display Whether to display the Language selector on the login screen.
apply_filters( 'login_display_language_dropdown', true )
$languages = get_available_languages();
if ( ! empty( $languages ) ) {
<div class="language-switcher">
<form id="language-switcher" method="get">
<label for="language-switcher-locales">
<span class="dashicons dashicons-translation" aria-hidden="true"></span>
<span class="screen-reader-text">
/* translators: Hidden accessibility text. */
'id' => 'language-switcher-locales',
'selected' => determine_locale(),
'show_available_translations' => false,
'explicit_option_en_us' => true,
'languages' => $languages,
* Filters default arguments for the Languages select input on the login screen.
* The arguments get passed to the wp_dropdown_languages() function.
* @param array $args Arguments for the Languages select input on the login screen.
wp_dropdown_languages( apply_filters( 'login_language_dropdown_args', $args ) );
<?php if ( $interim_login ) { ?>
<input type="hidden" name="interim-login" value="1" />
<?php if ( isset( $_GET['redirect_to'] ) && '' !== $_GET['redirect_to'] ) { ?>
<input type="hidden" name="redirect_to" value="<?php echo sanitize_url( $_GET['redirect_to'] ); ?>" />
<?php if ( isset( $_GET['action'] ) && '' !== $_GET['action'] ) { ?>
<input type="hidden" name="action" value="<?php echo esc_attr( $_GET['action'] ); ?>" />
<input type="submit" class="button" value="<?php esc_attr_e( 'Change' ); ?>">
if ( ! empty( $input_id ) ) {
try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
if(typeof wpOnload==='function')wpOnload();
wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
* Fires in the login page footer.
do_action( 'login_footer' );
* Outputs the JavaScript to handle the form shaking on the login page.
wp_print_inline_script_tag( "document.querySelector('form').classList.add('shake');" );
* Outputs the viewport meta tag for the login page.
function wp_login_viewport_meta() {
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
* Check the request and redirect or display a form based on the current action.
$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
$errors = new WP_Error();
if ( isset( $_GET['key'] ) ) {
if ( isset( $_GET['checkemail'] ) ) {
$default_actions = array(