Jump to content

Try to create a Custom Login site


doolin
 Share

Recommended Posts

Hi guys

I try to create a custom login page. So i read a lot in the forum about this, but i don't understand how i have to implement it. The login page was no problem, i use the code from ryan here:


And customize my login page. At the moment is this site my default admin page: 

/admin. 

So my first idea was..I create a new site called "login" and add my custom Login site as template to this site. This worked fine, but now i have two more problems:

First, when the user logout via the custom logout links, he gets back to the old default login site "/admin". I've tried to change this in the admin template, without success. I use the Default admin theme.

Second: The created page "login" is visible in the site tree, but it should be hidden for non admin user, so i move the "login" site below the admin site, but now the non admin user cannot access the site anymore. I also tied to customize the template access, but the site are still visible.

Can anyone explaine me a better solution for this?

Greats

Link to comment
Share on other sites

Hi doolin, I would suggest checking this post from Soma, which "corrects" ryan's original code for the custom login.

Concerning the redirection after logging out, I am assuming that you are using the link in the admin area, right? Since the admin doesn't know about your custom login page, it can't redirect to it. You need to hook into the Session::logout function to force redirection to the right login page, for example with a module:

class CustomLogout extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'Custom Logout',
      'summary' => 'Redirects to a custom login page after logout',
      'singular' => true,
      'autoload' => true
    );
  }

  public function init() {
    $this->addHookAfter('Session::logout', function($event) {
      $this->session->redirect($this->pages->get('/login/')->url);
    });
  }
}

Concerning the login page itself, it should remain accessible for non-admin users, since they need to access it to login. What you could simply do is make it non-editable by non-admin users by configuring the permissions for the login template (in the Access tab). Removing it from the page tree is somewhat of a hassle...

  • Like 3
Link to comment
Share on other sites

Hi ESRCH

Thanks for the right code.

Yes i user the link in the admin area.

Where i have to put this code? I read in the Docs i can place hooks anywhere i want with the autoload method. I add the code into the default.php in the Default admin theme, but it doesn't work?

yes i see, i can set the site as non editable, but the site are still display, but i have to hide it. Is there no easy way?

greats

Link to comment
Share on other sites

While you can put hooks anywhere, the cleanest approach is usually to create a separate module for it. In this case, the code I gave you is the code for a complete module, so here's what you should do:

  • Create a CustomLogout.module file in the /site/modules directory (you can rename the file if you want, but it must have the same name as the class that it defines).
  • Paste the code from my previous post.
  • Go to Modules > Refresh. The new module should appear, and you can click on install, to install it just like any Core module.

After doing this, the redirection should work.

To hide the login page, I would suggest using CSS to hide a specific item in the PageList. You will notice when examining the HTML generated by the PageList that each page is actually a div with (among other things) a class of "PageListID1234", where 1234 is the id of the page. So if your login page's id is 1025 for example, you could create a custom.css file (in /site/templates/styles) with the rule

.PageListID1025 { display: none !important; }

You now have to include this CSS file when showing the PageList page, but only when the user is not the superuser (or any another rule based on permissions or roles). You can try using the Admin Custom Files module and checking the different options there. I must admit that I have never used it, so I can't help you much. Otherwise, you can make a module (or include it in the above module in the init function) with this hook:

$this->addHookBefore("ProcessPageList::execute", function($event) {
  if (!$this->user->isSuperUser()) // You can change the rule here
    $this->config-styles->add($this->config->urls->templates . "styles/custom.css"); // Adapt the link to the file
})

As a final note, you can indeed add hooks (the $this->addHookAfter(...) call) more or less anywhere, but the syntax will change:

  • Within a class (such as a module as defined in the code in my previous post), the hook is called on $this, e.g., $this->addHookBefore("Page::render")
  • Outside of a class (such as in a template, or the admin.php file), the hook is called on wire(), so wire()->addHookBefore("Page::render").
  • You can also call addHook on an instance of a class, like $page->addHookBefore("render").

What you tried to do by including my entire module code in the default.php file wouldn't have worked, because the autoload looks for classes in files that have the same name as the class (so the CustomLogout class must be in the CustomLogout.module or CustomLogout.php file).

