5

I created a private page, but this page needs to be more than just available by entering a code for a page that has been listed private in the Publish settings of Visibility, so I created a page and have added an if/else statement to check if the user is logged in or not. If so, the content displays as it should, if they aren't the login form appears and the user is prompted to login which appears as it should.

The problem is, after they login using the form they are redirected to the admin page. I have added a redirect to the login page to go to the page I want but it doesn't seem to work. Am I doing the redirect incorrectly?

<?php
/*
Template Name: Minutes
*/
?>

<?php get_header(); ?>

<?php get_template_part( 'templates/content', 'nav' ); ?>  
<?php get_template_part( 'templates/content', 'breadcrumb' ); ?> 




<section class="band bottom u-full-width" style="margin-top: 2%">
    <div class="container">
        <div class="row">


<?php if (is_user_logged_in()) { ?>


<div class="ten columns" >

<h5><b>Click the Plus (+) Sign to expend the list of available minutes per section</b></h5>   

Plus more code


<?php } else {
    echo 'We are sorry, but this area is only for registered, logged in users. If you are a registered user, please use the link below to login to the site to view content not available to the general public.  If you have any questions, please contact us.';
    wp_login_form(array('redirect' => 'http://etomv2.bambergmarketing.com/meeting-minutes'));
}
?>

</div>

</div></div>
</section>

<?php get_footer(); ?>
6
  • Have you tested in a vanilla WordPress install? All too often I see a plugin/theme hijacking the login redirect with complete disregard for anything other than its own intentions. Commented May 16, 2016 at 17:07
  • I'm not sure what you mean by vanilla? I've tested this on two domains with same result, it goes to the admin page and not my redirected page. Commented May 16, 2016 at 17:47
  • As in a plain install. No plugins. Default theme. Put it this way, I just tested the redirect param with wp_login_form on a "vanilla" install and it works exactly as expected - thus it must be a rogue plugin and/or your theme. The only way to find the culprit is disable all of them, then one by one re-activate and test until it stops working again! Commented May 16, 2016 at 18:35
  • I understand. It must be in my theme, I tried disabling all my plugins and still having an issue. Any ideas where I might look in my theme to try and fix it? Thank you @TheDeadMedic Commented May 16, 2016 at 21:19
  • 1
    This is due to wp_safe_redirect in wp-login.php:840 Commented May 16, 2016 at 21:30

1 Answer 1

6

Internal happenings explained

When you look at wp_login_form(), then you will see, that the redirect argument will ask for an absolute URl. So either use admin_url() or site_url() if you want to link internally.

The action/ target of this form is not meant to be changed (unless you set echo to FALSE and use some \DOMDocument replacement or some Regex to change it in the output string):

action="' . esc_url( site_url( 'wp-login.php', 'login_post' ) ) . '" method="post"

When you then look at wp_login.php and the case : 'login'|default, you will note two things:

  1. There's a filter to adjust the redirect, which might override anything set in your arguments. Keep in mind that this might even switch depending on the user who performs the login action (typically used to redirect users of different roles to different welcome screens):

    apply_filters( 'login_redirect', $redirect_to, $requested_redirect_to, $user );
    
  2. Then the user gets checked if it is authenticated and not an erroneous object. Depending on that, if the request is not directed at the /wp-admin side of things, the following function is called:

    exit( wp_safe_redirect( $target ) );
    

…and using wp_safe_redirect() means that you can not link outside (figured that from @TheDeadMedic comment – thanks!).

Solutions

As usual in WordPress, you have options:

  1. This function is inside pluggable.php, which means you can replace it with your own function. This is not very stable (every other plugin can do the same), but it's ok if you use it on your personal site, document this is in place and fix things when there's a conflict. More info in this question and the answer by @ChipBennet on it.
  2. The better solution is to look at wp_validate_redirect() which is internally used by wp_safe_redirect() and leverage the filter that WP offers to extend the list of allowed hosts.

    // End of `wp_validate_redirect()`
    $allowed_hosts = (array) apply_filters( 
        'allowed_redirect_hosts', 
        array( $wpp['host'] ), 
        isset( $lp['host'] ) ? $lp['host'] : '' 
    );
    
    if ( 
        isset($lp['host']) 
        && ( !in_array($lp['host'], $allowed_hosts) 
        && $lp['host'] != strtolower($wpp['host'])) 
    )
        $location = $default;
    

    In your case a (mu-)plugin to allow that redirect would look like the following:

    <?php /* Plugin Name: Allow external login redirect */
    add_filter( 'allowed_redirect_hosts', function( Array $hosts, $check )
    {
        return $hosts + [ 'http://etomv2.bambergmarketing.com' ];
    }, 10, 2 );
    

    Also take a look at the second argument inside wp_safe_redirect( $target, $fallback ) that is used for wp_validate_redirect(). It is set as filter. That means, that you can redirect to another external URl in case your login fails. Or you can redirect locally to some error page (or just the current page, which is the default):

    apply_filters( 'wp_safe_redirect_fallback', admin_url(), $status )
    

The second solution is what I would use. You might also want to use it in case you are using some external OAuth provider that you need to validate users against.

Note

In case you read the docs and wonder about login_post as "scheme" in there: The site_url() function is a wrapper for get_site_url() which uses set_url_scheme() internally. There login_post, login and rpc are equal to admin, which adjusts the action properly:

$scheme = is_ssl() || force_ssl_admin() ? 'https' : 'http';
1
  • 1
    I had to remove the protocol (e.g., https://) when adding hosts to the filter allowed_redirect_hosts.
    – Leukipp
    Commented Aug 12, 2021 at 2:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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