[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/ -> wp-login.php (source)

   1  <?php
   2  /**
   3   * WordPress User Page
   4   *
   5   * Handles authentication, registering, resetting passwords, forgot password,
   6   * and other user handling.
   7   *
   8   * @package WordPress
   9   */
  10  
  11  /** Make sure that the WordPress bootstrap has run before continuing. */
  12  require  __DIR__ . '/wp-load.php';
  13  
  14  // Redirect to HTTPS login if forced to use SSL.
  15  if ( force_ssl_admin() && ! is_ssl() ) {
  16      if ( str_starts_with( $_SERVER['REQUEST_URI'], 'http' ) ) {
  17          wp_safe_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
  18          exit;
  19      } else {
  20          wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  21          exit;
  22      }
  23  }
  24  
  25  /**
  26   * Outputs the login page header.
  27   *
  28   * @since 2.1.0
  29   *
  30   * @global string      $error         Login error message set by deprecated pluggable wp_login() function
  31   *                                    or plugins replacing it.
  32   * @global bool|string $interim_login Whether interim login modal is being displayed. String 'success'
  33   *                                    upon successful login.
  34   * @global string      $action        The action that brought the visitor to the login page.
  35   *
  36   * @param string|null   $title    Optional. WordPress login page title to display in the `<title>` element.
  37   *                                Defaults to 'Log In'.
  38   * @param string        $message  Optional. Message to display in header. Default empty.
  39   * @param WP_Error|null $wp_error Optional. The error to pass. Defaults to a WP_Error instance.
  40   */
  41  function login_header( $title = null, $message = '', $wp_error = null ) {
  42      global $error, $interim_login, $action;
  43  
  44      if ( null === $title ) {
  45          $title = __( 'Log In' );
  46      }
  47  
  48      // Don't index any of these forms.
  49      add_filter( 'wp_robots', 'wp_robots_sensitive_page' );
  50      add_action( 'login_head', 'wp_strict_cross_origin_referrer' );
  51  
  52      add_action( 'login_head', 'wp_login_viewport_meta' );
  53  
  54      if ( ! is_wp_error( $wp_error ) ) {
  55          $wp_error = new WP_Error();
  56      }
  57  
  58      // Shake it!
  59      $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure' );
  60      /**
  61       * Filters the error codes array for shaking the login form.
  62       *
  63       * @since 3.0.0
  64       *
  65       * @param string[] $shake_error_codes Error codes that shake the login form.
  66       */
  67      $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
  68  
  69      if ( $shake_error_codes && $wp_error->has_errors() && in_array( $wp_error->get_error_code(), $shake_error_codes, true ) ) {
  70          add_action( 'login_footer', 'wp_shake_js', 12 );
  71      }
  72  
  73      $login_title = get_bloginfo( 'name', 'display' );
  74  
  75      /* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
  76      $login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );
  77  
  78      if ( wp_is_recovery_mode() ) {
  79          /* translators: %s: Login screen title. */
  80          $login_title = sprintf( __( 'Recovery Mode &#8212; %s' ), $login_title );
  81      }
  82  
  83      /**
  84       * Filters the title tag content for login page.
  85       *
  86       * @since 4.9.0
  87       *
  88       * @param string $login_title The page title, with extra context added.
  89       * @param string $title       The original page title.
  90       */
  91      $login_title = apply_filters( 'login_title', $login_title, $title );
  92  
  93      ?><!DOCTYPE html>
  94      <html <?php language_attributes(); ?>>
  95      <head>
  96      <meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
  97      <title><?php echo $login_title; ?></title>
  98      <?php
  99  
 100      wp_enqueue_style( 'login' );
 101  
 102      /*
 103       * Remove all stored post data on logging out.
 104       * This could be added by add_action('login_head'...) like wp_shake_js(),
 105       * but maybe better if it's not removable by plugins.
 106       */
 107      if ( 'loggedout' === $wp_error->get_error_code() ) {
 108          ob_start();
 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>
 111          <?php
 112          wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
 113      }
 114  
 115      /**
 116       * Enqueues scripts and styles for the login page.
 117       *
 118       * @since 3.1.0
 119       */
 120      do_action( 'login_enqueue_scripts' );
 121  
 122      /**
 123       * Fires in the login page header after scripts are enqueued.
 124       *
 125       * @since 2.1.0
 126       */
 127      do_action( 'login_head' );
 128  
 129      $login_header_url = __( 'https://wordpress.org/' );
 130  
 131      /**
 132       * Filters link URL of the header logo above login form.
 133       *
 134       * @since 2.1.0
 135       *
 136       * @param string $login_header_url Login header logo URL.
 137       */
 138      $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
 139  
 140      $login_header_title = '';
 141  
 142      /**
 143       * Filters the title attribute of the header logo above login form.
 144       *
 145       * @since 2.1.0
 146       * @deprecated 5.2.0 Use {@see 'login_headertext'} instead.
 147       *
 148       * @param string $login_header_title Login header logo title attribute.
 149       */
 150      $login_header_title = apply_filters_deprecated(
 151          'login_headertitle',
 152          array( $login_header_title ),
 153          '5.2.0',
 154          'login_headertext',
 155          __( 'Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.' )
 156      );
 157  
 158      $login_header_text = empty( $login_header_title ) ? __( 'Powered by WordPress' ) : $login_header_title;
 159  
 160      /**
 161       * Filters the link text of the header logo above the login form.
 162       *
 163       * @since 5.2.0
 164       *
 165       * @param string $login_header_text The login header logo link text.
 166       */
 167      $login_header_text = apply_filters( 'login_headertext', $login_header_text );
 168  
 169      $classes = array( 'login-action-' . $action, 'wp-core-ui', 'admin-color-modern' );
 170  
 171      if ( is_rtl() ) {
 172          $classes[] = 'rtl';
 173      }
 174  
 175      if ( $interim_login ) {
 176          $classes[] = 'interim-login';
 177  
 178          ?>
 179          <style>html{background-color: transparent;}</style>
 180          <?php
 181  
 182          if ( 'success' === $interim_login ) {
 183              $classes[] = 'interim-login-success';
 184          }
 185      }
 186  
 187      $classes[] = 'locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
 188  
 189      /**
 190       * Filters the login page body classes.
 191       *
 192       * @since 3.5.0
 193       *
 194       * @param string[] $classes An array of body classes.
 195       * @param string   $action  The action that brought the visitor to the login page.
 196       */
 197      $classes = apply_filters( 'login_body_class', $classes, $action );
 198  
 199      ?>
 200      </head>
 201      <body class="login no-js <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
 202      <?php
 203      wp_print_inline_script_tag( "document.body.className = document.body.className.replace('no-js','js');" );
 204      ?>
 205  
 206      <?php
 207      /**
 208       * Fires in the login page header after the body tag is opened.
 209       *
 210       * @since 4.6.0
 211       */
 212      do_action( 'login_header' );
 213      ?>
 214      <?php
 215      if ( 'confirm_admin_email' !== $action && ! empty( $title ) ) :
 216          ?>
 217          <h1 class="screen-reader-text"><?php echo $title; ?></h1>
 218          <?php
 219      endif;
 220      ?>
 221      <div id="login">
 222          <h1 role="presentation" class="wp-login-logo"><a href="<?php echo esc_url( $login_header_url ); ?>"><?php echo $login_header_text; ?></a></h1>
 223      <?php
 224      /**
 225       * Filters the message to display above the login form.
 226       *
 227       * @since 2.1.0
 228       *
 229       * @param string $message Login message text.
 230       */
 231      $message = apply_filters( 'login_message', $message );
 232  
 233      if ( ! empty( $message ) ) {
 234          echo $message . "\n";
 235      }
 236  
 237      // In case a plugin uses $error rather than the $wp_errors object.
 238      if ( ! empty( $error ) ) {
 239          $wp_error->add( 'error', $error );
 240          unset( $error );
 241      }
 242  
 243      if ( $wp_error->has_errors() ) {
 244          $error_list = array();
 245          $messages   = '';
 246  
 247          foreach ( $wp_error->get_error_codes() as $code ) {
 248              $severity = $wp_error->get_error_data( $code );
 249              foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
 250                  if ( 'message' === $severity ) {
 251                      $messages .= '<p>' . $error_message . '</p>';
 252                  } else {
 253                      $error_list[] = $error_message;
 254                  }
 255              }
 256          }
 257  
 258          if ( ! empty( $error_list ) ) {
 259              $errors = '';
 260  
 261              if ( count( $error_list ) > 1 ) {
 262                  $errors .= '<ul class="login-error-list">';
 263  
 264                  foreach ( $error_list as $item ) {
 265                      $errors .= '<li>' . $item . '</li>';
 266                  }
 267  
 268                  $errors .= '</ul>';
 269              } else {
 270                  $errors .= '<p>' . $error_list[0] . '</p>';
 271              }
 272  
 273              /**
 274               * Filters the error messages displayed above the login form.
 275               *
 276               * @since 2.1.0
 277               *
 278               * @param string $errors Login error messages.
 279               */
 280              $errors = apply_filters( 'login_errors', $errors );
 281  
 282              wp_admin_notice(
 283                  $errors,
 284                  array(
 285                      'type'           => 'error',
 286                      'id'             => 'login_error',
 287                      'paragraph_wrap' => false,
 288                  )
 289              );
 290          }
 291  
 292          if ( ! empty( $messages ) ) {
 293              /**
 294               * Filters instructional messages displayed above the login form.
 295               *
 296               * @since 2.5.0
 297               *
 298               * @param string $messages Login messages.
 299               */
 300              $messages = apply_filters( 'login_messages', $messages );
 301  
 302              wp_admin_notice(
 303                  $messages,
 304                  array(
 305                      'type'               => 'info',
 306                      'id'                 => 'login-message',
 307                      'additional_classes' => array( 'message' ),
 308                      'paragraph_wrap'     => false,
 309                  )
 310              );
 311          }
 312      }
 313  } // End of login_header().
 314  
 315  /**
 316   * Outputs the footer for the login page.
 317   *
 318   * @since 3.1.0
 319   *
 320   * @global bool|string $interim_login Whether interim login modal is being displayed. String 'success'
 321   *                                    upon successful login.
 322   *
 323   * @param string $input_id Which input to auto-focus.
 324   */
 325  function login_footer( $input_id = '' ) {
 326      global $interim_login;
 327  
 328      // Don't allow interim logins to navigate away from the page.
 329      if ( ! $interim_login ) {
 330          ?>
 331          <p id="backtoblog">
 332              <?php
 333              $html_link = sprintf(
 334                  '<a href="%s">%s</a>',
 335                  esc_url( home_url( '/' ) ),
 336                  sprintf(
 337                      /* translators: %s: Site title. */
 338                      _x( '&larr; Go to %s', 'site' ),
 339                      get_bloginfo( 'title', 'display' )
 340                  )
 341              );
 342              /**
 343               * Filters the "Go to site" link displayed in the login page footer.
 344               *
 345               * @since 5.7.0
 346               *
 347               * @param string $link HTML link to the home URL of the current site.
 348               */
 349              echo apply_filters( 'login_site_html_link', $html_link );
 350              ?>
 351          </p>
 352          <?php
 353  
 354          the_privacy_policy_link( '<div class="privacy-policy-page-link">', '</div>' );
 355      }
 356  
 357      ?>
 358      </div><?php // End of <div id="login">. ?>
 359  
 360      <?php
 361      if (
 362          ! $interim_login &&
 363          /**
 364           * Filters whether to display the Language selector on the login screen.
 365           *
 366           * @since 5.9.0
 367           *
 368           * @param bool $display Whether to display the Language selector on the login screen.
 369           */
 370          apply_filters( 'login_display_language_dropdown', true )
 371      ) {
 372          $languages = get_available_languages();
 373  
 374          if ( ! empty( $languages ) ) {
 375              ?>
 376              <div class="language-switcher">
 377                  <form id="language-switcher" method="get">
 378  
 379                      <label for="language-switcher-locales">
 380                          <span class="dashicons dashicons-translation" aria-hidden="true"></span>
 381                          <span class="screen-reader-text">
 382                              <?php
 383                              /* translators: Hidden accessibility text. */
 384                              _e( 'Language' );
 385                              ?>
 386                          </span>
 387                      </label>
 388  
 389                      <?php
 390                      $args = array(
 391                          'id'                          => 'language-switcher-locales',
 392                          'name'                        => 'wp_lang',
 393                          'selected'                    => determine_locale(),
 394                          'show_available_translations' => false,
 395                          'explicit_option_en_us'       => true,
 396                          'languages'                   => $languages,
 397                      );
 398  
 399                      /**
 400                       * Filters default arguments for the Language select input on the login screen.
 401                       *
 402                       * The arguments get passed to the wp_dropdown_languages() function.
 403                       *
 404                       * @since 5.9.0
 405                       *
 406                       * @param array $args Arguments for the Language select input on the login screen.
 407                       */
 408                      wp_dropdown_languages( apply_filters( 'login_language_dropdown_args', $args ) );
 409                      ?>
 410  
 411                      <?php if ( $interim_login ) { ?>
 412                          <input type="hidden" name="interim-login" value="1" />
 413                      <?php } ?>
 414  
 415                      <?php if ( isset( $_GET['redirect_to'] ) && '' !== $_GET['redirect_to'] ) { ?>
 416                          <input type="hidden" name="redirect_to" value="<?php echo sanitize_url( $_GET['redirect_to'] ); ?>" />
 417                      <?php } ?>
 418  
 419                      <?php if ( isset( $_GET['action'] ) && '' !== $_GET['action'] ) { ?>
 420                          <input type="hidden" name="action" value="<?php echo esc_attr( $_GET['action'] ); ?>" />
 421                      <?php } ?>
 422  
 423                          <input type="submit" class="button" value="<?php esc_attr_e( 'Change' ); ?>">
 424  
 425                      </form>
 426                  </div>
 427          <?php } ?>
 428      <?php } ?>
 429  
 430      <?php
 431  
 432      if ( ! empty( $input_id ) ) {
 433          ob_start();
 434          ?>
 435          <script>
 436          try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
 437          if(typeof wpOnload==='function')wpOnload();
 438          </script>
 439          <?php
 440          wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
 441      }
 442  
 443      /**
 444       * Fires in the login page footer.
 445       *
 446       * @since 3.1.0
 447       */
 448      do_action( 'login_footer' );
 449  
 450      ?>
 451      </body>
 452      </html>
 453      <?php
 454  }
 455  
 456  /**
 457   * Outputs the JavaScript to handle the form shaking on the login page.
 458   *
 459   * @since 3.0.0
 460   */
 461  function wp_shake_js() {
 462      wp_print_inline_script_tag( "document.querySelector('form').classList.add('shake');" );
 463  }
 464  
 465  /**
 466   * Outputs the viewport meta tag for the login page.
 467   *
 468   * @since 3.7.0
 469   */
 470  function wp_login_viewport_meta() {
 471      ?>
 472      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 473      <?php
 474  }
 475  
 476  /*
 477   * Main part.
 478   *
 479   * Check the request and redirect or display a form based on the current action.
 480   */
 481  
 482  $action = isset( $_REQUEST['action'] ) && is_string( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
 483  $errors = new WP_Error();
 484  
 485  if ( isset( $_GET['key'] ) ) {
 486      $action = 'resetpass';
 487  }
 488  
 489  if ( isset( $_GET['checkemail'] ) ) {
 490      $action = 'checkemail';
 491  }
 492  
 493  $default_actions = array(
 494      'confirm_admin_email',
 495      'postpass',
 496      'logout',
 497      'lostpassword',
 498      'retrievepassword',
 499      'resetpass',
 500      'rp',
 501      'register',
 502      'checkemail',
 503      'confirmaction',
 504      'login',
 505      WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED,
 506  );
 507  
 508  // Validate action so as to default to the login screen.
 509  if ( ! in_array( $action, $default_actions, true ) && false === has_filter( 'login_form_' . $action ) ) {
 510      $action = 'login';
 511  }
 512  
 513  nocache_headers();
 514  
 515  header( 'Content-Type: ' . get_bloginfo( 'html_type' ) . '; charset=' . get_bloginfo( 'charset' ) );
 516  
 517  if ( defined( 'RELOCATE' ) && RELOCATE ) { // Move flag is set.
 518      if ( isset( $_SERVER['PATH_INFO'] ) && ( $_SERVER['PATH_INFO'] !== $_SERVER['PHP_SELF'] ) ) {
 519          $_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] );
 520      }
 521  
 522      $url = dirname( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] ) );
 523  
 524      if ( get_option( 'siteurl' ) !== $url ) {
 525          update_option( 'siteurl', $url );
 526      }
 527  }
 528  
 529  // Set a cookie now to see if they are supported by the browser.
 530  $secure = ( 'https' === parse_url( wp_login_url(), PHP_URL_SCHEME ) );
 531  setcookie( TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN, $secure, true );
 532  
 533  if ( SITECOOKIEPATH !== COOKIEPATH ) {
 534      setcookie( TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN, $secure, true );
 535  }
 536  
 537  if ( isset( $_GET['wp_lang'] ) ) {
 538      setcookie( 'wp_lang', sanitize_text_field( $_GET['wp_lang'] ), 0, COOKIEPATH, COOKIE_DOMAIN, $secure, true );
 539  }
 540  
 541  /**
 542   * Fires when the login form is initialized.
 543   *
 544   * @since 3.2.0
 545   */
 546  do_action( 'login_init' );
 547  
 548  /**
 549   * Fires before a specified login form action.
 550   *
 551   * The dynamic portion of the hook name, `$action`, refers to the action
 552   * that brought the visitor to the login form.
 553   *
 554   * Possible hook names include:
 555   *
 556   *  - `login_form_checkemail`
 557   *  - `login_form_confirm_admin_email`
 558   *  - `login_form_confirmaction`
 559   *  - `login_form_entered_recovery_mode`
 560   *  - `login_form_login`
 561   *  - `login_form_logout`
 562   *  - `login_form_lostpassword`
 563   *  - `login_form_postpass`
 564   *  - `login_form_register`
 565   *  - `login_form_resetpass`
 566   *  - `login_form_retrievepassword`
 567   *  - `login_form_rp`
 568   *
 569   * @since 2.8.0
 570   */
 571  do_action( "login_form_{$action}" );
 572  
 573  $http_post     = ( 'POST' === $_SERVER['REQUEST_METHOD'] );
 574  $interim_login = isset( $_REQUEST['interim-login'] );
 575  
 576  /**
 577   * Filters the separator used between login form navigation links.
 578   *
 579   * @since 4.9.0
 580   *
 581   * @param string $login_link_separator The separator used between login form navigation links.
 582   */
 583  $login_link_separator = apply_filters( 'login_link_separator', ' | ' );
 584  
 585  switch ( $action ) {
 586  
 587      case 'confirm_admin_email':
 588          /*
 589           * Note that `is_user_logged_in()` will return false immediately after logging in
 590           * as the current user is not set, see wp-includes/pluggable.php.
 591           * However this action runs on a redirect after logging in.
 592           */
 593          if ( ! is_user_logged_in() ) {
 594              wp_safe_redirect( wp_login_url() );
 595              exit;
 596          }
 597  
 598          if ( ! empty( $_REQUEST['redirect_to'] ) ) {
 599              $redirect_to = $_REQUEST['redirect_to'];
 600          } else {
 601              $redirect_to = admin_url();
 602          }
 603  
 604          if ( current_user_can( 'manage_options' ) ) {
 605              $admin_email = get_option( 'admin_email' );
 606          } else {
 607              wp_safe_redirect( $redirect_to );
 608              exit;
 609          }
 610  
 611          /**
 612           * Filters the interval for dismissing the admin email confirmation screen.
 613           *
 614           * If `0` (zero) is returned, the "Remind me later" link will not be displayed.
 615           *
 616           * @since 5.3.1
 617           *
 618           * @param int $interval Interval time (in seconds). Default is 3 days.
 619           */
 620          $remind_interval = (int) apply_filters( 'admin_email_remind_interval', 3 * DAY_IN_SECONDS );
 621  
 622          if ( ! empty( $_GET['remind_me_later'] ) ) {
 623              if ( ! wp_verify_nonce( $_GET['remind_me_later'], 'remind_me_later_nonce' ) ) {
 624                  wp_safe_redirect( wp_login_url() );
 625                  exit;
 626              }
 627  
 628              if ( $remind_interval > 0 ) {
 629                  update_option( 'admin_email_lifespan', time() + $remind_interval );
 630              }
 631  
 632              $redirect_to = add_query_arg( 'admin_email_remind_later', 1, $redirect_to );
 633              wp_safe_redirect( $redirect_to );
 634              exit;
 635          }
 636  
 637          if ( ! empty( $_POST['correct-admin-email'] ) ) {
 638              if ( ! check_admin_referer( 'confirm_admin_email', 'confirm_admin_email_nonce' ) ) {
 639                  wp_safe_redirect( wp_login_url() );
 640                  exit;
 641              }
 642  
 643              /**
 644               * Filters the interval for redirecting the user to the admin email confirmation screen.
 645               *
 646               * If `0` (zero) is returned, the user will not be redirected.
 647               *
 648               * @since 5.3.0
 649               *
 650               * @param int $interval Interval time (in seconds). Default is 6 months.
 651               */
 652              $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS );
 653  
 654              if ( $admin_email_check_interval > 0 ) {
 655                  update_option( 'admin_email_lifespan', time() + $admin_email_check_interval );
 656              }
 657  
 658              wp_safe_redirect( $redirect_to );
 659              exit;
 660          }
 661  
 662          login_header( __( 'Confirm your administration email' ), '', $errors );
 663  
 664          /**
 665           * Fires before the admin email confirm form.
 666           *
 667           * @since 5.3.0
 668           *
 669           * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
 670           *                         credentials. Note that the error object may not contain any errors.
 671           */
 672          do_action( 'admin_email_confirm', $errors );
 673  
 674          ?>
 675  
 676          <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">
 677              <?php
 678              /**
 679               * Fires inside the admin-email-confirm-form form tags, before the hidden fields.
 680               *
 681               * @since 5.3.0
 682               */
 683              do_action( 'admin_email_confirm_form' );
 684  
 685              wp_nonce_field( 'confirm_admin_email', 'confirm_admin_email_nonce' );
 686  
 687              ?>
 688              <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
 689  
 690              <h1 class="admin-email__heading">
 691                  <?php _e( 'Administration email verification' ); ?>
 692              </h1>
 693              <p class="admin-email__details">
 694                  <?php _e( 'Please verify that the <strong>administration email</strong> for this website is still correct.' ); ?>
 695                  <?php
 696  
 697                  /* translators: URL to the WordPress help section about admin email. */
 698                  $admin_email_help_url = __( 'https://wordpress.org/documentation/article/settings-general-screen/#email-address' );
 699  
 700                  $accessibility_text = sprintf(
 701                      '<span class="screen-reader-text"> %s</span>',
 702                      /* translators: Hidden accessibility text. */
 703                      __( '(opens in a new tab)' )
 704                  );
 705  
 706                  printf(
 707                      '<a href="%s" target="_blank">%s%s</a>',
 708                      esc_url( $admin_email_help_url ),
 709                      __( 'Why is this important?' ),
 710                      $accessibility_text
 711                  );
 712  
 713                  ?>
 714              </p>
 715              <p class="admin-email__details">
 716                  <?php
 717  
 718                  printf(
 719                      /* translators: %s: Admin email address. */
 720                      __( 'Current administration email: %s' ),
 721                      '<strong>' . esc_html( $admin_email ) . '</strong>'
 722                  );
 723  
 724                  ?>
 725              </p>
 726              <p class="admin-email__details">
 727                  <?php _e( 'This email may be different from your personal email address.' ); ?>
 728              </p>
 729  
 730              <div class="admin-email__actions">
 731                  <div class="admin-email__actions-primary">
 732                      <?php
 733  
 734                      $change_link = admin_url( 'options-general.php' );
 735                      $change_link = add_query_arg( 'highlight', 'confirm_admin_email', $change_link );
 736  
 737                      ?>
 738                      <a class="button button-large" href="<?php echo esc_url( $change_link ); ?>"><?php _e( 'Update' ); ?></a>
 739                      <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' ); ?>" />
 740                  </div>
 741                  <?php if ( $remind_interval > 0 ) : ?>
 742                      <div class="admin-email__actions-secondary">
 743                          <?php
 744  
 745                          $remind_me_link = wp_login_url( $redirect_to );
 746                          $remind_me_link = add_query_arg(
 747                              array(
 748                                  'action'          => 'confirm_admin_email',
 749                                  'remind_me_later' => wp_create_nonce( 'remind_me_later_nonce' ),
 750                              ),
 751                              $remind_me_link
 752                          );
 753  
 754                          ?>
 755                          <a href="<?php echo esc_url( $remind_me_link ); ?>"><?php _e( 'Remind me later' ); ?></a>
 756                      </div>
 757                  <?php endif; ?>
 758              </div>
 759          </form>
 760  
 761          <?php
 762  
 763          login_footer();
 764          break;
 765  
 766      case 'postpass':
 767          $redirect_to = $_POST['redirect_to'] ?? wp_get_referer();
 768  
 769          if ( ! isset( $_POST['post_password'] ) || ! is_string( $_POST['post_password'] ) ) {
 770              wp_safe_redirect( $redirect_to );
 771              exit;
 772          }
 773  
 774          require_once  ABSPATH . WPINC . '/class-phpass.php';
 775          $hasher = new PasswordHash( 8, true );
 776  
 777          /**
 778           * Filters the life span of the post password cookie.
 779           *
 780           * By default, the cookie expires 10 days from creation. To turn this
 781           * into a session cookie, return 0.
 782           *
 783           * @since 3.7.0
 784           *
 785           * @param int $expires The expiry time, as passed to setcookie().
 786           */
 787          $expire = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
 788  
 789          if ( $redirect_to ) {
 790              $secure = ( 'https' === parse_url( $redirect_to, PHP_URL_SCHEME ) );
 791          } else {
 792              $secure = false;
 793          }
 794  
 795          setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
 796  
 797          wp_safe_redirect( $redirect_to );
 798          exit;
 799  
 800      case 'logout':
 801          check_admin_referer( 'log-out' );
 802  
 803          $user = wp_get_current_user();
 804  
 805          wp_logout();
 806  
 807          if ( ! empty( $_REQUEST['redirect_to'] ) && is_string( $_REQUEST['redirect_to'] ) ) {
 808              $redirect_to           = $_REQUEST['redirect_to'];
 809              $requested_redirect_to = $redirect_to;
 810          } else {
 811              $redirect_to = add_query_arg(
 812                  array(
 813                      'loggedout' => 'true',
 814                      'wp_lang'   => get_user_locale( $user ),
 815                  ),
 816                  wp_login_url()
 817              );
 818  
 819              $requested_redirect_to = '';
 820          }
 821  
 822          /**
 823           * Filters the log out redirect URL.
 824           *
 825           * @since 4.2.0
 826           *
 827           * @param string  $redirect_to           The redirect destination URL.
 828           * @param string  $requested_redirect_to The requested redirect destination URL passed as a parameter.
 829           * @param WP_User $user                  The WP_User object for the user that's logging out.
 830           */
 831          $redirect_to = apply_filters( 'logout_redirect', $redirect_to, $requested_redirect_to, $user );
 832  
 833          wp_safe_redirect( $redirect_to );
 834          exit;
 835  
 836      case 'lostpassword':
 837      case 'retrievepassword':
 838          if ( $http_post ) {
 839              $errors = retrieve_password();
 840  
 841              if ( ! is_wp_error( $errors ) ) {
 842                  $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
 843                  wp_safe_redirect( $redirect_to );
 844                  exit;
 845              }
 846          }
 847  
 848          if ( isset( $_GET['error'] ) ) {
 849              if ( 'invalidkey' === $_GET['error'] ) {
 850                  $errors->add( 'invalidkey', __( '<strong>Error:</strong> Your password reset link appears to be invalid. Please request a new link below.' ) );
 851              } elseif ( 'expiredkey' === $_GET['error'] ) {
 852                  $errors->add( 'expiredkey', __( '<strong>Error:</strong> Your password reset link has expired. Please request a new link below.' ) );
 853              }
 854          }
 855  
 856          $lostpassword_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
 857          /**
 858           * Filters the URL redirected to after submitting the lostpassword/retrievepassword form.
 859           *
 860           * @since 3.0.0
 861           *
 862           * @param string $lostpassword_redirect The redirect destination URL.
 863           */
 864          $redirect_to = apply_filters( 'lostpassword_redirect', $lostpassword_redirect );
 865  
 866          /**
 867           * Fires before the lost password form.
 868           *
 869           * @since 1.5.1
 870           * @since 5.1.0 Added the `$errors` parameter.
 871           *
 872           * @param WP_Error $errors A `WP_Error` object containing any errors generated by using invalid
 873           *                         credentials. Note that the error object may not contain any errors.
 874           */
 875          do_action( 'lost_password', $errors );
 876  
 877          login_header(
 878              __( 'Lost Password' ),
 879              wp_get_admin_notice(
 880                  __( 'Please enter your username or email address. You will receive an email message with instructions on how to reset your password.' ),
 881                  array(
 882                      'type'               => 'info',
 883                      'additional_classes' => array( 'message' ),
 884                  )
 885              ),
 886              $errors
 887          );
 888  
 889          $user_login = '';
 890  
 891          if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
 892              $user_login = wp_unslash( $_POST['user_login'] );
 893          }
 894  
 895          ?>
 896  
 897          <form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=lostpassword', 'login_post' ) ); ?>" method="post">
 898              <p>
 899                  <label for="user_login"><?php _e( 'Username or Email Address' ); ?></label>
 900                  <input type="text" name="user_login" id="user_login" class="input ltr" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" autocomplete="username" required="required" />
 901              </p>
 902              <?php
 903  
 904              /**
 905               * Fires inside the lostpassword form tags, before the hidden fields.
 906               *
 907               * @since 2.1.0
 908               */
 909              do_action( 'lostpassword_form' );
 910  
 911              ?>
 912              <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
 913              <p class="submit">
 914                  <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Get New Password' ); ?>" />
 915              </p>
 916          </form>
 917  
 918          <p id="nav">
 919              <a class="wp-login-log-in" href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
 920              <?php
 921  
 922              if ( get_option( 'users_can_register' ) ) {
 923                  $registration_url = sprintf( '<a class="wp-login-register" href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
 924  
 925                  echo esc_html( $login_link_separator );
 926  
 927                  /** This filter is documented in wp-includes/general-template.php */
 928                  echo apply_filters( 'register', $registration_url );
 929              }
 930  
 931              ?>
 932          </p>
 933          <?php
 934  
 935          login_footer( 'user_login' );
 936          break;
 937  
 938      case 'resetpass':
 939      case 'rp':
 940          list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
 941          $rp_cookie       = 'wp-resetpass-' . COOKIEHASH;
 942  
 943          if ( isset( $_GET['key'] ) && isset( $_GET['login'] ) ) {
 944              $value = sprintf( '%s:%s', wp_unslash( $_GET['login'] ), wp_unslash( $_GET['key'] ) );
 945              setcookie( $rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
 946  
 947              wp_safe_redirect( remove_query_arg( array( 'key', 'login' ) ) );
 948              exit;
 949          }
 950  
 951          if ( isset( $_COOKIE[ $rp_cookie ] ) && 0 < strpos( $_COOKIE[ $rp_cookie ], ':' ) ) {
 952              list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ $rp_cookie ] ), 2 );
 953  
 954              $user = check_password_reset_key( $rp_key, $rp_login );
 955  
 956              if ( isset( $_POST['pass1'] ) && ! hash_equals( $rp_key, $_POST['rp_key'] ) ) {
 957                  $user = false;
 958              }
 959          } else {
 960              $user = false;
 961          }
 962  
 963          if ( ! $user || is_wp_error( $user ) ) {
 964              setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
 965  
 966              if ( $user && $user->get_error_code() === 'expired_key' ) {
 967                  wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=expiredkey' ) );
 968              } else {
 969                  wp_redirect( site_url( 'wp-login.php?action=lostpassword&error=invalidkey' ) );
 970              }
 971  
 972              exit;
 973          }
 974  
 975          $errors = new WP_Error();
 976  
 977          // Check if password is one or all empty spaces.
 978          if ( ! empty( $_POST['pass1'] ) ) {
 979              $_POST['pass1'] = trim( $_POST['pass1'] );
 980  
 981              if ( empty( $_POST['pass1'] ) ) {
 982                  $errors->add( 'password_reset_empty_space', __( 'The password cannot be a space or all spaces.' ) );
 983              }
 984          }
 985  
 986          // Check if password fields do not match.
 987          if ( ! empty( $_POST['pass1'] ) && trim( $_POST['pass2'] ) !== $_POST['pass1'] ) {
 988              $errors->add( 'password_reset_mismatch', __( '<strong>Error:</strong> The passwords do not match.' ) );
 989          }
 990  
 991          /**
 992           * Fires before the password reset procedure is validated.
 993           *
 994           * @since 3.5.0
 995           *
 996           * @param WP_Error         $errors WP Error object.
 997           * @param WP_User|WP_Error $user   WP_User object if the login and reset key match. WP_Error object otherwise.
 998           */
 999          do_action( 'validate_password_reset', $errors, $user );
