You could do this with a low-priority authenticate filter. I’m surprised there aren’t more appropriate hooks in the login process, but I can’t see one. (There is already an example of a filter like this though: wp_authenticate_spam_check.)
If the value the filter is given is a user, that means a previous filter has accepted the username & password. We can then perform our check and then either return the user if good or an error if not:
function authenticate_reject_account_status_pending( $user, $username, $password ) {
if ( $user instanceof WP_User ) {
if ( $user[ 'account_status' ] === 'pending' ) {
return new WP_Error( 'user_is_pending',
__( 'Account is pending approval. Please contact support for help.' )
);
}
}
return $user;
}
add_filter( 'authenticate', 'authenticate_reject_account_status_pending', 999999, 3 );
I have not tested this, but the general pattern should work even if this code doesn’t. This runs before the cookie is created etc.