The warning you are receiving is because you can’t redirect the browser to another page once you have already sent content for the current page to it.
The rest of the error tells you the exact file that is sending the content you don’t yet want. You need to either:
- ensure you run your redirect in an earlier hook, before this content has the chance to be output; or
- fix whatever is causing this content to be output so that the redirect will function as intended
In your case, the output is coming from wp-login.php
as it outputs the actual login form. This means you’re going to have to hook in before this happens.
I can see what you’ve done here, and it’s a common error: you’ve found the login_head
action referred to earlier in this function (around line 37 of wp-login.php
), and attempted to hook into it. The thing is, the code add_action( 'login_head', 'wp_no_robots' );
that you’ve seen here is actually hooking into login_head
itself; it’s not running the action.
Looking further into wp-login.php
, within this same function, we find do_action( 'login_head' );
at around line 98 (notice do_action
rather than add_action
). This is when your hooked code is actually running, which unfortunately is after the output that has already been sent by WordPress (the start of the login page).
So, we need to find ourselves an earlier hook. Because we’re redirecting, we really should go as early as possible, otherwise we might be making WordPress do a lot of work it’s just going to have to do all over again on the page we redirect to. Having a look at the Action Reference on the Codex, init
is a pretty early hook that sounds like it might meet our needs.
Excellent. Try modifying your hooked function to use init
instead of login_head
.
BUT, there’s one more step we need to take… otherwise we’re going to redirect every user on every page!
Inside your function, you need to now also check that it is the login page that is being viewed. Unfortunately WordPress doesn’t offer an is_login_page()
function, so we can do this instead with a quick statement that checks the global pagenow
variable:
if($GLOBALS["pagenow"] == "wp-login.php"){ /* do redirect here */ }
Putting all this together, you should now successfully be able to redirect away from the login page (I haven’t tested all this yet though!):
function e4_login_form_disable() {
if ( $GLOBALS['pagenow'] == 'wp-login.php' ){
if ( ! isset( $_GET['gandalf'] ) || $_GET['gandalf'] != 'thewhite' ) {
wp_redirect( home_url() );
exit;
}
}
}
add_action('init', 'e4_login_form_disable');
In regards to output buffering, yes this does technically work, but it’s definitely hacky, and you shouldn’t use it when there’s an alternative available. It’ll slow down each redirect slightly too.