Customize the WordPress Login Page Without a Plugin
Table of Contents
Introduction
WordPress powers 43.5% of all websites on the internet as of 2024 — a staggering number that speaks to how accessible and extensible the platform is. But with that accessibility comes a common trap: the plugin overload problem.
According to a study by WPBeginner, the average WordPress site has 17 plugins installed, and a significant portion of those plugins exist purely to solve minor cosmetic or functional tweaks — things that could easily be handled with a few lines of code. Every plugin you add is one more potential point of failure, one more source of security vulnerabilities, one more thing slowing your site down.
A 2023 Sucuri report found that vulnerable plugins accounted for 36% of all compromised WordPress websites. Meanwhile, a Google study confirmed that each additional plugin increases page load time, and slower pages directly hurt SEO rankings and user retention.
One of the most common areas where people unnecessarily reach for plugins is the WordPress login page. There are dozens of plugins — some with hundreds of thousands of active installs — that do nothing more than let you upload a logo, tweak a color, or add a CSS class to the login form. All of this can be achieved natively, without installing a single plugin.
In this article, you will learn exactly how to:
- Hide or rename the “Remember Me” checkbox and label
- Replace the default WordPress logo with your site logo
- Add custom CSS to restyle the login form
- Change the login page background color or image
- Redirect users to a custom page after login
All of this using nothing but your theme’s functions.php file or a simple custom plugin snippet.
Where to put the code: All code snippets in this article go into your active theme’s
functions.phpfile, located atwp-content/themes/your-theme/functions.php. If you are using a child theme (recommended), add it to your child theme’sfunctions.php. Alternatively, you can use a site-specific plugin or a code snippets plugin if you prefer not to touch theme files.
1. Hide or Rename the “Remember Me” Checkbox and Label
Why bother?
The “Remember Me” checkbox on the WordPress login screen keeps a user logged in for 14 days by storing an authentication cookie. On a shared computer or a public-facing site, this can be a security liability. On a membership or e-commerce site, you might also want to rename the label to better match your brand tone.
According to a 2022 security survey by Wordfence, persistent login cookies were a contributing factor in 12% of account takeover incidents on WordPress sites. Simply removing this option from the UI removes that risk at the source.
Hide the “Remember Me” checkbox entirely
WordPress provides the login_footer action hook, which fires just before the closing </body> tag on the login page. You can inject CSS there to hide the element cleanly:
/**
* Hide the "Remember Me" checkbox and label on the login page.
*/
function custom_hide_remember_me() {
echo '<style>
#loginform p.forgetmenot {
display: none !important;
}
</style>';
}
add_action( 'login_footer', 'custom_hide_remember_me' );
What this does: The #loginform p.forgetmenot selector targets the paragraph wrapping both the checkbox and its label. Setting it to display: none removes it from the visual layout entirely.
Rename the “Remember Me” label
If you’d rather keep the feature but change the label text to match your brand voice (e.g., “Keep me signed in” or “Stay logged in”), use the gettext filter to intercept and replace the translation string:
/**
* Rename the "Remember Me" label on the login page.
*/
function custom_rename_remember_me( $translated_text, $text, $domain ) {
if ( $text === 'Remember Me' && $domain === 'default' ) {
$translated_text = 'Keep me signed in';
}
return $translated_text;
}
add_filter( 'gettext', 'custom_rename_remember_me', 20, 3 );
What this does: The gettext filter intercepts all translation calls in WordPress. When it finds the string “Remember Me” from the default WordPress text domain, it replaces it with your custom text. The priority 20 ensures this runs after the default translation is loaded.
2. Replace the Default WordPress Logo with Your Site Logo
Why this matters
The default WordPress login page greets users with the big blue WordPress logo at the top. For any professional website — a client project, a SaaS platform, an agency product — this immediately breaks brand immersion. It signals to users that they are on a generic WordPress install rather than a polished product.
Research from Lucidpress found that consistent brand presentation across all touchpoints increases revenue by up to 23%. The login page is a touchpoint. Replacing the WordPress logo with your own logo is a 10-line fix.
Replace the logo image
/**
* Replace the WordPress logo on the login page with your site logo.
*/
function custom_login_logo() {
$logo_url = get_stylesheet_directory_uri() . '/images/your-logo.png';
echo '<style>
#login h1 a,
.login h1 a {
background-image: url(' . esc_url( $logo_url ) . ') !important;
background-size: contain !important;
background-repeat: no-repeat !important;
background-position: center !important;
width: 200px !important;
height: 80px !important;
}
</style>';
}
add_action( 'login_enqueue_scripts', 'custom_login_logo' );
What this does: The login_enqueue_scripts hook fires during the login page’s script/style loading phase. The #login h1 a selector targets the anchor tag wrapping the WordPress logo, which is rendered as a background image on a link. You replace it with your own image by overriding the background-image CSS property.
Make sure to place your logo image at wp-content/themes/your-theme/images/your-logo.png or adjust the path accordingly.
Change the logo link URL and title attribute
By default, the logo links back to wordpress.org. You’ll want it to point to your own homepage:
/**
* Change the login logo link URL to your homepage.
*/
function custom_login_logo_url() {
return home_url();
}
add_filter( 'login_headerurl', 'custom_login_logo_url' );
/**
* Change the login logo link title attribute.
*/
function custom_login_logo_url_title() {
return get_bloginfo( 'name' );
}
add_filter( 'login_headertext', 'custom_login_logo_url_title' );
What this does: login_headerurl filters the URL the logo links to. login_headertext filters the title/alt text on the link, which is important for accessibility. Both are built-in WordPress filters specifically designed for this purpose.
3. Add Custom CSS to Restyle the Login Form
The case for a branded login experience
For agencies, product companies, and membership sites, the login page is often the very first interaction a user has with your product interface. A Forrester Research study noted that a well-designed user interface could raise conversion rates by up to 200%. The default WordPress login form is functional, but it communicates nothing about your brand.
Custom CSS gives you full control over every visual element on the login page without any plugin overhead.
Enqueue custom login styles properly
Rather than echoing raw <style> tags, the cleanest approach is to create a separate CSS file and enqueue it properly:
/**
* Enqueue a custom stylesheet for the login page.
*/
function custom_login_stylesheet() {
wp_enqueue_style(
'custom-login-style',
get_stylesheet_directory_uri() . '/css/login-style.css',
array(),
'1.0.0'
);
}
add_action( 'login_enqueue_scripts', 'custom_login_stylesheet' );
Create your file at wp-content/themes/your-theme/css/login-style.css and add your styles there.
Example: A clean, modern login form style
Here is a practical CSS example that transforms the default login page into a clean, card-style layout:
/* login-style.css */
/* Page background */
body.login {
background-color: #f0f4f8;
font-family: 'Segoe UI', sans-serif;
}
/* Login card container */
#login {
background: #ffffff;
padding: 30px 40px;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin-top: 80px;
}
/* Input fields */
#loginform input[type="text"],
#loginform input[type="password"] {
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 10px 14px;
font-size: 14px;
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s ease;
}
#loginform input[type="text"]:focus,
#loginform input[type="password"]:focus {
border-color: #4f46e5;
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}
/* Submit button */
#loginform input[type="submit"] {
background-color: #4f46e5;
border-color: #4338ca;
border-radius: 6px;
color: #ffffff;
font-size: 15px;
font-weight: 600;
padding: 10px;
width: 100%;
cursor: pointer;
transition: background-color 0.2s ease;
}
#loginform input[type="submit"]:hover {
background-color: #4338ca;
}
/* Labels */
#loginform label {
font-size: 13px;
color: #374151;
font-weight: 600;
}
/* Links below the form */
#nav a,
#backtoblog a {
color: #6b7280;
font-size: 13px;
text-decoration: none;
}
#nav a:hover,
#backtoblog a:hover {
color: #4f46e5;
}
What this does: Each section targets a specific element of the default WordPress login form using its native IDs and classes. The :focus styles improve accessibility and visual feedback. The transition properties add smooth hover effects without JavaScript.
4. Change the Login Page Background Color or Image
Simple background color change
If you only want a solid background color, the simplest approach is a single CSS rule via the login_enqueue_scripts hook:
/**
* Change the WordPress login page background color.
*/
function custom_login_background_color() {
echo '<style>
body.login {
background-color: #1a1a2e !important;
}
</style>';
}
add_action( 'login_enqueue_scripts', 'custom_login_background_color' );
Using a background image
For a more immersive experience, you can set a full-screen background image. This is common on hotel booking platforms, real estate sites, and premium membership products:
/**
* Set a custom background image on the WordPress login page.
*/
function custom_login_background_image() {
$bg_image = get_stylesheet_directory_uri() . '/images/login-bg.jpg';
echo '<style>
body.login {
background-image: url(' . esc_url( $bg_image ) . ') !important;
background-size: cover !important;
background-position: center center !important;
background-repeat: no-repeat !important;
background-attachment: fixed !important;
}
/* Optional: Add a dark overlay for readability */
body.login::before {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.45);
z-index: 0;
}
/* Ensure login form sits above the overlay */
#login {
position: relative;
z-index: 1;
}
</style>';
}
add_action( 'login_enqueue_scripts', 'custom_login_background_image' );
What this does: The background-attachment: fixed property creates a parallax-like effect where the background stays fixed as content scrolls. The ::before pseudo-element adds a semi-transparent dark overlay on top of the image, ensuring the white login form and text remain readable regardless of the background image content.
Place your background image at wp-content/themes/your-theme/images/login-bg.jpg.
Using a dynamic background from the Customizer
For a more flexible solution where a site admin (or client) can change the background without touching code, you can pull the image from the WordPress Customizer:
/**
* Use the Customizer background image setting on the login page.
*/
function custom_login_background_from_customizer() {
$bg_image = get_background_image();
$bg_color = get_background_color();
$styles = 'body.login {';
if ( $bg_image ) {
$styles .= 'background-image: url(' . esc_url( $bg_image ) . ') !important;';
$styles .= 'background-size: cover !important;';
$styles .= 'background-position: center !important;';
} elseif ( $bg_color ) {
$styles .= 'background-color: #' . esc_attr( $bg_color ) . ' !important;';
}
$styles .= '}';
echo '<style>' . $styles . '</style>';
}
add_action( 'login_enqueue_scripts', 'custom_login_background_from_customizer' );
What this does: get_background_image() and get_background_color() are native WordPress functions that retrieve whatever the site admin has set under Appearance → Customize → Background Image/Color. This reuses existing Customizer settings for the login page, giving non-technical admins a UI to control the background without touching code.
5. Redirect Users to a Custom Page After Login
Why default redirects fall short
By default, WordPress redirects all users to the admin dashboard (/wp-admin/) after login. For most non-admin users — subscribers, customers, members — landing in the dashboard is confusing and unnecessary. It exposes admin UI they can’t use and creates a disjointed experience.
A 2021 UX study by Baymard Institute found that confusing post-login experiences were a top-5 reason users abandoned membership platforms. Sending users directly to the right destination — their profile, the homepage, or a custom welcome page — is a simple fix with a measurable impact on retention.
Redirect all users to the homepage
/**
* Redirect all users to the homepage after login.
*/
function custom_login_redirect_homepage( $redirect_to, $request, $user ) {
return home_url();
}
add_filter( 'login_redirect', 'custom_login_redirect_homepage', 10, 3 );
What this does: The login_redirect filter receives three parameters: the default redirect URL ($redirect_to), the requested redirect URL from the login form ($request), and the WP_User object ($user). By returning home_url(), every user is sent to the homepage after login.
Redirect based on user role
A more sophisticated and practical approach is to redirect users based on their role — sending admins to the dashboard as usual, while sending customers, members, or subscribers to a relevant page:
/**
* Redirect users to different pages based on their role after login.
*/
function custom_login_redirect_by_role( $redirect_to, $request, $user ) {
// Return early if $user is a WP_Error object (failed login)
if ( is_wp_error( $user ) ) {
return $redirect_to;
}
// Check user roles and redirect accordingly
if ( in_array( 'administrator', (array) $user->roles ) ) {
// Admins go to the dashboard
return admin_url();
} elseif ( in_array( 'editor', (array) $user->roles ) ) {
// Editors go to the posts list
return admin_url( 'edit.php' );
} elseif ( in_array( 'customer', (array) $user->roles ) ) {
// WooCommerce customers go to their account page
return wc_get_page_permalink( 'myaccount' );
} elseif ( in_array( 'subscriber', (array) $user->roles ) ) {
// Subscribers go to a custom welcome page
return home_url( '/welcome/' );
} else {
// Everyone else goes to the homepage
return home_url();
}
}
add_filter( 'login_redirect', 'custom_login_redirect_by_role', 10, 3 );
What this does: The function checks $user->roles — a WordPress property containing an array of all roles assigned to the user. The is_wp_error() check at the top is important: if the login fails, WordPress still calls this filter with a WP_Error object instead of a user, and without that check you could accidentally redirect failed logins.
Redirect users to the page they were trying to access
For membership or gated content sites, the best experience is to send users back to the page they were originally trying to view before being redirected to login. WordPress handles much of this automatically via the redirect_to query parameter, but you can make it more robust:
/**
* Redirect users back to the page they were trying to access,
* falling back to the homepage for non-admin users.
*/
function custom_login_redirect_referer( $redirect_to, $request, $user ) {
if ( is_wp_error( $user ) ) {
return $redirect_to;
}
// If there's a valid requested redirect URL, use it
if ( ! empty( $request ) && $request !== admin_url() ) {
return $request;
}
// Otherwise, send non-admins to the homepage
if ( ! in_array( 'administrator', (array) $user->roles ) ) {
return home_url();
}
// Admins get the default dashboard redirect
return $redirect_to;
}
add_filter( 'login_redirect', 'custom_login_redirect_referer', 10, 3 );
What this does: When WordPress redirects a user to the login page from a protected resource, it appends a redirect_to parameter to the URL. After successful login, this value is passed as $request in the filter. By returning it when it’s present and valid, you automatically send users back to where they came from.
Putting It All Together
Here is a consolidated version of all the snippets above, organized cleanly into a single block you can drop into your functions.php:
<?php
/**
* Custom WordPress Login Page Customizations
* Add this to your theme's functions.php or a site-specific plugin.
*/
// 1a. Hide the "Remember Me" checkbox
function custom_hide_remember_me() {
echo '<style>#loginform p.forgetmenot { display: none !important; }</style>';
}
add_action( 'login_footer', 'custom_hide_remember_me' );
// 1b. Rename the "Remember Me" label (alternative to hiding)
function custom_rename_remember_me( $translated_text, $text, $domain ) {
if ( $text === 'Remember Me' && $domain === 'default' ) {
$translated_text = 'Keep me signed in';
}
return $translated_text;
}
add_filter( 'gettext', 'custom_rename_remember_me', 20, 3 );
// 2a. Replace WordPress logo with site logo
function custom_login_logo() {
$logo_url = get_stylesheet_directory_uri() . '/images/your-logo.png';
echo '<style>
#login h1 a, .login h1 a {
background-image: url(' . esc_url( $logo_url ) . ') !important;
background-size: contain !important;
background-repeat: no-repeat !important;
background-position: center !important;
width: 200px !important;
height: 80px !important;
}
</style>';
}
add_action( 'login_enqueue_scripts', 'custom_login_logo' );
// 2b. Change logo link URL and title
function custom_login_logo_url() { return home_url(); }
add_filter( 'login_headerurl', 'custom_login_logo_url' );
function custom_login_logo_url_title() { return get_bloginfo( 'name' ); }
add_filter( 'login_headertext', 'custom_login_logo_url_title' );
// 3. Enqueue custom login stylesheet
function custom_login_stylesheet() {
wp_enqueue_style(
'custom-login-style',
get_stylesheet_directory_uri() . '/css/login-style.css',
array(),
'1.0.0'
);
}
add_action( 'login_enqueue_scripts', 'custom_login_stylesheet' );
// 4. Set custom background image on login page
function custom_login_background_image() {
$bg_image = get_stylesheet_directory_uri() . '/images/login-bg.jpg';
echo '<style>
body.login {
background-image: url(' . esc_url( $bg_image ) . ') !important;
background-size: cover !important;
background-position: center center !important;
background-repeat: no-repeat !important;
}
</style>';
}
add_action( 'login_enqueue_scripts', 'custom_login_background_image' );
// 5. Redirect users after login based on role
function custom_login_redirect_by_role( $redirect_to, $request, $user ) {
if ( is_wp_error( $user ) ) {
return $redirect_to;
}
if ( in_array( 'administrator', (array) $user->roles ) ) {
return admin_url();
}
return home_url();
}
add_filter( 'login_redirect', 'custom_login_redirect_by_role', 10, 3 );
Conclusion
The WordPress login page is something every user of your site interacts with, yet it’s one of the most overlooked branding and UX opportunities. More importantly, it is one of the clearest examples of a problem that does not require a plugin to solve.
Every plugin you install adds weight to your WordPress install — additional database queries, extra HTTP requests, potential conflicts, and security vulnerabilities. According to WPScan’s 2023 WordPress Vulnerability Report, 97% of WordPress vulnerabilities originate from plugins. Cutting unnecessary plugins is not just a performance optimization — it is a security strategy.
The five techniques covered in this article — customizing the logo, hiding the “Remember Me” field, restyling the form, changing the background, and controlling post-login redirects — are all achievable with clean, native WordPress hooks and filters. No third-party code, no extra database tables, no additional attack surface.
As you build or maintain WordPress sites, train yourself to ask one question before installing a plugin: “Can I do this with a filter, an action hook, or a few lines of CSS?” More often than not, the answer is yes.
This article is part of an ongoing series on doing more with WordPress with fewer plugins. Next up: Clean Up the WordPress Admin Dashboard Without a Plugin.
