pwFoo Posted May 9, 2014 Share Posted May 9, 2014 Hello, I found some code examples to build a frontend user login. I thinking about a little module/ extension for it... but after some searching I've the question what could be the best way to do it... Login and logout already buildin with the following methods $session->login() $session->logout() API pages: http://processwire.com/api/variables/user/ http://processwire.com/api/variables/session/ How to create a new user or set a password found here http://processwire.com/api/variables/user/ So I need custum methods to register a new user, update password/ profile and reset a password. The needed code could be found here at the forum https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/page-2?hl=%2Bregister+%2Bconfirm#entry50183 https://processwire.com/talk/topic/4066-activate-user-account-via-email/ https://processwire.com/talk/topic/107-custom-login/?p=11290 ... But I think it's not needed to create a new class with all methods and so duplicate/ wrap already existing functions... Should I hook into session or user to add "missing" methods? How to addHook found here: http://processwire.com/api/hooks/#add_new_method https://processwire.com/talk/topic/1186-how-do-i-extend-user/?p=10507 It's my first try to build a pw / php module... so be forgiving my stupid questions 2 Link to comment Share on other sites More sharing options...
pwFoo Posted May 10, 2014 Author Share Posted May 10, 2014 Have found my way to try it Created two modules. A "proxy class" which loads an "driver class". The proxy pass-through method calls via __call() to the selected driver. The first driver will work with local PW users. Additional drivers could use another user backend to perform frontend register, login, logout... actions . So I wrap all actions into a driver to make it changeable. Link to comment Share on other sites More sharing options...
pneumatig Posted May 19, 2014 Share Posted May 19, 2014 So, how is it going? I've started to write my own module for register/login/logout, but maybe you would like to share your solution? Though, I'm not convinced about your choice to use two modules instead of one, but on the other hand - maybe I don't understand something yet . Link to comment Share on other sites More sharing options...
pwFoo Posted May 19, 2014 Author Share Posted May 19, 2014 Modified my solution. So I need one module and a driver (first: local PW users). So backend could be changed with a new driver (for example to use forum users or ldap auth). I use forum snippets to build login / register / logout and also a user profile is planned. The PW template is used as controller and I start with default templates inside the module directory. If templates exist at PW template subfolder <MODULE NAME> that will be used. At the moment there isn't much code to share, but I'll need to build it for a own project. After base features are useable and a little code cleanup I can share it as module... 2 Link to comment Share on other sites More sharing options...
pwFoo Posted May 25, 2014 Author Share Posted May 25, 2014 Update Module FrontendUsers to handle login, logout, register and user profiles. backend related methods moved to the driver FrontendUsersPW (PW local users) so could be replaced with other user backends in the future... default templates/ views within the module directory overwrite default templates with custom code by place in templates/FrontendUsers/ (login.tpl.php, register.tpl.php) use form api and CSRF to build form fields use templateFile class to work with templates and render them ToDo optimize code add comments to code... add profile features user activation via email / activation code (https://processwire.com/talk/topic/4066-activate-user-account-via-email/) password reset via email (https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=15919) First try to build a module... work in progress 2 Link to comment Share on other sites More sharing options...
pwFoo Posted May 25, 2014 Author Share Posted May 25, 2014 Ok, link to the first lines of code... But be patient with me! I'm a newbie and without any development experience I know code have to be cleaned up and commented soon... Module tested to login, logout and register users with basic forms / templates. https://bitbucket.org/pwFoo/frontendusers/src Link to comment Share on other sites More sharing options...
pwFoo Posted June 3, 2014 Author Share Posted June 3, 2014 Yeah, I like PW api and module / hook concept Learned a lot! rebuild my (dev) module with key features: register login, logout used hooks to create a profile page after register and send a activation email profiles handled by pages (simple pages with different template) use form api and csrf token to generate form fields, but forms rendered with template files (templateFile class) Code examples to build the module found here at various forum topics. Register, login, logout and profiles working, but its not useable as is at the moment 1 Link to comment Share on other sites More sharing options...
kixe Posted September 8, 2014 Share Posted September 8, 2014 Another possible and very simple way to setup a Frontend-login: Use the ProcessLogin.module from core within a login Template. <?php /** * Frontend Login template * */ include("./head.inc"); echo = $modules->get('ProcessLogin')->execute(); include("./foot.inc"); or to prevent from redirecting with a few lines more code <?php /** * Frontend Login template * */ include("./head.inc"); //to prevent from redirecting to backend, happens anyway only if loggedIn User has permission page-edit function noRedirect($event) { $event->replace = true; $event->return = $config->urls->root; } $login = $modules->get('ProcessLogin'); $login->addHookAfter('afterLoginRedirect', null, 'noRedirect'); echo $login->execute(); include("./foot.inc"); same works with Profile after login echo $modules->get('ProcessProfile')->execute(); Don't reinvent the wheel like me very often. To customize the output look here http://processwire.com/api/hooks/ 5 Link to comment Share on other sites More sharing options...
adrian Posted September 8, 2014 Share Posted September 8, 2014 Hi kixe, Seems like a cool approach to things, but I just did a little testing and am having some issues - maybe you made some changes to your code just before posting. Firstly, you need wire('config') because it's inside a function. It can't get the root url the way you have it. $event->return = wire('config')->urls->root; Also, the redirect still happens with the code you have. If I change it to a "before" hook it doesn't redirect, but you are stuck with the "Continue" link on the page. Looking at the edit Profile option - not sure I'd want any front-end only users to have the options to change the admin theme, which will show up in that form if you have more than one installed. It won't be relevant to them and just confusing. It might seem like more work, but there are simple ways to create your own custom login and profile edit form with not too much code. I have based most of mine off this post by Ryan: https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=15919 3 Link to comment Share on other sites More sharing options...
kixe Posted September 8, 2014 Share Posted September 8, 2014 Hi Adrian, oops ... thanks for correction. I didn't tested it well. To hide the Continue and get a Logout link instead this should work if (isset($_GET['logout'])) { $session->logout(); $session->redirect($page->url); } if($user->isLoggedin()) { echo "<a href='{$page->url}?logout'>Logout</a>"; } else { echo $login->execute(); } Looking at the edit Profile option - not sure I'd want any front-end only users to have the options to change the admin theme, which will show up in that form if you have more than one installed. It won't be relevant to them and just confusing. It should be possible to set show/hide user-template-fields in the User-Profil with the Module-Settings or is this not selectable for custom admin-themes? in the example below I put some more fields to the user template.modules > Process User Profile > Settings Link to comment Share on other sites More sharing options...
adrian Posted September 8, 2014 Share Posted September 8, 2014 It should be possible to set show/hide user-template-fields in the User-Profil with the Module-Settings or is this not selectable for custom admin-themes? I haven't looked to see if it's possible or not, but I wouldn't want to hide it for admin users, just for front-end users using your profile edit approach, so not sure that option would be much help anyway. Just thinking through scenarios here - not meaning to pull apart your ideas Link to comment Share on other sites More sharing options...
pwFoo Posted September 8, 2014 Author Share Posted September 8, 2014 Good to know! Thanks! Backend plugins (like ldap, external apis,...) could be implemented via a hook... Maybe I replace my login function with that code. Because user profiles could be build with user pages (not pw own userprofiles) the final part would be extend the own register function with additional features (email activation, password reset). At the moment I use a template (without file) with username and password fields and generate a login form via form api / template to form helper module. That works fine, but with reuse the existing module I haven't care about sanitizing input and code security, because it should be updated via PW core Link to comment Share on other sites More sharing options...
pwFoo Posted September 8, 2014 Author Share Posted September 8, 2014 Custom login can be realized with few lines of code... also works fine with inline error messages. ProcessLogin doesn't show inline errors. How can this behaviour changed via form API? Link to comment Share on other sites More sharing options...
kixe Posted September 9, 2014 Share Posted September 9, 2014 This makes the messages visible. I'm not sure what login you mean but for custom login using $session->login(user,password) you'd have to code it like this: //..try{ $u = $session->login($username, $pass); if($u && $u->id){ $session->redirect("/somepage/"); }} catch(Exception $e) { echo $e->getMessage();} found here: https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=50501My post was not ready to use. Sorry. Just another approach. If I have something working well and secure I will post it here. Another way is to start from here.@Adrian: Thanks for the hint. It might seem like more work, but there are simple ways to create your own custom login and profile edit form with not too much code. I have based most of mine off this post by Ryan: https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=15919 Link to comment Share on other sites More sharing options...
pwFoo Posted September 9, 2014 Author Share Posted September 9, 2014 @Kixe Yes, $session->login and a little bit sanitizing values Works fine, but changed it for testing to use ProcessLogin instead, but login failed without error message. So my custom function is more flexible for my use case (works fine, simple to hook in and know the code *g*) Link to comment Share on other sites More sharing options...
pwFoo Posted September 10, 2014 Author Share Posted September 10, 2014 same works with Profile after login echo $modules->get('ProcessProfile')->execute(); Have to test and think about ProcessProfile vs. user page as profile... But maybe ProcessProfile is a alternative to custom user prolfile pages. Link to comment Share on other sites More sharing options...
kixe Posted September 10, 2014 Share Posted September 10, 2014 (edited) Little modification which works proper and doesn't need a hook to prevent from redirecting. Only thing which I couldn't get work is to display the Error Exception thrown by Login Throttle - Solutions welcome.complete template: <?php /** * Frontend Login template * */ include("./head.inc"); try { if($user->isLoggedin()) { if(isset($_GET['logout'])) $modules->get('ProcessLogin')->executeLogout(); // redirect user with page-edit permission to admin otherwise to root-page else echo "<a href='{$page->url}?logout'>{$user->name} logout</a>";// no redirect because module isn't called again } else { echo $modules->get('ProcessLogin')->execute(); if($notices->last()) echo '<br/><strong>'.$notices->last().'</strong>'; // error message from ProcessLogin //var_dump($session->getAll()); } } catch(Exception $e) { echo $e->getMessage(); } include("./foot.inc"); If you use echo $modules->get('ProcessProfile')->execute(); take care about setting the permissions right and give the frontend-user not page-edit role. Hide role-field and admin-template-field and maybe some others in the module settings.You should also set the validation of all fields shown in frontend very strict.Go here:fields > input > strip tagsandfields > input > patternCheck security carfully. Like Adrian I have still some doubts about this way is a save one ...But I think it is good to test in this direction. I am playing around also with process fields (like in admin template) in frontend - just for development. To have easy access to the good stuff of backend in frontend. Edited September 10, 2014 by kixe Link to comment Share on other sites More sharing options...
pwFoo Posted September 14, 2014 Author Share Posted September 14, 2014 I created a simple login / logout module UserLogin based on my new FormHelper... <?php class UserLogin extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array */ public static function getModuleInfo() { return array( 'title' => 'UserLogin', 'summary' => 'Login and logout frontend users', 'version' => '001', 'requires' => array('FormHelper'), ); } private $formSubmit = array('attr' => array('value' => 'Login')); private $formFields = array( 'username' => array( 'module' => 'InputfieldText', 'vars' => array('name' => 'username', 'label' => 'Username', 'required' => true), 'attr' => array('id+name' => 'username'), ), 'password' => array ( 'module' => 'InputfieldText', 'vars' => array('name' => 'password', 'label' => 'Password', 'required' => true), 'attr' => array('id+name' => 'password', 'type' => 'password'), ), ); public function login($redirect = null) { $fh = $this->modules->get('FormHelper'); $fh->createForm(array('formFields' => $this->formFields, 'formSubmit' => $this->formSubmit)); $process = $fh->formProcess(); if ($process) { // form ok, sanitizing and execute login process... $user = $this->sanitizer->name($process->get('username')->value); $pass = $process->get('password')->value; // Try to login and redirect after user sucessfully logged in... $login = $this->processLogin($user, $pass, $redirect); // Not rediected after tried login...? Set login error message! $error = "<p style='color:red;'>{$login}</p>"; // should be added to form as InputfieldMarkup return $error . $fh->render(); } // Show login form return $fh->render(); } public function logout($redirect = null) { $this->processLogout($redirect); } protected function ___processLogin($user, $pass, $redirect) { try { $login = $this->session->login($user, $pass); if($login && $login->id) { $this->session->redirect($redirect, false); // redirect - process stops here!!! } else { return "Login failed"; } } catch(Exception $e) { return $e->getMessage(); } } protected function ___processLogout($redirect) { $this->session->logout(); $this->session->redirect($redirect, false); } } Example usage (template code for /user page, URL segments activated)... <?php $fu = $modules->get('UserLogin'); if ($user->isGuest()) { $output = $fu->login("{$config->urls->root}/user"); } elseif ($input->urlSegment1 === 'logout') { $fu->logout("{$config->urls->root}/user"); } else { $output = "Username: {$user->name}<br /><a href='{$config->urls->root}/user/logout'>Logout</a><br />"; } echo '<html><head>'; // outpunt needed scripts for inputfield modules, ... foreach ($config->scripts as $file) { echo "<script type='text/javascript' src='$file'></script>\n"; } foreach ($config->styles as $file) { echo "<link type='text/css' href='$file' rel='stylesheet' />\n"; } echo '</head><body>'; echo $output; echo '</body></html>'; Extensions and improvements planned... Link to comment Share on other sites More sharing options...
pwFoo Posted September 24, 2014 Author Share Posted September 24, 2014 Simple ProcessForgotPassword (core module) integration done. "Forgot password?" link added as form field after login form password field if ForgotPassword module is installed. 3 Link to comment Share on other sites More sharing options...
pwFoo Posted September 26, 2014 Author Share Posted September 26, 2014 First public repo of UserLogin module (dev! unstable!) based on my FormHelper module. https://bitbucket.org/pwFoo/userlogin/src/02d405031f26c1d55b08db93f23eae8ca144ecc2/UserLogin/UserLogin.module?at=master Demo usage see readme file. Basic features are login and logout. If ProcessForgotPassword core module is installed the link is added to login form. 1 Link to comment Share on other sites More sharing options...
pwFoo Posted October 8, 2014 Author Share Posted October 8, 2014 At the moment I'm thinking about a correct module name... I split up the module into login & logout register profile (no code yet) Possible addons / plugins like RegisterEmailActivation, ForgotPassword (simple integration with ProcessForgotPassword core module), ... are planned. I renamed the modules to UserFrontendLogin, UserFrontendRegister and UserFrontendProfile and with a own sub directory inside a folder UserFrontend. So it's possible to extend the module collection with plugins and additional functionalities. (also changed Repo: https://bitbucket.org/pwFoo/userfrontend) modules/UserFrontend/ /UserFrontendLogin/UserFrontendLogin.module /UserFrontendRegister/UserFrontendRegister.module /UserFrontendProfile/UserFrontendProfile.module But how should the module collection named? UserFrontend? FrontendUsers? User? ... ? Any suggestions? UPDATE UserFrontendProfile initial commit. Edit profile based on ProcessProfile core module. Profile information / fields will be based on (hidden system) user template. Link to comment Share on other sites More sharing options...
pwFoo Posted October 18, 2014 Author Share Posted October 18, 2014 First dev release FrontendUserLogin FrontendUserRegister will be the next one... 1 Link to comment Share on other sites More sharing options...
Sradesign Posted November 4, 2015 Share Posted November 4, 2015 Hi how we can change the markup of specific field in forms ? for example I want to create something like this with my login form. http://www.keenthemes.com/preview/metronic/theme/admin_6/page_user_login_5.html I can change the wrapper for the form but it do it for all the fields in simple word is there anyway to have our own custom markup for the form ? Link to comment Share on other sites More sharing options...
pwFoo Posted November 4, 2015 Author Share Posted November 4, 2015 FrontendUser module is based on PW form api. Here I linked two topics about form api. https://processwire.com/talk/topic/9811-frontenduser-login-logout-and-register-users-members/?p=102535 You should find some more topics about form api here in the forum. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now