Question

I need to display the online status (online/offline) for each author page (custom author page template).

is_user_logged_in() only applies to the current user and I can't find a relevant approach targeting the current author e.g. is_author_logged_in()

Any ideas?

Answer

One Trick Pony was kind enough to prepare the coding for two to three functions using transients, something I hadn't use before.

http://codex.wordpress.org/Transients_API

Add this to functions.php:

add_action('wp', 'update_online_users_status');
function update_online_users_status(){

  if(is_user_logged_in()){

    // get the online users list
    if(($logged_in_users = get_transient('users_online')) === false) $logged_in_users = array();

    $current_user = wp_get_current_user();
    $current_user = $current_user->ID;  
    $current_time = current_time('timestamp');

    if(!isset($logged_in_users[$current_user]) || ($logged_in_users[$current_user] < ($current_time - (15 * 60)))){
      $logged_in_users[$current_user] = $current_time;
      set_transient('users_online', $logged_in_users, 30 * 60);
    }

  }
}

Add this to author.php (or another page template):

function is_user_online($user_id) {

  // get the online users list
  $logged_in_users = get_transient('users_online');

  // online, if (s)he is in the list and last activity was less than 15 minutes ago
  return isset($logged_in_users[$user_id]) && ($logged_in_users[$user_id] > (current_time('timestamp') - (15 * 60)));
}

$passthis_id = $curauth->ID;
if(is_user_online($passthis_id)){
echo 'User is online.';}
else {
echo'User is not online.';}

Second Answer (do not use)

This answer is included for reference. As pointed out by One Trick Pony, this is undesireable approach because the database is updated on each page load. After further scrutiny the code only seemed to be detecting the current user's log-in status rather than additionally matching it to the current author.

1) Install this plugin: http://wordpress.org/extend/plugins/who-is-online/

2) Add the following to your page template:

//Set the $curauth variable
if(isset($_GET['author_name'])) :
$curauth = get_userdatabylogin($author_name);
else :
$curauth = get_userdata(intval($author));
endif;

// Define the ID of whatever authors page is being viewed.
$authortemplate_id = $curauth->ID;

// Connect to database.
global $wpdb;
// Define table as variable.
$who_is_online_table = $wpdb->prefix . 'who_is_online';
// Query: Count the number of user_id's (plugin) that match the author id (author template page).
$onlinestatus_check = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM ".$who_is_online_table." WHERE user_id = '".$authortemplate_id."';" ) );

// If a match is found...
if ($onlinestatus_check == "1"){
echo "<p>User is <strong>online</strong> now!</p>";
}
else{
echo "<p>User is currently <strong>offline</strong>.</p>";
}
Was it helpful?

Solution

I would use transients to do this:

  • create a user-online-update function that you hook on init; it would look something like this:

    // get the user activity the list
    $logged_in_users = get_transient('online_status');
    
    // get current user ID
    $user = wp_get_current_user();
    
    // check if the current user needs to update his online status;
    // he does if he doesn't exist in the list
    $no_need_to_update = isset($logged_in_users[$user->ID])
    
        // and if his "last activity" was less than let's say ...15 minutes ago          
        && $logged_in_users[$user->ID] >  (time() - (15 * 60));
    
    // update the list if needed
    if(!$no_need_to_update){
      $logged_in_users[$user->ID] = time();
      set_transient('online_status', $logged_in_users, $expire_in = (30*60)); // 30 mins 
    }
    

    So this should run on each page load, but the transient will be updated only if required. If you have a large number of users online you might want to increase the "last activity" time frame to reduce db writes, but 15 minutes is more than enough for most sites...

  • now to check if the user is online, simply look inside that transient to see if a certain user is online, just like you did above:

    // get the user activity the list
    $logged_in_users = get_transient('online_status');
    
    // for eg. on author page
    $user_to_check = get_query_var('author'); 
    
    $online = isset($logged_in_users[$user_to_check])
       && ($logged_in_users[$user_to_check] >  (time() - (15 * 60)));
    

The transient expires in 30 minutes if there's no activity at all. But in case you have users online all the time it won't expire, so you might want to clean-up that transient periodically by hooking another function on a twice-daily event or something like that. This function would remove old $logged_in_users entries...

OTHER TIPS

To my knowledge there is not a way to do this using the built-in WordPress functions, but don't let that discourage you; write a plugin!

One way you could do this is by creating a new table in the database that simply tracks the last time the user was active on the site. You could also have a settings page for your plugin that determined how long you would consider a registered user to be "Logged in".

You would implement this using a WordPress hook. I'd start by hooking into the login, so that once a user logs in, your plugin logs the time in the database. You could then explore other things like setting their status to 'away' if they click logout, or 'idle' if their login time was more than two hours ago.

