Wordpress - 'Password field is empty' error when using autofill in Chrome

The JavaScript function wp_attempt_focus is causing this issue. The function fires shortly after page load, clears the form and focuses on it, forcing users to manually enter their login information.

Chrome is filling in the username and password automatically, just milliseconds before the JS function clears the field. Chrome does not properly pick up the changes, displaying yellow colored filled out fields even though the fields are actually empty.

Though I appreciate the autofocus functionality, I can't think of a good reason anyone would want the form to automatically clear.

The source

Sadly, the function has been hardcoded in wp-login.php in lines 913-930 (WordPress 4.0). Changing the wp-login.php file altogether is a bad idea, since it could be overwritten in any upcoming WordPress update. So we will have to resort to a bit of 'hacking'.

The easy fix

The wp_attempt_focus function is called if the form has no errors. We're in luck - the error checking is done via PHP. This means we can simply prevent the function from firing by faking a form error at the right time using WP actions. I chose the login_form action since the action always fires after error handling, right before the JS call. Add the following code to your theme's functions.php (or plugin file):

add_action("login_form", "kill_wp_attempt_focus");
function kill_wp_attempt_focus() {
    global $error;
    $error = TRUE;
}

The hackish fix

The fix above prevents the function from firing altogether, meaning you won't get proper autofocus either. There's another way around it: buffering HTML output and modifying it via ob_start, as inspired by Geeklab. Buffering allows us to remove specific portions of code - in this case, the autoclear part d.value = ''. Don't forget to flush the buffer though.

add_action("login_form", "kill_wp_attempt_focus_start");
function kill_wp_attempt_focus_start() {
    ob_start("kill_wp_attempt_focus_replace");
}

function kill_wp_attempt_focus_replace($html) {
    return preg_replace("/d.value = '';/", "", $html);
}

add_action("login_footer", "kill_wp_attempt_focus_end");
function kill_wp_attempt_focus_end() {
    ob_end_flush();
}