1

Update: This question was initially about how to log a user out without confirmation, but from a "pretty" URL without a logout nonce. However, in retrospect I realize this is a security issue that goes against the entire reason WordPress requires a nonce to log out in the first place, so I've updated both the question and the answer to show a better way of implementing a smooth logout without any overt "wp" strings in the link.


I would like to add a menu item that logs the user out without asking for confirmation. To this end, I have attempted to create a redirection to the actual logout URL with a proper WordPress nonce added to bypass the user confirmation page, like so:

/**
 * Adds a nonce to a bare logout link in a menu,
 * presented in the form of a GET query (the "t" is for "token")
 */
add_filter('wp_nav_menu_objects', function($sorted_menu_items) {
    foreach ($sorted_menu_items as $item)
        if (preg_match('#^/logout/?$#', $item->url) === 1)
            $item->url .= '?t='.wp_create_nonce();
    return $sorted_menu_items;
});

/**
 * Redirects the user to the real logout page
 * & bypasses confirmation by using the previously-
 * added nonce/token
 */
add_action('template_redirect', function() {
    if (empty($_SERVER['REQUEST_URI'])) return;
    
    $uri = $_SERVER['REQUEST_URI'];
    
    if (preg_match('#^/logout/?\?t=([0-9A-Fa-f]+)#', $uri, $matches) === 1) {
        wp_redirect(home_url(
            '/wp-login.php?action=logout&redirect_to=%2F&_wpnonce='.$matches[1]
        ), 302);
        exit;
    }
})

This does succeed in redirecting the user to the logout page with nonce added. However, the presence of the nonce doesn't actually stop the confirmation page from appearing! In fact, on the confirmation page itself, the final logout link has its own separate nonce.

1 Answer 1

0

You can use wp_logout_url() function for logout link. It will automatically add nonce to the url.

Try this code:

add_action('template_redirect', function() {
    if (empty($_SERVER['REQUEST_URI'])) return;

    $uri = $_SERVER['REQUEST_URI'];

    if (preg_match('#^/log-out/?$#', $uri, $matches) === 1) {
        $logout_url = str_replace('&', '&', wp_logout_url());
        wp_safe_redirect($logout_url);
        die;
    }
});

If you do not want to use wp_logout_url(), then try to create nonce with 'log-out' string as this wp_create_nonce('log-out')

Updated code:

add_action('template_redirect', function() {
    if (empty($_SERVER['REQUEST_URI'])) return;

    $uri = $_SERVER['REQUEST_URI'];

    if (preg_match('#^/log-out/?$#', $uri, $matches) === 1) {
        wp_redirect(home_url(
            '/wp-login.php?action=logout&redirect_to=%2F&_wpnonce='.wp_create_nonce('log-out')
        ), 302);
        exit;
    }
});
3
  • I've been deliberately avoiding wp_logout_url() because it automatically encodes the URL for HTML output, and although that can be fixed with str_replace() as you did in your example, it's a bit of a pointless step IMO and I'd rather avoid it if possible. Is that the only way WordPress will recognize the added nonce as valid?
    – G.S.
    Commented Dec 28, 2022 at 23:46
  • @G.S. Then try to create nonce as wp_create_nonce('log-out') in your code. It will bypass the confirmation page. - I have edited the answer.
    – Irfan
    Commented Dec 29, 2022 at 7:37
  • That appears to have worked. Thanks!
    – G.S.
    Commented Dec 29, 2022 at 16:17

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.