You would run into an issue if they are logged in and active on the site, but past this two hour window. In this case, you'd need to be hooked into the wp-admin section so that anytime they do anything in wp-admin it updates your database to the current time.

Then, on the posts, you would need to do two things: get the author of the current post:

<?php $user_login = the_author_meta( $user_login ); ?>

then query your database to determine if they are logged in:

<?php if your_plugin_function($user_login)... ?>
...display something...

I decided to revisit the given answer. This is just an update as 10 years have passed it was overdue.

One thing that was talked about in the comment was some kind of daily transient cleaner. As pointed out by @onetrickpony we can use wp_schedule_event() to setup a daily reset.

wp_schedule_event()

Schedules a recurring event.

Coupled with delete_transient() and we have our daily cleaner function.

if (! wp_next_scheduled ( 'wp_schedule_event_delete_transient_users_online' )) {

    wp_schedule_event( strtotime( '23:59:00' ), 'twicedaily', 'wp_schedule_event_delete_transient_users_online' );

};

add_action( 'wp_schedule_event_delete_transient_users_online', 'delete_transient_users_online' );

function delete_transient_users_online() {

    delete_transient( 'users_online' );

};

We can also build a get_count_users_online() function which will retrieve the total number of users currently online;

if ( ! function_exists( 'get_count_users_online' ) ) {

    function get_count_users_online() {
    
        $value = get_transient( 'users_online' );
        $buffet = 15 * MINUTE_IN_SECONDS;
        $i = 0;

        foreach ( $value as $key => $timestamp ) {
            if ( $timestamp > ( current_time( 'timestamp' ) - $buffet ) ) {
                $i++;
            };
        };

        return $i;

    };

};

You would call it on the frontend via:

<?php echo get_count_users_online(); ?>

Clever Code

In general, readability is more important than cleverness or brevity.

As per Wordpress standard, I decided also to clean up @onetrickpony code, and dum-it-down a notch, to make it more friendly.

If you don't know what a transient is, take 5 minutes and go through the CODEX overview on transient.

Here is the full working snippet. It includes 3 differents functions.

add_action( 'wp', 'update_online_users_status' );

if ( ! function_exists( 'update_online_users_status' ) ) {

    function update_online_users_status() {
    
        if ( is_user_logged_in() ) { //... only fire for logged in users

            $value = get_transient( 'users_online' ); //... set our transient value as the current transient value
    
            if ( empty( $value ) ) { //... if the value isn't set or is false then we declare it as a new array

                $value = array();

            };
        
            $user_id = get_current_user_id();
            $time = current_time( 'timestamp' );
            $buffet = 15 * MINUTE_IN_SECONDS;  //... the buffet margin where a user is considered online. Take inactivity into account (if no server request are made = user is offline ).

            if ( empty( $value[$user_id] ) || ( $value[$user_id] < ( $time - $buffet ) ) ) { //... if the user isn't already in the transient value array, or if the current user as passed the buffet margin set/update the transient value for that user.
                
                $value[$user_id] = $time;
                $expiration = 30 * MINUTE_IN_SECONDS; //.. global transient expiration, set to 30 minutes. If even ONLY one user do a server request (eg: load a page) then the transient expiration is reset.

                set_transient( 'users_online', $value, $expiration );

            };
    
        };

    };

};

if ( ! function_exists( 'is_user_online' ) ) {

    function is_user_online( $user_id ) { //... echo is_user_online( get_queried_object_id() );
    
        $value = get_transient( 'users_online' );
        $buffet = 15 * MINUTE_IN_SECONDS;

        if ( $value[$user_id] > ( current_time( 'timestamp' ) - $buffet ) ) { //... if our current user is considered within the time buffet margin then return true else null

            return isset( $value[$user_id] );

        };

    };

};

if ( ! function_exists( 'get_count_users_online' ) ) {

    function get_count_users_online() {
    
        $value = get_transient( 'users_online' );
        $buffet = 15 * MINUTE_IN_SECONDS;
        $i = 0;

        foreach ( $value as $key => $timestamp ) {
            if ( $timestamp > ( current_time( 'timestamp' ) - $buffet ) ) {
                $i++;
            };
        };

        return $i;

    };

};

if (! wp_next_scheduled ( 'wp_schedule_event_delete_transient_users_online' )) {

    wp_schedule_event( strtotime( '23:59:00' ), 'twicedaily', 'wp_schedule_event_delete_transient_users_online' );

};

add_action( 'wp_schedule_event_delete_transient_users_online', 'delete_transient_users_online' );

function delete_transient_users_online() {

    delete_transient( 'users_online' );

};

Any and all credit should be directed to @onetrickpony answer.

Use case scenario: author.php

<?php 
if ( get_queried_object() instanceof \WP_User ) {
    echo is_user_online( get_queried_object_id() ); //... return 1 or null
};
?>
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top