Learning about hooks requires a little effort, but once you get it, it is very logical and it really opens the door to doing whatever you want with Processwire. The hook system is really well built, and most aspects of the application can be hooked into. I would suggest the following to learn about hooks (that's what I did):

  • Like 1
Link to comment
Share on other sites

ESRCH, thank you very much for your effort and the great explanation! No, Now i understood how hooks are working and for what they are.
 
Yes, CSS, thank you. I dont know why i did not think about this. Good solution.  :)
 
Ok, i created an module according to your instructions. The module are installed now. If I Logout now, it redirects me to 
 
/admin/login/logout
 
and i get a 
 

"Internal Server Error

 
The server encountered an internal error or misconfiguration and was unable to complete your request.
 
Error has been logged."
 
There are already an site called "Login" by default from processwire. So i create a new site in "/" called "logins", and customize your code. But i still get the error?
 
I created a new module for the css hook:
 
<?php
class SiteHider extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'SiteHider',
      'summary' => 'Hide Sites in CSS per User Roles',
      'singular' => true,
      'autoload' => true
    );
  }

  public function init() {
    $this->addHookBefore("ProcessPageList::execute", function($event) {
  if (!$this->user->isSelina())
    $this->config-styles->add($this->config->urls->templates . "css/sitehide.css");
})
  }
}

 
And get this error:
 

"Parse Error: syntax error, unexpected T_OBJECT_OPERATOR (line 15..."

I also get the same error if i combine both hooks like you sayed

 
What im doing wrong? 
I have to say i've added in the first line of both modules "<?php".
Link to comment
Share on other sites

The problem is most probably the $this->user->isSelena() function. I understand the confusion, since $this->user->isSuperuser() gives the impression that you can use any user name, but it's not the case. isSuperuser() is a built-in method of the User class (you can find it on the cheatsheet under $user / User methods). If you want to allow only a specific user with the username "selina", you would do

if (!$this->user->name === 'selina')

This should hopefully do the trick.

You should also add a semi-colon after the }) on the third line from the bottom, or you'll get another error :)

  • Like 1
Link to comment
Share on other sites

I didn't realize that your post had two parts with two different questions, sorry :rolleyes:

For the logout problem, I would need to know more about the error. There normally isn't a /login page in ProcessWire from the start, so I'm surprised that this would be an issue. At the end of th error message, you can see the message that the "Error has been logged". This means that you can find this error in /site/assets/logs/errors.txt. So try doing it again, and look at the last error in the file, it should give you some indication on how to solve the issue. If not, just post the error here, as well as the exact code from the module if you adapted it.

Link to comment
Share on other sites

It's a module:
 
/**
 * ProcessWire Login Process
 *
 * Provides Login capability for ProcessWire Admin 
 * 
 * For more details about how Process modules work, please see: 
 * /wire/core/Process.php 
 * 
 * ProcessWire 2.x 
 * Copyright (C) 2014 by Ryan Cramer 
 * Licensed under GNU/GPL v2, see LICENSE.TXT
 * 
 * http://www.processwire.com
 * http://www.ryancramer.com
 *
 */

