Sending users to wp-login.php works, but it breaks the experience on membership sites, online stores, and any project where you want to keep users within the main theme. WordPress makes it easy to render a login form on any page.
Problem: How do you display a WordPress login form on any page of your site instead of sending users to wp-login.php?
Solution: Use wp_login_form() to output a complete login form with redirect support, or build a custom form and process it with wp_signon() for full control over the markup.
The simplest approach is wp_login_form(), which outputs a complete form with all the required fields:
if ( is_user_logged_in() ) {
echo '<p>' . sprintf(
__( 'Welcome, %s. <a href="%s">Log out</a>', 'textdomain' ),
esc_html( wp_get_current_user()->display_name ),
esc_url( wp_logout_url( get_permalink() ) )
) . '</p>';
} else {
wp_login_form( [
'redirect' => home_url( '/dashboard/' ),
'remember' => true,
'value_remember' => true,
] );
}
For full control, build the form manually and process it with wp_signon():
add_action( 'init', 'handle_front_end_login' );
function handle_front_end_login() {
if ( empty( $_POST['custom_login_nonce'] ) ) return;
if ( ! wp_verify_nonce( $_POST['custom_login_nonce'], 'custom_login' ) ) return;
$user = wp_signon( [
'user_login' => sanitize_user( $_POST['log'] ),
'user_password' => $_POST['pwd'],
'remember' => ! empty( $_POST['rememberme'] ),
], is_ssl() );
if ( is_wp_error( $user ) ) {
// Store error in a transient or query var for display
return;
}
wp_safe_redirect( home_url( '/dashboard/' ) );
exit;
}
NOTE: Always verify a nonce before calling wp_signon(). Use wp_safe_redirect() (not wp_redirect()) for post-login redirects to prevent open redirect vulnerabilities. Never log the user's password.