Jump to content

Add last login field to user


mackenzie
 Share

Recommended Posts

Hi everyone, sorry if this is a duplicate question but I cannot seem to find the proper way to achieve what I want.

I need a way to store and retrieve the datetime of users' last login so that I can display a list of pages that have been updated since the user was last logged in. I've been trying to accomplish this with hooks but I can't figure out where to store the login date. I feel like I should be able to do this with just $user->get and $user->set, but it seems like these only hang around during the current session? Do I need to extend the User class in a module or is there another way to add a field to the User class?

Thanks in advance!

Link to comment
Share on other sites

This is how I have done it in the past:

https://processwire.com/talk/topic/5534-new-articles-to-users-with-cookie/?p=53935

Ignore the title of the first post - this option does not use cookies.

Note that this is not just about storing the last login, but rather the datetime of the last page they viewed, which may or may not be what you are looking for :)

Link to comment
Share on other sites

thanks for the fast response! Yes this was exactly what I needed to know I can just stick the 

$user->last_page_load = date('Y-m-d H:i:s'); 
$user->of(false); 
$user->save(); 

chunk in a hook. Only I'm getting an error when it tries to save. Somehow the $user variable has become a NullPage by that line but wasn't on any previous line. Also what is the second line doing?

Error: Exception: Can't save page 0: : Pages of type NullPage are not saveable (in D:\somepath\processwire\wire\core\Pages.php line 604)

thanks again

Link to comment
Share on other sites

it's in a _init.php that's set as the prependTemplateFile

wire()->addHookAfter("Session::login", function(HookEvent $event) {
	$name = $event->arguments('$name');
	$name = $this->wire('sanitizer')->username($name); 
	$person = $this->wire('users')->get("name=$name");

	$last = $person->last_login;

	$person->last_login = date('Y-m-d H:i:s');
	$person->save();
});
Link to comment
Share on other sites

I am not sure where $name is initially defined, but your:

$name = $event->arguments('$name');

doesn't look right. If you are wanting to get an event argument by name, you need something like:

$event->argumentsByName("page");

Also, this:

$person = $this->wire('users')->get("name=$name");

can be simplified to:

$person = wire('users')->get($name);
  • Like 2
Link to comment
Share on other sites

Thanks for the help, that solved the problem combined with moving the 

$person->of(false); 

to before setting the value.

The examples I'd been looking at were probably from an old version of the syntax or something. 

  • Like 1
Link to comment
Share on other sites

Take care what you put in the _init.php. it can get executed multiple time if you use to render() pages inside the templates. Every render triggers slay what you have in init. Just good to know.

  • Like 4
Link to comment
Share on other sites

  • 9 months later...

I have tried the code above, but it always stores the date and time of the present login (the current date and time) and do not shows the last login date and time.

The code is inside the user frontend profile template.

$username = $user->name;
wire()->addHookAfter("Session::login", function(HookEvent $event) {
  $person->of(false); 
	$name = $event->arguments('$username');
	$name = $this->wire('sanitizer')->username($username); 
	$person = wire('users')->get($username);
	$last = $person->last_page_load;
	$person->last_page_load = date('Y-m-d H:i:s');
	$person->save();
});

I have never worked with hooks and therefore its quite difficult to me to figure out.

What I want to achieve:

If a user logs out (or maybe logs in) then the date and time of the logout (or login) will be stored in a userfield called "last_page_load". If the user logs in the next time, the date and time of the last visit will be displayed in his user profile on the frontend.

Link to comment
Share on other sites

How often do you actually log out of a site? My point is that I am not sure how relevant last login/logout is, which is why I went with last_page_load and actually record the date/time the user last loaded a page. My example here: https://processwire.com/talk/topic/5534-new-articles-to-users-with-cookie/?p=53935 takes that approach and works well for me and it about as close as you will get to knowing when a user was last on your site.

Is there a reason that won't work for you?

If you're sure that they are always going to logout (and therefore be logging in again each time they visit the site) then this should work for you. Put it in your templates/admin.php file.

wire()->addHookAfter("Session::login", function(HookEvent $event) {
    $user = wire('user');
    $user->of(false);
    $user->last_login = $user->current_login;
    $user->current_login = time();
    $user->save();
});

Note that I have two fields there - current_login and last_login, and that the value from current gets moved to last each time the user logs in and then a new current is set.

Then on your page you can simply output the value of $user->last_login

Does that help?

You could potentially solve the problem with a session variable to store the last login before it is overwritten by the hook on login, but I think this is cleaner and more reliable.

PS If you don't want to add these fields to your user template, you could make use of teppo's Login History (http://modules.processwire.com/modules/process-login-history/). It maintains a dedicated database table of logins which you could query.

  • Like 1
Link to comment
Share on other sites

Adrian,

thank you so much for your efforts. I havent seen that there is also a module available. This seems the best approach to me because it stores both (frontend and backend) logins. The other possibilities only show frontend logins.

Thanks!!!!!

Link to comment
Share on other sites

For everyone who also wants to use the Login history module from Teppo (http://modules.processwire.com/modules/process-login-history/), here is my attempt to make a sql query to output the date and time of the last visit on a frontend template.

$query = $db->query("SELECT login_timestamp FROM process_login_history WHERE username='{$user->name}' AND login_was_successful=1 ORDER BY login_timestamp DESC");   
$lastvisit = $query->fetch_row();
echo $lastvisit[0];

This will give you an output for the last successful login like this: 2015-05-08 16:40:59

It calls the table "process_login_history" from the module. The dates of the logins are stored in the column "login_timestamp". If the login was successful or not is stored in the column "login_was_successful" and has the value "1" for a successful login. The username is stored in the column "username".

I dont know if the code is the best but it works. If someone has an improvement, please post it here.

Best regards

  • Like 1
Link to comment
Share on other sites

Nice, although I would suggest using PDO - I know teppo's module doesn't use it yet, but I am sure he will update sometime soon.

Try this:

$query = $database->prepare("SELECT login_timestamp FROM process_login_history WHERE user_id = :userid AND login_was_successful=1 ORDER BY login_timestamp DESC LIMIT 1,1");   
$query->execute(array(':userid' => $user->id));
$lastvisit = $query->fetchColumn();
echo $lastvisit;

Note that I also went with the user id - always better to look up an integer than a text field.

PS - Just remember (and I know I already said it above), but this really isn't the "last visit" - you can go forever without needing to login if you visit a site regularly before the session has expired.

Edited by adrian
Add LIMIT 1,1 so as to get second last entry for user which will be their last, rather than current login.
  • Like 2
Link to comment
Share on other sites

Thanks Adrian,

I included the code and it works. Yes you are right, this is not the "last visit", it is the current visit. Unfortunately the query doesnt output all logins of the user which are stored in the column "login_timestamp". So it is not possible to grab the second position "last visit".

Link to comment
Share on other sites

True, it is the current visit - not what I was getting at, but it does make it rather useless for you :)

If you add "LIMIT 1,1" at the end of the query you should get the last login. Only catch is that you won't get anything if there has only been the one login for that user, but that is actually probably what you want anyway in this case.

PS I've updated my post above to include the LIMIT so others will have a working solution.

  • Like 2
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...