1

I'm working on a custom login page plugin. I'm trying to figure out how to log the user in without creating "headers already sent" errors.

I was calling wp_signon directly after the user clicked "login," but quickly found that this approach yields "headers already sent" errors. I've switched to using hooks:

private function attemptLogin() {
    add_action( 'after_setup_theme', array( $this->Cms, 'authenticateUser' ), 10, 2 );
    do_action( 'after_setup_theme', $_POST['username'], $_POST['password'] );
}

But, as you've probably guessed, this yields the same errors since I'm still, in essence, executing the login immediately.

How can I leave the hook to run on its own schedule to avoid errors, while still making the user's credentials available to it?

I've searched both Google and this site for the answer to no avail. The closest to an answer I've found is this, but I'm still unsure how to implement the advice while still passing the user's credentials.

2
+50

Upon successful login wp_signon() sets a cookie in the http response header. Hence it has to be called before any HTML output is sent to the browser. Otherwise the "headers already sent" error will occur.

After a successfull login you should redirect your user. Otherwise the login information will not present when the page HTML is rendered.

A very sketchy but working code:

// process login requests each time wordpress renders a page. 
function my_custom_login_process() {
    // check if login credentials are present in the current http request
    if ( isset( $_POST['user_login'] ) && isset( $_POST['user_password'] ) ) {
        // try login
        $user = wp_signon( $_POST );

        if ( is_wp_error($user) ) // didn't work. Tell the user.
            exit('Nope...');
        else // worked! Get him somewhere.
            wp_redirect( get_bloginfo('url') );
    }
}
add_action('after_setup_theme','my_custom_login_process');

Additionally you should protect your login form with a nonce, and add a nonce verification to the function above. The easiest way to do this is by using wp_nonce_field() in the login form.

Nonces explained

[EDIT]: A Nonce is a unique token, that gets registered along with a form. It is mainly used to make sure that a form has been generated by the Webserver, before any data is accepted for further processing. All forms in the admin area are using nonces (or at least should do).

During the login process it will provide basic protection against brute force attacks. (This means flooding your WordPress with blank POST requests containing arbitrary username / password combinations.)


(BTW: It seems like you have a little misconception on hooks. You really should not register (do_action()) and call a hook (do_action()) with arbitrary function arguments. Other plugins might also have registered their functions. This article looks like a pretty good starting point for a deeper understanding.)

  • Thank you for your thorough explanation! I'm going to try this ASAP. – Nathan GoFundMonica Arthur Sep 9 '14 at 22:20
  • Could you elaborate on why a nonce is needed? – Nathan GoFundMonica Arthur Sep 9 '14 at 22:54
  • I've successfully implemented your approach. It does seem odd, doesn't that WordPress wouldn't automatically throttle wp_signon attempts and perhaps include a lockout after x failed attempts? Anyway, thanks again for the great answer! – Nathan GoFundMonica Arthur Sep 10 '14 at 21:52
  • 1
    Thx :) As far as I can see in the source WP doesn't even count failed login attempts. Anyway there are some plugins out there, dealing with brute force attacks and other security issues. e.g. that one: wordpress.org/plugins/login-lockdown – Jörn Lund Sep 12 '14 at 9:03
  • Hmm, seems like a bit of an oversight to me. Yes, I believe I have the iThemes Security plugin set to do just that. I'll definitely work on getting my login form using nonces, too. – Nathan GoFundMonica Arthur Sep 12 '14 at 13:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.