1000  
1001          if ( ( ! $errors->has_errors() ) && isset( $_POST['pass1'] ) && ! empty( $_POST['pass1'] ) ) {
1002              reset_password( $user, $_POST['pass1'] );
1003              login_header(
1004                  __( 'Password Reset' ),
1005                  wp_get_admin_notice(
1006                      __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a>',
1007                      array(
1008                          'type'               => 'info',
1009                          'additional_classes' => array( 'message', 'reset-pass' ),
1010                      )
1011                  )
1012              );
1013              login_footer();
1014              exit;
1015          }
1016  
1017          wp_enqueue_script( 'utils' );
1018          wp_enqueue_script( 'user-profile' );
1019  
1020          login_header(
1021              __( 'Reset Password' ),
1022              wp_get_admin_notice(
1023                  __( 'Enter your new password below or generate one.' ),
1024                  array(
1025                      'type'               => 'info',
1026                      'additional_classes' => array( 'message', 'reset-pass' ),
1027                  )
1028              ),
1029              $errors
1030          );
1031  
1032          ?>
1033          <form name="resetpassform" id="resetpassform" action="<?php echo esc_url( network_site_url( 'wp-login.php?action=resetpass', 'login_post' ) ); ?>" method="post" autocomplete="off">
1034              <input type="hidden" id="user_login" value="<?php echo esc_attr( $rp_login ); ?>" autocomplete="off" />
1035  
1036              <div class="user-pass1-wrap">
1037                  <p>
1038                      <label for="pass1"><?php _e( 'New password' ); ?></label>
1039                  </p>
1040  
1041                  <div class="wp-pwd">
1042                      <input type="password" name="pass1" id="pass1" class="input password-input ltr" size="24" value="" autocomplete="new-password" spellcheck="false" data-reveal="1" data-pw="<?php echo esc_attr( wp_generate_password( 16 ) ); ?>" aria-describedby="pass-strength-result" />
1043  
1044                      <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' ); ?>">
1045                          <span class="dashicons dashicons-hidden" aria-hidden="true"></span>
1046                      </button>
1047                      <div id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e( 'Strength indicator' ); ?></div>
1048                  </div>
1049                  <div class="pw-weak">
1050                      <input type="checkbox" name="pw_weak" id="pw-weak" class="pw-checkbox" />
1051                      <label for="pw-weak"><?php _e( 'Confirm use of weak password' ); ?></label>
1052                  </div>
1053              </div>
1054  
1055              <p class="user-pass2-wrap">
1056                  <label for="pass2"><?php _e( 'Confirm new password' ); ?></label>
1057                  <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="new-password" spellcheck="false" />
1058              </p>
1059  
1060              <p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
1061  
1062              <?php
1063  
1064              /**
1065               * Fires following the 'Strength indicator' meter in the user password reset form.
1066               *
1067               * @since 3.9.0
1068               *
1069               * @param WP_User $user User object of the user whose password is being reset.
1070               */
1071              do_action( 'resetpass_form', $user );
1072  
1073              ?>
1074              <input type="hidden" name="rp_key" value="<?php echo esc_attr( $rp_key ); ?>" />
1075              <p class="submit reset-pass-submit">
1076                  <button type="button" class="button wp-generate-pw hide-if-no-js skip-aria-expanded"><?php _e( 'Generate Password' ); ?></button>
1077                  <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Save Password' ); ?>" />
1078              </p>
1079          </form>
1080  
1081          <p id="nav">
1082              <a class="wp-login-log-in" href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
1083              <?php
1084  
1085              if ( get_option( 'users_can_register' ) ) {
1086                  $registration_url = sprintf( '<a class="wp-login-register" href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
1087  
1088                  echo esc_html( $login_link_separator );
1089  
1090                  /** This filter is documented in wp-includes/general-template.php */
1091                  echo apply_filters( 'register', $registration_url );
1092              }
1093  
1094              ?>
1095          </p>
1096          <?php
1097  
1098          login_footer( 'pass1' );
1099          break;
1100  
1101      case 'register':
1102          if ( is_multisite() ) {
1103              /**
1104               * Filters the Multisite sign up URL.
1105               *
1106               * @since 3.0.0
1107               *
1108               * @param string $sign_up_url The sign up URL.
1109               */
1110              wp_redirect( apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ) );
1111              exit;
1112          }
1113  
1114          if ( ! get_option( 'users_can_register' ) ) {
1115              wp_redirect( site_url( 'wp-login.php?registration=disabled' ) );
1116              exit;
1117          }
1118  
1119          $user_login = '';
1120          $user_email = '';
1121  
1122          if ( $http_post ) {
1123              if ( isset( $_POST['user_login'] ) && is_string( $_POST['user_login'] ) ) {
1124                  $user_login = wp_unslash( $_POST['user_login'] );
1125              }
1126  
1127              if ( isset( $_POST['user_email'] ) && is_string( $_POST['user_email'] ) ) {
1128                  $user_email = wp_unslash( $_POST['user_email'] );
1129              }
1130  
1131              $errors = register_new_user( $user_login, $user_email );
1132  
1133              if ( ! is_wp_error( $errors ) ) {
1134                  $redirect_to = ! empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
1135                  wp_safe_redirect( $redirect_to );
1136                  exit;
1137              }
1138          }
1139  
1140          $registration_redirect = ! empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
1141  
1142          /**
1143           * Filters the registration redirect URL.
1144           *
1145           * @since 3.0.0
1146           * @since 5.9.0 Added the `$errors` parameter.
1147           *
1148           * @param string       $registration_redirect The redirect destination URL.
1149           * @param int|WP_Error $errors                User id if registration was successful,
1150           *                                            WP_Error object otherwise.
1151           */
1152          $redirect_to = apply_filters( 'registration_redirect', $registration_redirect, $errors );
1153  
1154          login_header(
1155              __( 'Registration Form' ),
1156              wp_get_admin_notice(
1157                  __( 'Register For This Site' ),
1158                  array(
1159                      'type'               => 'info',
1160                      'additional_classes' => array( 'message', 'register' ),
1161                  )
1162              ),
1163              $errors
1164          );
1165  
1166          ?>
1167          <form name="registerform" id="registerform" action="<?php echo esc_url( site_url( 'wp-login.php?action=register', 'login_post' ) ); ?>" method="post" novalidate="novalidate">
1168              <p>
1169                  <label for="user_login"><?php _e( 'Username' ); ?></label>
1170                  <input type="text" name="user_login" id="user_login" class="input ltr" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" autocomplete="username" required="required" />
1171              </p>
1172              <p>
1173                  <label for="user_email"><?php _e( 'Email' ); ?></label>
1174                  <input type="email" name="user_email" id="user_email" class="input" value="<?php echo esc_attr( $user_email ); ?>" size="25" autocomplete="email" required="required" />
1175              </p>
1176              <?php
1177  
1178              /**
1179               * Fires following the 'Email' field in the user registration form.
1180               *
1181               * @since 2.1.0
1182               */
1183              do_action( 'register_form' );
1184  
1185              ?>
1186              <p id="reg_passmail">
1187                  <?php _e( 'Registration confirmation will be emailed to you.' ); ?>
1188              </p>
1189              <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
1190              <p class="submit">
1191                  <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Register' ); ?>" />
1192              </p>
1193          </form>
1194  
1195          <p id="nav">
1196              <a class="wp-login-log-in" href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
1197              <?php
1198  
1199              echo esc_html( $login_link_separator );
1200  
1201              $html_link = sprintf( '<a class="wp-login-lost-password" href="%s">%s</a>', esc_url( wp_lostpassword_url() ), __( 'Lost your password?' ) );
1202  
1203              /** This filter is documented in wp-login.php */
1204              echo apply_filters( 'lost_password_html_link', $html_link );
1205  
1206              ?>
1207          </p>
1208          <?php
1209  
1210          login_footer( 'user_login' );
1211          break;
1212  
1213      case 'checkemail':
1214          $redirect_to = admin_url();
1215          $errors      = new WP_Error();
1216  
1217          if ( 'confirm' === $_GET['checkemail'] ) {
1218              $errors->add(
1219                  'confirm',
1220                  sprintf(
1221                      /* translators: %s: Link to the login page. */
1222                      __( 'Check your email for the confirmation link, then visit the <a href="%s">login page</a>.' ),
1223                      wp_login_url()
1224                  ),
1225                  'message'
1226              );
1227          } elseif ( 'registered' === $_GET['checkemail'] ) {
1228              $errors->add(
1229                  'registered',
1230                  sprintf(
1231                      /* translators: %s: Link to the login page. */
1232                      __( 'Registration complete. Please check your email, then visit the <a href="%s">login page</a>.' ),
1233                      wp_login_url()
1234                  ),
1235                  'message'
1236              );
1237          }
1238  
1239          /** This action is documented in wp-login.php */
1240          $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
1241  
1242          login_header( __( 'Check your email' ), '', $errors );
1243          login_footer();
1244          break;
1245  
1246      case 'confirmaction':
1247          if ( ! isset( $_GET['request_id'] ) ) {
1248              wp_die( __( 'Missing request ID.' ) );
1249          }
1250  
1251          if ( ! isset( $_GET['confirm_key'] ) ) {
1252              wp_die( __( 'Missing confirm key.' ) );
1253          }
1254  
1255          $request_id = (int) $_GET['request_id'];
1256          $key        = sanitize_text_field( wp_unslash( $_GET['confirm_key'] ) );
1257          $result     = wp_validate_user_request_key( $request_id, $key );
1258  
1259          if ( is_wp_error( $result ) ) {
1260              wp_die( $result );
1261          }
1262  
1263          /**
1264           * Fires an action hook when the account action has been confirmed by the user.
1265           *
1266           * Using this you can assume the user has agreed to perform the action by
1267           * clicking on the link in the confirmation email.
1268           *
1269           * After firing this action hook the page will redirect to wp-login a callback
1270           * redirects or exits first.
1271           *
1272           * @since 4.9.6
1273           *
1274           * @param int $request_id Request ID.
1275           */
1276          do_action( 'user_request_action_confirmed', $request_id );
1277  
1278          $message = _wp_privacy_account_request_confirmed_message( $request_id );
1279  
1280          login_header( __( 'User action confirmed.' ), $message );
1281          login_footer();
1282          exit;
1283  
1284      case 'login':
1285      default:
1286          $secure_cookie   = '';
1287          $customize_login = isset( $_REQUEST['customize-login'] );
1288  
1289          if ( $customize_login ) {
1290              wp_enqueue_script( 'customize-base' );
1291          }
1292  
1293          // If the user wants SSL but the session is not SSL, force a secure cookie.
1294          if ( ! empty( $_POST['log'] ) && ! force_ssl_admin() ) {
1295              $user_name = sanitize_user( wp_unslash( $_POST['log'] ) );
1296              $user      = get_user_by( 'login', $user_name );
1297  
1298              if ( ! $user && strpos( $user_name, '@' ) ) {
1299                  $user = get_user_by( 'email', $user_name );
1300              }
1301  
1302              if ( $user ) {
1303                  if ( get_user_option( 'use_ssl', $user->ID ) ) {
1304                      $secure_cookie = true;
1305                      force_ssl_admin( true );
1306                  }
1307              }
1308          }
1309  
1310          if ( isset( $_REQUEST['redirect_to'] ) && is_string( $_REQUEST['redirect_to'] ) ) {
1311              $redirect_to = $_REQUEST['redirect_to'];
1312              // Redirect to HTTPS if user wants SSL.
1313              if ( $secure_cookie && str_contains( $redirect_to, 'wp-admin' ) ) {
1314                  $redirect_to = preg_replace( '|^http://|', 'https://', $redirect_to );
1315              }
1316          } else {
1317              $redirect_to = admin_url();
1318          }
1319  
1320          $reauth = ! empty( $_REQUEST['reauth'] );
1321  
1322          $user = wp_signon( array(), $secure_cookie );
1323  
1324          if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
1325              if ( headers_sent() ) {
1326                  $user = new WP_Error(
1327                      'test_cookie',
1328                      sprintf(
1329                          /* translators: 1: Browser cookie documentation URL, 2: Support forums URL. */
1330                          __( '<strong>Error:</strong> Cookies are blocked due to unexpected output. For help, please see <a href="%1$s">this documentation</a> or try the <a href="%2$s">support forums</a>.' ),
1331                          __( 'https://developer.wordpress.org/advanced-administration/wordpress/cookies/' ),
1332                          __( 'https://wordpress.org/support/forums/' )
1333                      )
1334                  );
1335              } elseif ( isset( $_POST['testcookie'] ) && empty( $_COOKIE[ TEST_COOKIE ] ) ) {
1336                  // If cookies are disabled, the user can't log in even with a valid username and password.
1337                  $user = new WP_Error(
1338                      'test_cookie',
1339                      sprintf(
1340                          /* translators: %s: Browser cookie documentation URL. */
1341                          __( '<strong>Error:</strong> Cookies are blocked or not supported by your browser. You must <a href="%s">enable cookies</a> to use WordPress.' ),
1342                          __( 'https://developer.wordpress.org/advanced-administration/wordpress/cookies/#enable-cookies-in-your-browser' )
1343                      )
1344                  );
1345              }
1346          }
1347  
1348          $requested_redirect_to = isset( $_REQUEST['redirect_to'] ) && is_string( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
1349  
1350          /**
1351           * Filters the login redirect URL.
1352           *
1353           * @since 3.0.0
1354           *
1355           * @param string           $redirect_to           The redirect destination URL.
1356           * @param string           $requested_redirect_to The requested redirect destination URL passed as a parameter.
1357           * @param WP_User|WP_Error $user                  WP_User object if login was successful, WP_Error object otherwise.
1358           */
1359          $redirect_to = apply_filters( 'login_redirect', $redirect_to, $requested_redirect_to, $user );
1360  
1361          if ( ! is_wp_error( $user ) && ! $reauth ) {
1362              if ( $interim_login ) {
1363                  $message       = '<p class="message">' . __( 'You have logged in successfully.' ) . '</p>';
1364                  $interim_login = 'success';
1365                  login_header( '', $message );
1366  
1367                  ?>
1368                  </div>
1369                  <?php
1370  
1371                  /** This action is documented in wp-login.php */
1372                  do_action( 'login_footer' );
1373  
1374                  if ( $customize_login ) {
1375                      ob_start();
1376                      ?>
1377                      <script>setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000 );</script>
1378                      <?php
1379                      wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
1380                  }
1381  
1382                  ?>
1383                  </body></html>
1384                  <?php
1385  
1386                  exit;
1387              }
1388  
1389              // Check if it is time to add a redirect to the admin email confirmation screen.
1390              if ( $user instanceof WP_User && $user->exists() && $user->has_cap( 'manage_options' ) ) {
1391                  $admin_email_lifespan = (int) get_option( 'admin_email_lifespan' );
1392  
1393                  /*
1394                   * If `0` (or anything "falsey" as it is cast to int) is returned, the user will not be redirected
1395                   * to the admin email confirmation screen.
1396                   */
1397                  /** This filter is documented in wp-login.php */
1398                  $admin_email_check_interval = (int) apply_filters( 'admin_email_check_interval', 6 * MONTH_IN_SECONDS );
1399  
1400                  if ( $admin_email_check_interval > 0 && time() > $admin_email_lifespan ) {
1401                      $redirect_to = add_query_arg(
1402                          array(
1403                              'action'  => 'confirm_admin_email',
1404                              'wp_lang' => get_user_locale( $user ),
1405                          ),
1406                          wp_login_url( $redirect_to )
1407                      );
1408                  }
1409              }
1410  
1411              if ( ( empty( $redirect_to ) || 'wp-admin/' === $redirect_to || admin_url() === $redirect_to ) ) {
1412                  // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
1413                  if ( is_multisite() && ! get_active_blog_for_user( $user->ID ) && ! is_super_admin( $user->ID ) ) {
1414                      $redirect_to = user_admin_url();
1415                  } elseif ( is_multisite() && ! $user->has_cap( 'read' ) ) {
1416                      $redirect_to = get_dashboard_url( $user->ID );
1417                  } elseif ( ! $user->has_cap( 'edit_posts' ) ) {
1418                      $redirect_to = $user->has_cap( 'read' ) ? admin_url( 'profile.php' ) : home_url();
1419                  }
1420  
1421                  wp_redirect( $redirect_to );
1422                  exit;
1423              }
1424  
1425              wp_safe_redirect( $redirect_to );
1426              exit;
1427          }
1428  
1429          $errors = $user;
1430          // Clear errors if loggedout is set.
1431          if ( ! empty( $_GET['loggedout'] ) || $reauth ) {
1432              $errors = new WP_Error();
1433          }
1434  
1435          if ( empty( $_POST ) && $errors->get_error_codes() === array( 'empty_username', 'empty_password' ) ) {
1436              $errors = new WP_Error( '', '' );
1437          }
1438  
1439          if ( $interim_login ) {
1440              if ( ! $errors->has_errors() ) {
1441                  $errors->add( 'expired', __( 'Your session has expired. Please log in to continue where you left off.' ), 'message' );
1442              }
1443          } else {
1444              // Some parts of this script use the main login form to display a message.
1445              if ( isset( $_GET['loggedout'] ) && $_GET['loggedout'] ) {
1446                  $errors->add( 'loggedout', __( 'You are now logged out.' ), 'message' );
1447              } elseif ( isset( $_GET['registration'] ) && 'disabled' === $_GET['registration'] ) {
1448                  $errors->add( 'registerdisabled', __( '<strong>Error:</strong> User registration is currently not allowed.' ) );
1449              } elseif ( str_contains( $redirect_to, 'about.php?updated' ) ) {
1450                  $errors->add( 'updated', __( '<strong>You have successfully updated WordPress!</strong> Please log back in to see what&#8217;s new.' ), 'message' );
1451              } elseif ( WP_Recovery_Mode_Link_Service::LOGIN_ACTION_ENTERED === $action ) {
1452                  $errors->add( 'enter_recovery_mode', __( 'Recovery Mode Initialized. Please log in to continue.' ), 'message' );
1453              } elseif ( isset( $_GET['redirect_to'] ) && is_string( $_GET['redirect_to'] )
1454                  && str_contains( $_GET['redirect_to'], 'wp-admin/authorize-application.php' )
1455              ) {
1456                  $query_component = wp_parse_url( $_GET['redirect_to'], PHP_URL_QUERY );
1457                  $query           = array();
1458                  if ( $query_component ) {
1459                      parse_str( $query_component, $query );
1460                  }
1461  
1462                  if ( ! empty( $query['app_name'] ) ) {
1463                      /* translators: 1: Website name, 2: Application name. */
1464                      $message = sprintf( __( 'Please log in to %1$s to authorize %2$s to connect to your account.' ), get_bloginfo( 'name', 'display' ), '<strong>' . esc_html( $query['app_name'] ) . '</strong>' );
1465                  } else {
1466                      /* translators: %s: Website name. */
1467                      $message = sprintf( __( 'Please log in to %s to proceed with authorization.' ), get_bloginfo( 'name', 'display' ) );
1468                  }
1469  
1470                  $errors->add( 'authorize_application', $message, 'message' );
1471              }
1472          }
1473  
1474          /**
1475           * Filters the login page errors.
1476           *
1477           * @since 3.6.0
1478           *
1479           * @param WP_Error $errors      WP Error object.
1480           * @param string   $redirect_to Redirect destination URL.
1481           */
1482          $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
1483  
1484          // Clear any stale cookies.
1485          if ( $reauth ) {
1486              wp_clear_auth_cookie();
1487          }
1488  
1489          // Obtain user from password reset cookie flow before clearing the cookie.
1490          $rp_cookie = 'wp-resetpass-' . COOKIEHASH;
1491          if ( isset( $_COOKIE[ $rp_cookie ] ) && is_string( $_COOKIE[ $rp_cookie ] ) ) {
1492              $user_login      = sanitize_user( strtok( wp_unslash( $_COOKIE[ $rp_cookie ] ), ':' ) );
1493              list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
1494              setcookie( $rp_cookie, ' ', time() - YEAR_IN_SECONDS, $rp_path, COOKIE_DOMAIN, is_ssl(), true );
1495          }
1496  
1497          login_header( __( 'Log In' ), '', $errors );
1498  
1499          if ( isset( $_POST['log'] ) ) {
1500              $user_login = ( 'incorrect_password' === $errors->get_error_code() || 'empty_password' === $errors->get_error_code() ) ? wp_unslash( $_POST['log'] ) : '';
1501          }
1502  
1503          $rememberme = ! empty( $_POST['rememberme'] );
1504  
1505          $aria_describedby = '';
1506          $has_errors       = $errors->has_errors();
1507  
1508          if ( $has_errors ) {
1509              $aria_describedby = ' aria-describedby="login_error"';
1510          }
1511  
1512          if ( $has_errors && 'message' === $errors->get_error_data() ) {
1513              $aria_describedby = ' aria-describedby="login-message"';
1514          }
1515  
1516          wp_enqueue_script( 'user-profile' );
1517          ?>
1518  
1519          <form name="loginform" id="loginform" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
1520              <p>
1521                  <label for="user_login"><?php _e( 'Username or Email Address' ); ?></label>
1522                  <input type="text" name="log" id="user_login"<?php echo $aria_describedby; ?> class="input ltr" value="<?php echo esc_attr( $user_login ); ?>" size="20" autocapitalize="off" autocomplete="username" required="required" />
1523              </p>
1524  
1525              <div class="user-pass-wrap">
1526                  <label for="user_pass"><?php _e( 'Password' ); ?></label>
1527                  <div class="wp-pwd">
1528                      <input type="password" name="pwd" id="user_pass"<?php echo $aria_describedby; ?> class="input password-input ltr" value="" size="20" autocomplete="current-password" spellcheck="false" required="required" />
1529                      <button type="button" class="button button-secondary wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Show password' ); ?>">
1530                          <span class="dashicons dashicons-visibility" aria-hidden="true"></span>
1531                      </button>
1532                  </div>
1533              </div>
1534              <?php
1535  
1536              /**
1537               * Fires following the 'Password' field in the login form.
1538               *
1539               * @since 2.1.0
1540               */
1541              do_action( 'login_form' );
1542  
1543              ?>
1544              <p class="forgetmenot"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked( $rememberme ); ?> /> <label for="rememberme"><?php esc_html_e( 'Remember Me' ); ?></label></p>
1545              <p class="submit">
1546                  <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e( 'Log In' ); ?>" />
1547                  <?php
1548  
1549                  if ( $interim_login ) {
1550                      ?>
1551                      <input type="hidden" name="interim-login" value="1" />
1552                      <?php
1553                  } else {
1554                      ?>
1555                      <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
1556                      <?php
1557                  }
1558  
1559                  if ( $customize_login ) {
1560                      ?>
1561                      <input type="hidden" name="customize-login" value="1" />
1562                      <?php
1563                  }
1564  
1565                  ?>
1566                  <input type="hidden" name="testcookie" value="1" />
1567              </p>
1568          </form>
1569  
1570          <?php
1571  
1572          if ( ! $interim_login ) {
1573              ?>
1574              <p id="nav">
1575                  <?php
1576  
1577                  if ( get_option( 'users_can_register' ) ) {
1578                      $registration_url = sprintf( '<a class="wp-login-register" href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) );
1579  
1580                      /** This filter is documented in wp-includes/general-template.php */
1581                      echo apply_filters( 'register', $registration_url );
1582  
1583                      echo esc_html( $login_link_separator );
1584                  }
1585  
1586                  $html_link = sprintf( '<a class="wp-login-lost-password" href="%s">%s</a>', esc_url( wp_lostpassword_url() ), __( 'Lost your password?' ) );
1587  
1588                  /**
1589                   * Filters the link that allows the user to reset the lost password.
1590                   *
1591                   * @since 6.1.0
1592                   *
1593                   * @param string $html_link HTML link to the lost password form.
1594                   */
1595                  echo apply_filters( 'lost_password_html_link', $html_link );
1596  
1597                  ?>
1598              </p>
1599              <?php
1600          }
1601  
1602          $login_script  = 'function wp_attempt_focus() {';
1603          $login_script .= 'setTimeout( function() {';
1604          $login_script .= 'try {';
1605  
1606          if ( $user_login ) {
1607              $login_script .= 'd = document.getElementById( "user_pass" ); d.value = "";';
1608          } else {
1609              $login_script .= 'd = document.getElementById( "user_login" );';
1610  
1611              if ( $errors->get_error_code() === 'invalid_username' ) {
1612                  $login_script .= 'd.value = "";';
1613              }
1614          }
1615  
1616          $login_script .= 'd.focus(); d.select();';
1617          $login_script .= '} catch( er ) {}';
1618          $login_script .= '}, 200);';
1619          $login_script .= "}\n"; // End of wp_attempt_focus().
1620  
1621          /**
1622           * Filters whether to print the call to `wp_attempt_focus()` on the login screen.
1623           *
1624           * @since 4.8.0
1625           *
1626           * @param bool $print Whether to print the function call. Default true.
1627           */
1628          if ( apply_filters( 'enable_login_autofocus', true ) && ! $error ) {
1629              $login_script .= "wp_attempt_focus();\n";
1630          }
1631  
1632          // Run `wpOnload()` if defined.
1633          $login_script .= "if ( typeof wpOnload === 'function' ) { wpOnload() }";
1634  
1635          wp_print_inline_script_tag( $login_script );
1636  
1637          if ( $interim_login ) {
1638              ob_start();
1639              ?>
1640              <script>
1641              ( function() {
1642                  try {
1643                      var i, links = document.getElementsByTagName( 'a' );
1644                      for ( i in links ) {
1645                          if ( links[i].href ) {
1646                              links[i].target = '_blank';
1647                          }
1648                      }
1649                  } catch( er ) {}
1650              }());
1651              </script>
1652              <?php
1653              wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
1654          }
1655  
1656          login_footer();
1657          break;
1658  } // End action switch.


Generated : Fri Apr 24 08:20:12 2026 Cross-referenced by PHPXref