Earlier today I ran into a problem where I needed a simple way to display which registered users are online right now on the site.
I’ve done a Video explaining what was my solution and how to apply it to a theme, but I myself hate when I see a video without any code that I can easily take a look at, so below the video you will find a explanation of the code step by step, and in the end the plugin I created for this purpose.
Please note that I will comment further the code on the video, but there are some comments on each one of the snippets here
Variables used [icon:youtube time=’5m20s’ id=’k8W5O0Cpfog’]
We will use only two variables on this plugin:
static protected $_instance = null;
— Holds the static instance of our class after the plugin is initializedstatic protected $prefix = 'OnlineNow';
— Prefix we will use on the Database Options
Class Instance handling [icon:youtube time=’6m42s’ id=’k8W5O0Cpfog’]
When dealing with plugins in WordPress a good practice is to save a static variable of the main class on a private/protected variable and create a static method to instantiate the class whenever you call this method the first time:
static public function instance(){
null === self::$_instance and self::$_instance = new self;
return self::$_instance;
}
Plugin Initialization [icon:youtube time=’7m14s’ id=’k8W5O0Cpfog’]
Here is where our plugin will hook into WordPress and do the required actions to allot this plugin to work as we expect.
public static function init(){
// Lock this class to be initialized only once
if ( null !== self::$_instance ){
return false;
}
add_action( 'wp_login', array( self::instance(), 'login' ), 10, 2 );
add_action( 'clear_auth_cookie', array( self::instance(), 'logout' ), 10 );
// Register Shortcodes
add_shortcode( 'online:list', array( self::instance(), 'shortcode_list' ) );
add_shortcode( 'online:qty', array( self::instance(), 'shortcode_qty' ) );
add_filter( 'widget_text', 'do_shortcode' );
return true;
}
Register when a User logs in [icon:youtube time=’11m25s’ id=’k8W5O0Cpfog’]
We need to register when a user do the login so that we can save it in the database to grab this value and display for the users.
public function login( $user_login, $user ) {
$users = get_option( self::$prefix . '-users', array() );
if ( in_array( $user->ID, $users ) ){
return;
}
$users[] = $user->ID;
update_option( self::$prefix . '-users', $users );
}
Register when a User logs out [icon:youtube time=’13m25s’ id=’k8W5O0Cpfog’]
Just like when we register the action of login and add the user ID to the database option, now we will remove that ID when the user logs out.
public function logout() {
$users = get_option( self::$prefix . '-users', array() );
$user_id = get_current_user_id();
if ( ! in_array( $user_id, $users ) ){
return;
}
update_option( self::$prefix . '-users', array_diff( $users , array( $user_id ) ) );
}
Grab the users logged in [icon:youtube time=’15m47s’ id=’k8W5O0Cpfog’]
We need a method that will allow us to get the users from the database option, I’ve also allowed the developer to exclude or include a user to the list.
public function get_users( $include = array(), $exclude = array() ){
// Retrieve the users from Database
$users = get_option( self::$prefix . '-users', array() );
// Parse Shortcode atts to exclude
if ( is_string( $exclude ) ){
$exclude = array_map( 'trim', explode( ',', $exclude ) );
}
// Exclude users based on shortcode attribute
$users = array_diff( (array) $users, (array) $exclude );
// Parse Shortcode atts to include
if ( is_string( $include ) ){
$include = array_map( 'trim', explode( ',', $include ) );
}
// Include users based on shortcode attribute
$users = array_merge( (array) $users, (array) $include );
// Garantee that the array is safe for usage
$users = array_unique( array_filter( (array) $users ) );
// Remove all non existent users
$users = array_map( array( $this, 'user_exists' ), $users );
// Garantee that the array is safe for usage
$users = array_filter( (array) $users );
return $users;
}
Then I used a method inside of the `get_users` to check if the user exists before return the list of `WP_User` objects – *[on video](http://www.youtube.com/watch?v=k8W5O0Cpfog&t=19m47s)*.
public function user_exists( $user_id ){
$user = new WP_User( $user_id );
// Check if the users exists
if ( ! $user->exists() ){
return false;
}
return $user;
}
List Online Users Shortcode [icon:youtube time=’20m30s’ id=’k8W5O0Cpfog’]
After we did all the hard work of storing the data about user on the database, now we will use that information to print an HTML with the list of users that are currently online.
public function shortcode_list( $atts ) {
$atts = (object) shortcode_atts( array(
'avatar' => false,
'name' => true,
'link' => false,
'exclude' => '',
'include' => '',
'zero_text' => esc_attr__( 'There are no users online right now', 'online-now' ),
), $atts );
$html = '';
$users = $this->get_users( $atts->include, $atts->exclude );
$objects = array();
// Builds the objects
foreach ( $users as $id => $time ) {
$objects[] = new WP_User( $id );
}
if ( ! empty( $users ) ) {
$html .= '<ul class="users-online">';
foreach ( (array) $objects as $user ) {
// Always reset the Profile Link
$profile_link = null;
$html .= '<li>';
// Only start the link if we have the atts for it
if ( $atts->link ) {
// If the user can edit posts then show the author URL
if ( current_user_can( 'edit_posts' ) ) {
$profile_link = get_author_posts_url( $user->ID );
}
// Replace Author URL with BBPress profile link if available
if ( function_exists( 'bbp_get_user_profile_url' ) ) {
$profile_link = esc_url( bbp_get_user_profile_url( $user->ID ) );
}
// Only Show the link if we have something
if ( ! empty( $profile_link ) ) {
$html .= sprintf( '<a href="%s" title="%s">', $profile_link, $user->display_name );
}
}
// Allow the user to control the avatar size and if he wants to show
if ( ! empty( $atts->avatar ) && is_numeric( $atts->avatar ) ) {
$html .= get_avatar( $user->ID, $atts->avatar );
}
// Allow control ver displaying the name
if ( $atts->name ) {
$html .= '<span>' . $user->display_name . '</span>';
}
// Only close link if we have the Link atts and a URL
if ( $atts->link && ! empty( $profile_link ) ) {
$html .= '</a>';
}
$html .= '</li>';
}
$html .= '</ul>';
} else {
$html .= '<p>' . $atts->zero_text . '</p>';
}
return $html;
}
Display the quantity of Users Online [icon:youtube time=’22m26s’ id=’k8W5O0Cpfog’]
The user might also want to display the quantity of users that are online with a shortcode, so we will deal with that too.
public function shortcode_qty( $atts ) {
$atts = (object) shortcode_atts( [
'plural' => __( '%s users online', 'online-now' ),
'singular' => __( 'One user online', 'online-now' ),
'zero' => __( 'Zero users online', 'online-now' ),
'numeric' => false,
'exclude' => '',
'include' => '',
], $atts );
$users = $this->get_users( $atts->include, $atts->exclude );
if ( $atts->numeric ){
return count( $users );
}
if ( count( $users ) === 0 ) {
$text = $atts->zero;
} elseif ( count( $users ) === 1 ) {
$text = $atts->singular;
} else {
$text = $atts->plural;
}
return sprintf( $text, count( $users ) );
}
Repository and Download
You can always checkout the official repository for this plugin and/or download the latest version of the code to install it in your WordPress.
I have installed the plugin onto my site as is and added the shortcode [online:list avatar=’16’] but it displays nothing. What exactly do I have to edit within the plugin for it to show the users? I am using wordpress 4.1
Hi Achoron,
It will depend on which place you’ve added the shortcode. You’ve installed the plugin and activated it correct?
Thank you, add this to wordpress plugins, youd think somebody would have soomething working by now like this geez
Hi Gustavo, I installed and activated the plugin as you described. I want to display the online users in the sidebar of the main page. I added a text box with the shortcode [online:list avatar=’16’] but it does not display anything. Can you please clarify the process to make this work. I am using WordPress 4.1. Thanks for the help.
Hi Hypermediaz,
It will only track the users that logged in and out while the plugin is active.
To see yourself on the list you would have to log-out then login again.
And I updated the code to allow a message when there is no users online available.
Hi, thank you very much for the help. Have a nice day.
Hey 🙂
I understand this does not list ONLINE (ACTIVE) users but LOGGED IN users.
Correct?
It’s somehow a difference to really ONLINE status
(a user might never logout but also not be online)
Hi Beda69, you are 100% correct, I might improve the plugin with something cool from your suggestion.
Create some sort of “timeout” after the login an the user is no longer active on the Website.
Thanks for the answer.
What if they did not logout and left the site? It will show wrong count right?
As I replied for _beda69_ above that’s 100% correct, I will implement a filterable **timeout** to allow that number to be accurate.
Hello..this look great if can work with latest wp..when I activate this plugin what code I need to add to my author.php theme file to get user online/offline status next to name?
After you activate the plugin you will only need the to call for the Shortcode on a Page, on in your case on the `author.php` file, you can call the method directly, like the following:
“`php
$online_users = OnlineNow::instance()->get_users();
// This will hold if the Author is online
$status = in_array( the_author_meta( ‘ID’ ), $online_users );
“`
In official wp plugins directory there is plugin wp-recall,he has good online/offline status for register members but I don’t need that whole plugin for my site just that code for online status..can you make something like this?
Sorry if I didn’t understand your question, can you explain a little bit further?
Thanks for a good tutorial and the user friendly coding! Im trying to use this plugin to display when a certain user type is online, say “subscribers”. Is there a fairly simple way to do that?
Hi Rob,
To do that you would need to change the code after the [line#191](https://github.com/bordoni/online-now/blob/master/online-now.php#L191):
“`php
foreach( $users as $key => $user ) {
// Check if the user is not something then unset it
if ( ! in_array( ‘subscriber’, $user->roles ) ) {
unset( $users[ $key ] );
}
}
// This will reset the keys after removing non-wanted users
$users = array_values( $users );
“`
Hope this helps.
Helo, thank you for this great plugin, how I can check if the user is online in a normal get users loop? or a normal wpdb get_results loop?
I supose it needs to be smth like this, is_user_online($user_id); ? I`m getting undefined function is_user_online(); Thank you
Hey Tzeby1,
First if you can check the version of the plugin you are using, it should be `0.2.1` for the following code to work.
You can use the function called `is_user_onlinenow`:
“`php
if ( is_user_onlinenow( $user_id ) ) {
// User is Online
} else {
// User is not Online
}
“`
Hello Gustavo,
Thank you for this pluggin.
I activated it (version(0.2.1)) but i can’t use the function is_user_onlinenow(). It did’nt recognize other connection
I use it in localhost with different browser for each connection.
Thank you for reply
It will only recognize if you are logged in on a user, if you were logged with other users on other browsers and it still didn’t show, then you found a bug that I will try to reproduce and fix. Let me know.
Hi, I change the code for my case.
it’s not really proper, but for me it works.
In my case, $user->iD was not recognize in $users
“`php
public function is_user_online( $user = 0 ) {
$user = $this->user_exists( $user );
if ( ! $user ){
return false;
}
$users = $this->get_users();
/*echo “”;
print_r( $users);
echo “”;echo $user->data->ID;*/
$liste_u=array();
foreach($users as $u)
{
$liste_u[]=$u->data->ID;
}
/*print_r($liste_u);
if( in_array( $user->data->ID, $liste_u )) echo “in array”;die();
return in_array( $user->ID, $users );*/
return in_array( $user->data->ID, $liste_u );
}
“`
Thanks for the quick answer and the good job 😉
Ahh Now I know what happened, I will fix the code on the plugin, thanks for the report man.
Hi Gustavo, first of all great plugin. one issue I noticed though was that custom local avatars are not supported. I’m using Advanced Custom Fields to set up custom local avatars using this code: https://gist.github.com/ControlledChaos/cd6558219cfbc0a75d6f however the plugin only displays the default avatar of a user. Is there a section of code I can alter to display the local avatars? Thanks in advance.
Hi Phillip,
Sorry for the delay on my answer, the code should be able to get custom avatars if the method is using the required.
I will be sure to make tests with the Code you provided me on your comment. I should release a new version of the plugin next month.
So we will see how it goes.
My Best Regards,
How easy would be be to turn this upside down and show users of a certain role that are not online?
I have created 4 dummy accounts using a custom ‘role’ for customers to use as a demo, if an demo account is is use then the link would disappear.
Uhnn I like the Use-case. I will send you an email about this and we will make this happen.
I want to turn this into a new Article for the blog ahaha.
This is so confusing 🙁
I activated the plugin, now what? what is the shortcode?
Im so Sorry Jonas, the plugin was supposed to be coupled with the Video as a “teaching” tutorial.
Basically after installing you will have access to a few Shortcodes:
* `[online:list]` – That should give you a list of users online
* `[online:qty]` – That should give you a number, which is the quantity of users online
Let me know if I can help you in any way.
Oh thanx for your quickly response. Well i have another question.
I tried something like this….
But shows an error….
Warning: strpos() expects parameter 1 to be string, array given in C:\wamp\www\crazyviral\wp-includes\shortcodes.php on line 205
I found a possible solution, change this — if ( false === strpos( $content, ‘[‘ ) ) { — for this — if ( false === strpos( (string) $content, ‘[‘ ) ) { —
The error message disappeared, but only shows a text “array”.
Any hint?
Hi Jonas,
After taking a good look at could possibly be doing this, Im almost sure this is a conflict been raised by another plugin you have active, because this is Core Behavior.
If you can, try deactivating your all the other plugins and switching to one of the WordPress default themes for testing purposes.
When deactivating do it one by one so you can know the source of the problem.
This will allow you to have a clean environment. After that let me know how thing go.
My Best Regards,
Hi Gustavo, its me again………LOL.
Well i finally made the plugin works and its great!!! just exactly what i was looking for.
So, i have other questions if you could help me.
1.- In my blog, there are 5 authors/contributors, and each one of them publishes just one post. So, how can i show a link to his post using ‘online:list’ shortcode?
2.-Theres a div which is auto refresh by javascript any certain time, inside the div theres an include ‘online.php in that file i inserted the shortcode. But show an error message …Fatal error: Call to undefined function do_shortcode() in…..
3.-How can i create another shortcode to show only the authors name when someone enters to his post?
Sorry for bother so much.
Hi Jonas,
So, basically to auto-refresh after some time you will need to use an [AJAX request that should be created using WordPress methods (check the article)](https://bordoni.me/ajax-wordpress/), it’s not a simple process but after checking that article you can do a little bit more research on google to get more info on AJAX requests on WordPress.
This Call to undefined Function is due to not including WordPress before trying to execute your PHP file, which using WP ajax will solve.
To be able to display a link you would have to craft a custom shortcode that that would be a “duplicate” of what I did on the method `shortcode_list` but with a [`WP_Query`](https://codex.wordpress.org/Class_Reference/WP_Query#Author_Parameters) to check for the latest Post that this author has published. (You can also check on google how to do that)
To create a new Shortcode you just need to duplicate the method and change it’s name, and duplicate the shortcode initialization on the beginning of the code:
“`php
add_shortcode( ‘online:list’, array( self::instance(), ‘shortcode_new_list’ ) );
“`
Be careful to name everything correctly otherwise it won’t work.
Sorry for the late response, and my best regards,
Great script! I’m trying to get it to show the most recent users online, in order of their activity. Is this possible at all with some variable you’ve set, or something I would need to create? If the latter, any tips on where to start?
Cheers.
Hi Dave, I’m going to update this video and Article with a few new tricks to the Code.
I like your idea, of improving the Ordering, but basically I would say that you would have to store more data to be able to do that.
Sorry for not been able to help you now.
Gustavo, if you’d like to get in touch with me I’d be willing to pay for certain customizations. Cheers.
Hello thanks for this great plugin it solve my all problams . how can i get the all users list and then indigate the online and offline users with green or red sign,
Thanks
Hi, thank you so much for this plugin! ive been losing my mind for days trying to find something like this. I have one question though, is it possible to only show a certain type of user such as authors that are logged in and not every type of user.
Thanks a million!!!
Hi Russel,
Yes it’s possible, on the `shortcode_list()` method you add a filter for the roles using inside of the `foreach` with users: `get_user_roles_by_user_id( $user->ID )` and skip displaying any users that are just `contributors`.
If you still have any questions let me know.
hi, sorry ive no idea about coding plug-ins etc, one of the comments above you say about adding some code after line #191 but I cant seem to be able find what is that i need to change. thanks in advance
Ohh no problems.
I am planning to update to this Post in the future with a new Video, and will add that feature for sure, to make it easier for users.
Hello I tested it, it works fine and showing who is online. But among online users, if one of them logout or session ended, it doesn’t reduce the qty of users. it doesn’t seem to know who it already logout.
Hi Ronald,
It will catch who logs out specifically, but when the session ends it doesn’t right away, it uses a caching timeout of 5 minutes.
If that isn’t working properly I should debug to get it working again.
Thanks for commenting.
Hello Gustavo,
Great plugin. What I’ve been looking for.
However, it’s missing the users who are online but inactive.
When I refresh the page where I’ve installed it, it shows me who’s been active within the past 5 minute envelope. That’s not necessarily the full universe of users who are logged in.
I think there needs to be some kind of switch, where when it’s refreshed, it not only get’s the current “5 minute” list, but also pinging any from the previous 5 minute list who are not on the current list, to determine if they are still there.
Please let me know if you think that that’s possible?
THanks,
George Hughes
admin@reportrkr.com
One other feature which would be great would be to produce a running log, based on the 5 minute incremental model. Who’s in and who’s out with +/- 5 minute accuracy is a pretty valuable piece of info. Ideally you attach an IP address to that, and you’re doing more than the high priced plugins.
Also, I’d recommend at this point investing a bit of time, and put the Plugin as the headline, and put the historical “how I got here” as the meat and potatoes of the site. Focus on a few additional features, and you’ll have some good spending money generating out of the mix.
Cheers,
I want the code to show the number of members online on the role of administrator
Thank you so much for your excellent plugin! It is so simple and works right out of the box! What is the best way to style the widget? For example, increase the avatar size, padding, etc.? Thank you so much!
Never mind, I think I got it! I changed this code:
// Allow the user to control the avatar size and if he wants to show
if ( ! empty( $atts->avatar ) && is_numeric( $atts->avatar ) ) {
$html .= get_avatar( $user->ID, 40, $default, $atts->avatar );
}
And added this CSS:
.users-online li span {position: relative; left: 10px;}
.avatar {
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
}
To get pretty, large, rounded, avatars. Super easy plugin to work with! Thank you!
Hi There,
I just want to ask if I can use this plugin and add this feature on my site same as this mockup http://prntscr.com/l7thoq Thanks
awesome, thanks for your plugin. I love you