1

I use wp_logout_url() to output a logout link. How can I avoid displaying the confirmation page that appears after clicking the link?

<a href="<?= wp_logout_url(get_permalink()); ?>">Log out</a>

Why does this even happen? I already did some googling and it seems to have something to do with a missing nonce but in my case the nonce isn't missing at all. wp_logout_url() adds the nonce to the link.

edit:

I have figured out now that if I log in with the standard WordPress /wp-admin/ login form, logging out works without the confirmation page. But if I use my own custom frontend login form that uses wp_signon(), logging out only works with the confirmation page.

Here is my login code:

add_action('after_setup_theme', 'my_login');
function my_login()
{
  if(!empty($_POST['my_username']) && !empty($_POST['my_password']))
  {
    $user = wp_signon([
      'user_login' => $_POST['my_username'],
      'user_password' => $_POST['my_password'],
      'remember' => true],
      is_ssl());
    if(is_wp_error($user))
    {
      echo $user->get_error_message();
    }
    else
    {
      wp_set_current_user($user->ID);
    }
  }
}

The form on the frontend simply is:

<form method="post" action="<?= get_permalink(); ?>">
  <p><input type="text" name="my_username" placeholder="Username" /></p>
  <p><input type="password" name="my_password" placeholder="Password" /></p>
  <p><input type="submit" name="submit" value="Login" /></p>
</form>

Am I doing something wrong here which causes this to behave differently to the normal WordPress login?

5
  • What versions of WP are you using? Did you try disabling all plugins to test? Did you try go back to default theme to test?
    – simongcc
    Apr 3, 2020 at 1:19
  • I use WordPress 5.4 and I did some tests like you suggested. I figured out that if I log in with the standard WordPress /wp-admin/ login form, logging out works without the confirmation page. But if I use my own custom frontend login form that uses wp_signon() logging out only works with the confirmation page. What could be the reason for that? I use wp_signon() in the after_setup_theme action and also do a wp_set_current_user() afterwards. Is there anything else I have to do? (Except for the annoying log out confirmation page everything seems to work fine.)
    – horace
    Apr 3, 2020 at 10:45
  • How did you do the login code? Did you use any filter? Maybe you post your custom login code here if convenient. Maybe clues lie there.
    – simongcc
    Apr 3, 2020 at 13:50
  • I have added the code to the original post. Thanks!
    – horace
    Apr 3, 2020 at 19:54
  • I have found the best solution and explanation: scratchcode.io/how-to-logout-without-confirmation-in-wordpress Dec 20, 2020 at 7:26

1 Answer 1

2

After testing and reading the codes of WordPress. Here is the explanation of the phenomenon. Firstly, the following is nonce explanation and how it is going to affect the process. According to WordPress Nonces,

A nonce is a "number used once" to help protect URLs and forms from certain types of misuse, malicious or otherwise. WordPress nonces aren't numbers, but are a hash made up of numbers and letters. Nor are they used only once, but have a limited "lifetime" after which they expire. During that time period the same nonce will be generated for a given user in a given context. The nonce for that action will remain the same for that user until that nonce life cycle has completed.

In short, it is a checking reference for security reason to ensure things are not being tampered.

Come to the login case. Your login logic is right. A form + a form handler. The process of the login:

  1. you click the login after input username password
  2. it submit itself to the same page
  3. page seems refreshed, logout link appear, logout link is generated by wp_logout_url() (default template) , inside this, nonce is being generated together, you may refer to the source code for details.
  4. because nonce is based on a few things including time reference and a cookie value. If you follow the 1-3 sequence and click logout at this time. It will ask you for confirmation page.

However, if instead try immediately, you go to the URL bar, click enter to force a loading of the page as if input a new url. Then if you click logout again. It does not ask for confirmation. It prompts confirmation box because it thinks that the logout nonce is invalid.

It is because the cookie value is not available yet with a value Null. Thus, the nonce is invalid.

Once the cookies have been set, they can be accessed on the next page load with the $_COOKIE or $HTTP_COOKIE_VARS arrays.  
                                                            ^^^^^^^^^^^^^^  

You may refer to this related post and php manual on cookie

So there is a solution that, WordPress login also uses but not documented (maybe documented but I haven't read through) that adding a "redirect" parameter to handle this. By using redirect, it will be a new page load so the cookie is updated and thus nonce is valid.

So, here is the a solution:

Login form

<form method="post" action="<?= get_permalink(); ?>">
  <p><input type="text" name="my_username" placeholder="Username" /></p>
  <p><input type="password" name="my_password" placeholder="Password" /></p>
  <p><input type="submit" name="submit" value="Login" /></p>

  <!-- change to your url -->
  <input type="hidden" name="redirect_to" value="somewhere_or_same_link" />
</form>

Form handler

add_action('after_setup_theme', 'my_login');
function my_login()
{
  if(!empty($_POST['my_username']) && !empty($_POST['my_password']))
  {
    $user = wp_signon([
      'user_login' => $_POST['my_username'],
      'user_password' => $_POST['my_password'],
      'remember' => true],
      is_ssl());


        if(is_wp_error($user))
        {
        echo $user->get_error_message();
        }
        else
        {
            if ( ! empty( $_POST['redirect_to'] ) ) {
                wp_set_current_user($user->ID);
                $redirect_to = wp_unslash( $_POST['redirect_to'] );
                wp_safe_redirect( $redirect_to );
                // or directly use wp_redirect( $redirect_to );
            }
        exit(); // it is important to exit the current script so that the redirect start a new one completely or it will remain the same, the cookie will not be refreshed
        }
    }
}
2
  • Oh! That the cookie can't be accessed before the next page load makes sense! Thank you very much for your help! Works great now!
    – horace
    Apr 4, 2020 at 21:47
  • You are welcome. Nice to know it helps. :)
    – simongcc
    Apr 11, 2020 at 0:03

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.