Front-end login via router?

Hi,

I’ve been struggling with this a lot more than i thought:

I’ve created a template called login.php and created a router statement in config.php:

'pattern' => 'user/login',
        'action'  => function() {
            $site = kirby()->site();
            $pages = $site->pages();
            $page = $pages->findOpen();
            tpl::load( kirby()->roots()->templates() . DS . 'login.php', array('site' => $site, 'pages' => $pages, 'page' => $page), false);
        }

In this template I show two fields (username / password) and a submit button. The page checks if you are logged in and shows the form if you aren’t logged in.

<form method="post" class="login-form">
    <div class="form-element mt-4">
        <input type="text" id="username" name="username" placeholder="<?php echo $page->username()->html() ?>">
   </div>
   <div class="form-element">
       <input type="password" id="password" name="password" placeholder="<?php echo $page->password()->html() ?>">
    </div>
    <div class="form-element">
        <input type="submit" name="login_frontend" value="Login" class="widget-box__button" id="login_frontend">
      </div>
 </form>

When I go to /user/login I can see the template with the two fields. When I submit the form the form submits (checked via submit() with jQuery, but I’m redirected to the error page (with user/login still in the url-bar) for some reason.

Here’s my login.php in /controllers (mostly from the Authentication solution post):

<?php
return function($site, $pages, $page) {
    // don't show the login screen to already logged in users
    if($site->user()) go('/');

    // handle the form submission
    if(r::is('post') and get('login_frontend')) {
        // fetch the user by username and run the
        // login method with the password
        if($user = $site->user(get('username')) and $user->login(get('password'))) {

            // redirect to the homepage
            // if the login was successful
            $error = false;
            go('/');

        } else {
            $error = true;
        }

    } else {
        // nothing has been submitted
        // nothing has gone wrong
        $error = false;
    }

    return array('error' => $error);

};
?>

I don’t know what to look for, or why I’m sended to the error page instead of handling the form submission. Any takers? :slight_smile: Also, is there a way to see which page Kirby is trying to get on the error page?

Instead of $pages->findOpen(), try page(). But why are you using a route anyway? Just using a controller should be enough.

I was trying to use this template without creating a page for it in the panel, that’s why I though I needed a route :slight_smile: . The change from $pages->findOpen() to page() didn’t fix it, unfortunately.

Well, then the reason is that you don’t have a page. If there is no actual page in your content directory, what should page() return? :smiley:

To use the template and controller approach, you need a content page. You could alternatively build everything with the route only, but then you won’t be able to use templates and controllers.

Well, I will just use a page then and hide it in the panel for the client via CSS. Thanks for the help :smile:

Don’t you need your route to accept both POST and GET request methods?

'pattern' => 'user/login',
        'method' => 'GET|POST',
        'action'  => function() {
            $site = kirby()->site();
            $pages = $site->pages();
            $page = $pages->findOpen();
            tpl::load( kirby()->roots()->templates() . DS . 'login.php', array('site' => $site, 'pages' => $pages, 'page' => $page), false);
        }
1 Like

Here’s a bit of untested code to get you going, using only a single route and no controllers or pages.


kirby()->routes([

    # GET|POST /user/login
    [
        'method' => 'GET|POST',
        'pattern' => 'user/login',
        'action' => function() {
            // Redirect if user is already logged in
            if (site()->user())
                go('/');
            
            if (r::is('post'))
            {
                $user = site()->user( get('username') );

                if ($user && $user->login( get('password') ))
                {
                    // successfully logged in
                    go('/');
                }

                // otherwise show the form again
                // Redirect to GET /user/login
                go('user/login');
            }
            
            // Return your regular GET /user/login template
            // tpl::load('...');
        }
    ]
]);
1 Like