class ProcessLogin extends Process {

protected $nameField;
protected $passField; 
protected $submitField; 
protected $form; 
protected $id; 

public static function getModuleInfo() {
return array(
'title' => 'Login',          
'summary' => 'Login to ProcessWire', 
'version' => 101, 
'permanent' => true, 
'permission' => 'page-view',
);
}
.............
 
the error Log:
 

2015-03-13 09:35:54 admin http://SITE.ch/admins/module/ Parse Error:  syntax error, unexpected T_OBJECT_OPERATOR (line 15 of /is/htdocs/wp12205379_U47G28VDDD/www/SITE/site/modules/SiteHider/SiteHider.module)

2015-03-13 09:38:36 guest http://SITE.ch/admins/login/ Error:  Using $this when not in object context (line 14 of /is/htdocs/wp12205379_U47G28VDDD/www/SITE/site/modules/CustomLogout/CustomLogout.module)
Link to comment
Share on other sites

For ProcessLogin: Did you put your custom login page under the Admin page? You should avoid doing that if you want people who have not logged in to access it so that they are able to login.

I am a bit stumped with your errors. Could you please paste the exact code from the SiteHider.module and the CustomLogout.module files? Also, which version of PHP are you using?

Link to comment
Share on other sites

No. There are already an "Login" page under /admin that i never created. My created site is here /login. I tried to move the /admin/Login site to / and get an error.

CustomLogout.module



<?php
class CustomLogout extends WireData implements Module {
public static function getModuleInfo() {
return array(
'title' => 'Custom Logout',
'summary' => 'Redirects to a custom login page after logout',
'singular' => true,
'autoload' => true
);
}

public function init() {
$this->addHookAfter('Session::logout', function($event) {
$this->session->redirect($this->pages->get('/login/')->url);
});
}
}


SiteHider.module 



<?php
class SiteHider extends WireData implements Module {
public static function getModuleInfo() {
return array(
'title' => 'SiteHider',
'summary' => 'Hide Sites in CSS per User Roles',
'singular' => true,
'autoload' => true
);
}

public function init() {
$this->addHookBefore("ProcessPageList::execute", function($event) {
if (!$this->user->name === 'selina');
$this->config-styles->add($this->config->urls->templates . "css/sitehide.css")
})
}
}

I use PHP Version 5.3.29
Link to comment
Share on other sites

Hmmm... I wonder if it's the inline function. Try this code instead for each module:

<?php
class CustomLogout extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'Custom Logout',
      'summary' => 'Redirects to a custom login page after logout',
      'singular' => true,
      'autoload' => true
    );
  }

  public function init() {
    $this->addHookAfter('Session::logout', $this, 'hookAfterLogout');
  }

  public function hookAfterLogout($event) {
    $this->session->redirect($this->pages->get('/login/')->url);
  }
}
<?php
class SiteHider extends WireData implements Module {
  public static function getModuleInfo() {
    return array(
      'title' => 'SiteHider',
      'summary' => 'Hide Sites in CSS per User Roles',
      'singular' => true,
      'autoload' => true
    );
  }

  public function init() {
    $this->addHookBefore("ProcessPageList::execute", $this, 'hookBeforePageListExecute');
  }

  public function hookBeforePageListExecute($event) {
    if (!$this->user->name === 'selina')
      $this->config-styles->add($this->config->urls->templates . "css/sitehide.css");
  }
}

Also, be careful with where you put the semi-colons (;). In SiteHider, you had put it just after the if, which is a problem.

  • Like 3
Link to comment
Share on other sites

Hmmm... I wonder if it's the inline function

Yep, If I remember correctly, you can't refer to "$this" in a closure. But you could use wire('session') to get the session object there.

  • Like 1
Link to comment
Share on other sites

Ok, the CustomLogout Module works fine now :)
I try to understand. The problem was, you have to define a separate function and call it. Before we try it with an event right? why that didn't work?
 
For the SiteHider i still get this error:
 
2015-03-13 21:23:02 admin http://SITE.ch/admins/module/ Parse Error: syntax error, unexpected T_OBJECT_OPERATOR (line 18 of /is/htdocs/wp12205379_U47G28VDDD/www/SITE/site/modules/SiteHider/SiteHider.module)

I'm not even can install the module, I get the error as soon i transfer the files in the /modules folder

Link to comment
Share on other sites

The problem with the CustomLogout module was that we were using an anonymous function in the hook (the function($event) {...} is an anonymous function), and according to the PHP manual (here, under Changelog), PHP version 5.3 didn't allow using $this within such anonymous functions. So we had to use the "traditional" syntax for hooks, which uses a method of the module.

The reason why the SiteHider module is called without needing to install it is probably because it wasn't uninstalled correctly the previously, so it is still in the database (if you look in the modules table in your database, you can probably find the SiteHider module). Before deleting a module from the /site/modules folder, you should always uninstall it first by clicking on its name in the modules list, selecting Uninstall and clicking Save. This will remove the module from the database.

I see that I did a typo in my code, there is a > missing: it should be $this->config->styles->add(...); Also, the line above should be

if ($this->user->name !== 'selina')

because the ! operator has a higher precedence as the === operator.

I hope that this solves the problem :)

Link to comment
Share on other sites

this is embarrassing, because i checked the code for errors but i cant see this! My "Syntax View" is not so good right now, but it gets better. Now,  I've removed the "!" from:



if (!$this->user->name === 'selina')


and now, processwire takes the selected css file! It does what it should do  :)

Very nice, thank you :)

  • Like 1
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...