├── .gitmodules ├── useronline.js ├── useronline.dev.js ├── deprecated.php ├── uninstall.php ├── wp-stats.php ├── widget.php ├── wp-useronline.php ├── bots.php ├── core.php ├── README.md ├── template-tags.php └── admin.php /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "scb"] 2 | path = scb 3 | url = https://github.com/lesterchan/wp-scb-framework.git 4 | -------------------------------------------------------------------------------- /useronline.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function(c){var b=parseInt(useronlineL10n.timeout);var a=function(e){var d={action:"useronline",mode:e,page_url:location.protocol+"//"+location.host+location.pathname+location.search,page_title:c("title").text()};c.post(useronlineL10n.ajax_url,d,function(f){c("#useronline-"+e).html(f)})};c.each(["count","browsing-site","browsing-page","details"],function(d,e){if(c("#useronline-"+e).length){setInterval(function(){a(e)},b)}})}); -------------------------------------------------------------------------------- /useronline.dev.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function($) { 2 | var timeout = parseInt(useronlineL10n.timeout); 3 | 4 | var get_data = function(mode) { 5 | var data = { 6 | 'action': 'useronline', 7 | 'mode': mode, 8 | 'page_url': location.protocol + '//' + location.host + location.pathname + location.search, 9 | 'page_title': $('title').text() 10 | }; 11 | 12 | $.post(useronlineL10n.ajax_url, data, function(response) { 13 | $('#useronline-' + mode).html(response); 14 | }); 15 | } 16 | 17 | $.each(['count', 'browsing-site', 'browsing-page', 'details'], function(i, mode) { 18 | if ( $('#useronline-' + mode).length ) 19 | setInterval(function() { get_data(mode); }, timeout); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /deprecated.php: -------------------------------------------------------------------------------- 1 | 0 ) { 22 | foreach( $option_names as $option_name ) { 23 | delete_option( $option_name ); 24 | plugin_uninstalled(); 25 | } 26 | } 27 | } 28 | } 29 | 30 | restore_current_blog(); 31 | } else { 32 | if( sizeof( $option_names ) > 0 ) { 33 | foreach( $option_names as $option_name ) { 34 | delete_option( $option_name ); 35 | plugin_uninstalled(); 36 | } 37 | } 38 | } 39 | 40 | /** 41 | * Delete plugin table when uninstalled 42 | * 43 | * @access public 44 | * @return void 45 | */ 46 | function plugin_uninstalled() { 47 | global $wpdb; 48 | 49 | $table_names = array( 'useronline' ); 50 | if( sizeof( $table_names ) > 0 ) { 51 | foreach( $table_names as $table_name ) { 52 | $table = $wpdb->prefix . $table_name; 53 | $wpdb->query( "DROP TABLE IF EXISTS $table" ); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /wp-stats.php: -------------------------------------------------------------------------------- 1 |   
'."\n"; 61 | 62 | return $content; 63 | } 64 | 65 | /** 66 | * Add WP-UserOnline General Stats To WP-Stats Page 67 | * 68 | * @param string $content 69 | * 70 | * @access public 71 | * 72 | * @return string 73 | */ 74 | public function page_general_stats( $content ) { 75 | $stats_display = get_option( 'stats_display' ); 76 | 77 | $str = _n( 78 | '%s user online now.', 79 | '%s users online now.', 80 | get_users_online_count(), 'wp-useronline' 81 | ); 82 | 83 | if ( $stats_display['useronline'] === 1 ) 84 | $content .= 85 | html( 'p', html( 'strong', __( 'WP-UserOnline', 'wp-useronline' ) ) ) 86 | .html( 'ul', 87 | html( 'li', sprintf( $str, number_format_i18n( get_users_online_count() ) ) ) 88 | .html( 'li', UserOnline_Template::format_most_users() ) 89 | ); 90 | 91 | return $content; 92 | } 93 | } 94 | 95 | UserOnline_WpStats::get_instance(); 96 | -------------------------------------------------------------------------------- /widget.php: -------------------------------------------------------------------------------- 1 | __( 'WP-UserOnline users online statistics', 'wp-useronline' ) ); 6 | parent::__construct( 'useronline', __( 'UserOnline', 'wp-useronline' ), $widget_ops ); 7 | } 8 | 9 | function content( $instance ) { 10 | if ( empty( $instance['type'] ) ) { 11 | return ''; 12 | } 13 | 14 | $out = ''; 15 | 16 | switch( $instance['type'] ) { 17 | case 'users_online': 18 | $out .= html( 'div id="useronline-count"', get_users_online() ); 19 | break; 20 | case 'users_browsing_page': 21 | $out .= html( 'div id="useronline-browsing-page"', get_users_browsing_page() ); 22 | break; 23 | case 'users_browsing_site': 24 | $out .= html( 'div id="useronline-browsing-site"', get_users_browsing_site() ); 25 | break; 26 | case 'users_online_browsing_page': 27 | $out .= html( 'div id="useronline-count"', get_users_online() ); 28 | $out .= html( 'div id="useronline-browsing-page"', get_users_browsing_page() ); 29 | break; 30 | case 'users_online_browsing_site': 31 | $out .= html( 'div id="useronline-count"', get_users_online() ); 32 | $out .= html( 'div id="useronline-browsing-site"', get_users_browsing_site() ); 33 | break; 34 | } 35 | 36 | echo $out; 37 | } 38 | 39 | function update( $new_instance, $old_instance ) { 40 | if ( !isset( $new_instance['submit'] ) ) 41 | return false; 42 | 43 | $instance = $old_instance; 44 | $instance['title'] = strip_tags( $new_instance['title'] ); 45 | $instance['type'] = strip_tags( $new_instance['type'] ); 46 | 47 | return $instance; 48 | } 49 | 50 | function form( $instance ) { 51 | global $wpdb; 52 | $instance = wp_parse_args( (array) $instance, array( 53 | 'title' => __( 'UserOnline', 'wp-useronline' ), 54 | 'type' => 'users_online' 55 | ) ); 56 | $title = esc_attr( $instance['title'] ); 57 | $type = esc_attr( $instance['type'] ); 58 | ?> 59 |

60 | 61 |

62 |

63 | 73 |

74 | 75 | 1, 36 | 'date' => current_time( 'timestamp' ) 37 | ) ); 38 | 39 | $options = new scbOptions( 'useronline', __FILE__, array( 40 | 'timeout' => 300, 41 | 'url' => trailingslashit( get_bloginfo( 'url' ) ) . 'useronline', 42 | 'names' => false, 43 | 44 | 'naming' => array( 45 | 'user' => __( '1 User', 'wp-useronline' ), 46 | 'users' => __( '%COUNT% Users', 'wp-useronline' ), 47 | 'member' => __( '1 Member', 'wp-useronline' ), 48 | 'members' => __( '%COUNT% Members', 'wp-useronline' ), 49 | 'guest' => __( '1 Guest', 'wp-useronline' ), 50 | 'guests' => __( '%COUNT% Guests', 'wp-useronline' ), 51 | 'bot' => __( '1 Bot', 'wp-useronline' ), 52 | 'bots' => __( '%COUNT% Bots', 'wp-useronline' ) 53 | ), 54 | 55 | 'templates' => array( 56 | 'useronline' => '%USERS% '.__( 'Online', 'wp-useronline' ).'', 57 | 58 | 'browsingsite' => array( 59 | 'separators' => array( 60 | 'members' => __( ',', 'wp-useronline' ).' ', 61 | 'guests' => __( ',', 'wp-useronline' ).' ', 62 | 'bots' => __( ',', 'wp-useronline' ).' ', 63 | ), 64 | 'text' => _x( 'Users', 'Template Element', 'wp-useronline' ).': %MEMBER_NAMES%%GUESTS_SEPARATOR%%GUESTS%%BOTS_SEPARATOR%%BOTS%' 65 | ), 66 | 67 | 'browsingpage' => array( 68 | 'separators' => array( 69 | 'members' => __( ',', 'wp-useronline' ).' ', 70 | 'guests' => __( ',', 'wp-useronline' ).' ', 71 | 'bots' => __( ',', 'wp-useronline' ).' ', 72 | ), 73 | 'text' => '%USERS% '.__( 'Browsing This Page.', 'wp-useronline' ).'
'._x( 'Users', 'Template Element', 'wp-useronline' ).': %MEMBER_NAMES%%GUESTS_SEPARATOR%%GUESTS%%BOTS_SEPARATOR%%BOTS%' 74 | ) 75 | ) 76 | ) ); 77 | 78 | UserOnline_Core::init( $options, $most ); 79 | 80 | if ( is_admin() ) { 81 | require_once __DIR__ . '/admin.php'; 82 | scbAdminPage::register( 'UserOnline_Admin_Integration', __FILE__ ); 83 | scbAdminPage::register( 'UserOnline_Options', __FILE__, UserOnline_Core::$options ); 84 | } 85 | 86 | if ( function_exists( 'stats_page' ) ) 87 | require_once __DIR__ . '/wp-stats.php'; 88 | 89 | # scbUtil::do_uninstall( __FILE__ ); 90 | # scbUtil::do_activation( __FILE__ ); 91 | } 92 | scb_init( '_useronline_init' ); 93 | 94 | add_action( 'plugins_loaded', 'useronline_init_widget' ); 95 | function useronline_init_widget() { 96 | if ( ! class_exists( 'scbWidget', false ) ) { 97 | require_once __DIR__ . '/scb/Widget.php'; 98 | } 99 | require_once __DIR__ . '/widget.php'; 100 | scbWidget::init( 'UserOnline_Widget', __FILE__, 'useronline' ); 101 | } -------------------------------------------------------------------------------- /bots.php: -------------------------------------------------------------------------------- 1 | '360spider', 6 | 'AddThis' => 'addthis', 7 | 'Adsbot' => 'Adsbot', 8 | 'AdScanner' => 'adscanner', 9 | 'AHC' => 'AHC', 10 | 'Ahrefs' => 'ahrefsbot', 11 | 'Alex' => 'ia_archiver', 12 | 'AllTheWeb' => 'fast-webcrawler', 13 | 'Altavista' => 'scooter', 14 | 'Amazon' => 'amazonaws.com', 15 | 'Anders Pink' => 'anderspinkbot', 16 | 'Apple' => 'applebot', 17 | 'Archive.org' => 'archive.org_bot', 18 | 'Ask Jeeves' => 'jeeves', 19 | 'Aspiegel' => 'AspiegelBot', 20 | 'Axios' => 'axios', 21 | 'Baidu' => 'baidu', 22 | 'Become.com' => 'become.com', 23 | 'Bing' => 'bingbot', 24 | 'Bing Preview' => 'bingpreview', 25 | 'Blackboard' => 'Blackboard', 26 | 'BLEXBot' => 'blexbot', 27 | 'Bloglines' => 'bloglines', 28 | 'Blog Search Engine' => 'blogsearch', 29 | 'BUbiNG' => 'bubing', 30 | 'Buck' => 'Buck', 31 | 'Bytespider' => 'Bytespider', 32 | 'CCBot' => 'ccbot', 33 | 'CFNetwork' => 'cfnetwork', 34 | 'ChatGPT' => 'ChatGPT', 35 | 'CheckMarkNetwork' => 'CheckMarkNetwork', 36 | 'ClaudeBot' => 'ClaudeBot', 37 | 'Cliqzbot' => 'cliqzbot', 38 | 'Coccoc' => 'coccocbot', 39 | 'Crawl' => 'crawl', 40 | 'Curl' => 'Curl', 41 | 'Cyotek' => 'Cyotek', 42 | 'Daum' => 'Daum', 43 | 'Dispatch' => 'Dispatch', 44 | 'DomainCrawler' => 'domaincrawler', 45 | 'DotBot' => 'dotbot', 46 | 'DuckDuckGo' => 'duckduckbot', 47 | 'EveryoneSocialBot' => 'everyonesocialbot', 48 | 'Exalead' => 'exabot', 49 | 'Facebook' => 'facebook', 50 | 'Facebook Preview' => 'facebookexternalhit', 51 | 'faceBot' => 'facebot', 52 | 'Feedfetcher' => 'Feedfetcher', 53 | 'Femtosearch' => 'FemtosearchBot', 54 | 'Findexa' => 'findexa', 55 | 'Flipboard Preview' => 'FlipboardProxy', 56 | 'Gais' => 'gaisbo', 57 | 'Gigabot' => 'gigabot', 58 | 'Gluten Free' => 'gluten free crawler', 59 | 'Go-http-client' => 'Go-http-client', 60 | 'Goforit' => 'GOFORITBOT', 61 | 'Google' => 'google', 62 | 'GPTBot' => 'GPTBot', 63 | 'Grid' => 'gridbot', 64 | 'GroupHigh' => 'grouphigh', 65 | 'Heritrix' => 'heritrix', 66 | 'IA Archiver' => 'ia_archiver', 67 | 'Inktomi' => 'slurp@inktomi', 68 | 'IPS Agent' => 'ips-agent', 69 | 'James' => 'james bot', 70 | 'Jobboerse' => 'Jobboerse', 71 | 'KomodiaBot' => 'komodiabot', 72 | 'Konqueror' => 'konqueror', 73 | 'Lindex' => 'linkdexbot', 74 | 'Linguee' => 'Linguee', 75 | 'Linkfluence' => 'linkfluence', 76 | 'Lycos' => 'lycos', 77 | 'Maui' => 'mauibot', 78 | 'Mediatoolkit' => 'mediatoolkitbot', 79 | 'MegaIndex' => 'MegaIndex', 80 | 'MetaFeedly' => 'MetaFeedly', 81 | 'MetaURI' => 'metauri', 82 | 'MJ12bot' => 'mj12bot', 83 | 'MojeekBot' => 'mojeekBot', 84 | 'Moreover' => 'moreover', 85 | 'MSN' => 'msnbot', 86 | 'NBot' => 'nbot', 87 | 'NextLinks' => 'findlinks', 88 | 'Node-Fetch' => 'node-fetch', 89 | 'oBot' => 'oBot', 90 | 'Omgili' => 'omgili', 91 | 'Panscient' => 'panscient.com', 92 | 'PaperLiBot' => 'paperliBot', 93 | 'PetalBot' => 'PetalBot', 94 | 'PhantomJS' => 'phantomjs', 95 | 'Picsearch' => 'picsearch', 96 | 'Pinterestbot' => 'Pinterestbot', 97 | 'Proximic' => 'proximic', 98 | 'PubSub' => 'pubsub', 99 | 'Python' => 'Python', 100 | 'Radian6' => 'radian6', 101 | 'RadioUserland' => 'userland', 102 | 'Re-re Studio' => 'Re-re Studio', 103 | 'RyteBot' => 'RyteBot', 104 | 'Moz' => 'rogerbot', 105 | 'Qwantify' => 'Qwantify', 106 | 'Scoutjet' => 'Scoutjet', 107 | 'Scrapy' => 'Scrapy', 108 | 'Screaming Frog SEO Spider' => 'Screaming Frog SEO Spider', 109 | 'SEOkicks' => 'seokicks-robot', 110 | 'Semanticbot' => 'Semanticbot', 111 | 'SemrushBot' => 'semrushbot', 112 | 'SerendeputyBot' => 'serendeputybot', 113 | 'Seznam' => 'seznam', 114 | 'SirdataBot ' => 'SirdataBot ', 115 | 'SiteExplorer' => 'siteexplorer', 116 | 'Sixtrix' => 'SIXTRIX', 117 | 'Slurp' => 'slurp', 118 | 'SMTBot' => 'SMTBot', 119 | 'Sogou' => 'Sogou', 120 | 'OpenLinkProfiler.org' => 'spbot', 121 | 'SurveyBot' => 'surveybot', 122 | 'Syndic8' => 'syndic8', 123 | 'Technorati' => 'technorati', 124 | 'TelegramBot' => 'telegrambot', 125 | 'Tiny Tiny RSS' => 'tt-rss', 126 | 'Thither' => 'thither', 127 | 'TraceMyFile' => 'tracemyfile', 128 | 'Trendsmap' => 'trendsmap', 129 | 'Turnitin.com' => 'turnitinbot', 130 | 'The Tweeted Times' => 'tweetedtimes', 131 | 'TweetmemeBot' => 'tweetmemeBot', 132 | 'Twingly' => 'twingly', 133 | 'X' => 'twitterbot', 134 | 'VoilaBot' => 'VoilaBot', 135 | 'Wget' => 'wget', 136 | 'WhatsApp' => 'whatsapp', 137 | 'WhoisSource' => 'surveybot', 138 | 'WiseNut' => 'zyborg', 139 | 'Wotbox' => 'wotbox', 140 | 'Xenu Link Sleuth' => 'xenu link sleuth', 141 | 'XoviBot' => 'xoviBot', 142 | 'Yahoo' => 'yahoo', 143 | 'Yandex' => 'yandex', 144 | 'Disqus' => 'disqus', 145 | 'YisouSpider' => 'yisouspider' 146 | ); 147 | 148 | return apply_filters( 'useronline_bots', $bots ); 149 | } 150 | 151 | -------------------------------------------------------------------------------- /core.php: -------------------------------------------------------------------------------- 1 | get_var( "SELECT COUNT( * ) FROM $wpdb->useronline" ) ); 17 | 18 | return self::$useronline; 19 | } 20 | 21 | static function init( $options, $most ) { 22 | self::$options = $options; 23 | self::$most = $most; 24 | 25 | add_action( 'plugins_loaded', array( __CLASS__, 'wp_stats_integration' ) ); 26 | 27 | add_action( 'admin_head', array( __CLASS__, 'record' ) ); 28 | add_action( 'wp_head', array( __CLASS__, 'record' ) ); 29 | 30 | add_action( 'wp_footer', array( __CLASS__, 'scripts' ) ); 31 | 32 | add_action( 'wp_ajax_useronline', array( __CLASS__, 'ajax' ) ); 33 | add_action( 'wp_ajax_nopriv_useronline', array( __CLASS__, 'ajax' ) ); 34 | 35 | add_shortcode( 'page_useronline', 'users_online_page' ); 36 | 37 | if ( self::$options->names ) 38 | add_filter( 'useronline_display_user', array( __CLASS__, 'linked_names' ), 10, 2 ); 39 | } 40 | 41 | static function linked_names( $name, $user ) { 42 | if ( !$user->user_id ) 43 | return $name; 44 | 45 | return html_link( get_author_posts_url( $user->user_id ), $name ); 46 | } 47 | 48 | static function scripts() { 49 | if ( !self::$add_script ) 50 | return; 51 | 52 | $js_dev = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.dev' : ''; 53 | 54 | wp_enqueue_script( 'wp-useronline', plugins_url( "useronline$js_dev.js", __FILE__ ), array( 'jquery' ), '2.80', true ); 55 | wp_localize_script( 'wp-useronline', 'useronlineL10n', array( 56 | 'ajax_url' => admin_url( 'admin-ajax.php' ), 57 | 'timeout' => self::$options->timeout * 1000 58 | ) ); 59 | 60 | scbUtil::do_scripts('wp-useronline'); 61 | } 62 | 63 | static function record( $page_url = '', $page_title = '' ) { 64 | require_once dirname(__FILE__) . '/bots.php'; 65 | 66 | global $wpdb; 67 | 68 | if ( empty( $page_url ) ) { 69 | $page_url = wp_strip_all_tags( $_SERVER['REQUEST_URI'] ); 70 | } 71 | 72 | if ( empty( $page_title ) ) { 73 | $page_title = wp_strip_all_tags( self::get_title() ); 74 | } 75 | 76 | if ( isset( $_SERVER['HTTP_REFERER'] ) ) { 77 | $referral = wp_strip_all_tags( $_SERVER['HTTP_REFERER'] ); 78 | } else { 79 | $referral = ''; 80 | } 81 | 82 | $user_ip = wp_strip_all_tags( self::get_ip() ); 83 | 84 | if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) { 85 | $user_agent = wp_strip_all_tags( $_SERVER['HTTP_USER_AGENT'] ); 86 | } else { 87 | $user_agent = ''; 88 | } 89 | 90 | $current_user = wp_get_current_user(); 91 | 92 | // Check For Bot 93 | $bots = useronline_get_bots(); 94 | 95 | $bot_found = false; 96 | foreach ( $bots as $name => $lookfor ) { 97 | if ( stristr( $user_agent, $lookfor ) !== false ) { 98 | $user_id = 0; 99 | $user_name = $name; 100 | $username = $lookfor; 101 | $user_type = 'bot'; 102 | $bot_found = true; 103 | 104 | break; 105 | } 106 | } 107 | 108 | // If No Bot Is Found, Then We Check Members And Guests 109 | if ( !$bot_found ) { 110 | if ( $current_user->ID ) { 111 | // Check For Member 112 | $user_id = $current_user->ID; 113 | $user_name = $current_user->display_name; 114 | $user_type = 'member'; 115 | $where = $wpdb->prepare( "WHERE user_id = %d", $user_id ); 116 | } elseif ( !empty( $_COOKIE['comment_author_'.COOKIEHASH] ) ) { 117 | // Check For Comment Author ( Guest ) 118 | $user_id = 0; 119 | $user_name = trim( wp_strip_all_tags( $_COOKIE['comment_author_'.COOKIEHASH] ) ); 120 | $user_type = 'guest'; 121 | } else { 122 | // Check For Guest 123 | $user_id = 0; 124 | $user_name = __( 'Guest', 'wp-useronline' ); 125 | $user_type = 'guest'; 126 | } 127 | } 128 | 129 | // Current GMT Timestamp 130 | $timestamp = current_time( 'mysql' ); 131 | 132 | // Purge table 133 | $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->useronline WHERE (user_id <> 0 AND user_id = %d) OR (user_id = 0 AND user_agent = %s AND user_ip = %s) OR (timestamp < DATE_SUB(%s, INTERVAL %d SECOND))", $user_id, $user_agent, $user_ip, $timestamp, self::$options->timeout ) ); 134 | 135 | // Insert Users 136 | $data = compact( 'timestamp', 'user_type', 'user_id', 'user_name', 'user_ip', 'user_agent', 'page_title', 'page_url', 'referral' ); 137 | $data = stripslashes_deep( $data ); 138 | $wpdb->replace( $wpdb->useronline, $data ); 139 | 140 | // Count Users Online 141 | self::$useronline = intval( $wpdb->get_var( "SELECT COUNT( * ) FROM $wpdb->useronline" ) ); 142 | 143 | // Maybe Update Most User Online 144 | if ( self::$useronline > self::$most->count ) { 145 | self::$most->update( array( 146 | 'count' => self::$useronline, 147 | 'date' => current_time( 'timestamp' ) 148 | ) ); 149 | } 150 | } 151 | 152 | private function clear_table() { 153 | global $wpdb; 154 | 155 | $wpdb->query( "DELETE FROM $wpdb->useronline" ); 156 | } 157 | 158 | static function ajax() { 159 | $mode = trim( $_POST['mode'] ); 160 | 161 | $page_title = strip_tags( $_POST['page_title'] ); 162 | 163 | $page_url = str_replace( get_bloginfo( 'url' ), '', $_POST['page_url'] ); 164 | 165 | if ( $page_url != $_POST['page_url'] ) 166 | self::record( $page_url, $page_title ); 167 | 168 | switch( $mode ) { 169 | case 'count': 170 | users_online(); 171 | break; 172 | case 'browsing-site': 173 | users_browsing_site(); 174 | break; 175 | case 'browsing-page': 176 | users_browsing_page($page_url); 177 | break; 178 | case 'details': 179 | echo users_online_page(); 180 | break; 181 | } 182 | 183 | die; 184 | } 185 | 186 | static function wp_stats_integration() { 187 | if ( function_exists( 'stats_page' ) ) 188 | require_once dirname( __FILE__ ) . '/wp-stats.php'; 189 | } 190 | 191 | private static function get_title() { 192 | if ( is_admin() && function_exists( 'get_admin_page_title' ) ) { 193 | $page_title = ' » ' . __( 'Admin', 'wp-useronline' ) . ' » ' . get_admin_page_title(); 194 | } else { 195 | $page_title = wp_title( '»', false ); 196 | if ( empty( $page_title ) ) 197 | $page_title = ' » ' . strip_tags( $_SERVER['REQUEST_URI'] ); 198 | elseif ( is_singular() ) 199 | $page_title = ' » ' . $page_title; 200 | } 201 | $page_title = get_bloginfo( 'name' ) . $page_title; 202 | 203 | return $page_title; 204 | } 205 | 206 | private static function get_ip() { 207 | if ( isset( $_SERVER["HTTP_X_FORWARDED_FOR"] ) ) 208 | $ip_address = $_SERVER["HTTP_X_FORWARDED_FOR"]; 209 | else 210 | $ip_address = $_SERVER["REMOTE_ADDR"]; 211 | 212 | list( $ip_address ) = explode( ',', $ip_address ); 213 | 214 | return $ip_address; 215 | } 216 | } 217 | 218 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WP-UserOnline 2 | Contributors: GamerZ 3 | Donate link: https://lesterchan.net/site/donation/ 4 | Tags: useronline, usersonline, wp-useronline, online, widget 5 | Requires at least: 4.6 6 | Tested up to: 6.7 7 | Stable tag: 2.88.9 8 | License: GPLv2 or later 9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 10 | 11 | Enable you to display how many users are online on your Wordpress blog with detailed statistics. 12 | 13 | ## Description 14 | This plugin enables you to display how many users are online on your Wordpress site, with detailed statistics of where they are and who they are (Members/Guests/Search Bots). 15 | 16 | ### Usage (With Widget) 17 | 1. Go to `WP-Admin -> Appearance -> Widgets` 18 | 1. The widget name is UserOnline. 19 | 1. Scroll down for instructions on how to create a *UserOnline Page*. 20 | 21 | ### Usage (Without Widget) 22 | * Open `wp-content/themes//sidebar.php` and add Anywhere: 23 | 24 | ```php 25 | 26 |

Users online:

27 | 28 | ``` 29 | 30 | ### Development 31 | [https://github.com/lesterchan/wp-useronline](https://github.com/lesterchan/wp-useronline "https://github.com/lesterchan/wp-useronline") 32 | 33 | ### Credits 34 | * Plugin icon by [Freepik](http://www.freepik.com) from [Flaticon](http://www.flaticon.com) 35 | 36 | ### Donations 37 | I spent most of my free time creating, updating, maintaining and supporting these plugins, if you really love my plugins and could spare me a couple of bucks, I will really appreciate it. If not feel free to use it without any obligations. 38 | 39 | ## Screenshots 40 | 41 | 1. Admin - Dashboard's Right Now 42 | 2. UserOnline Page 43 | 3. Admin - Settings Page 44 | 45 | ## Frequently Asked Questions 46 | 47 | ### Creating A UserOnline Page 48 | 1. Go to `WP-Admin -> Pages -> Add New` 49 | 1. Type any title you like in the post's title area 50 | 1. If you ARE using nice permalinks, after typing the title, WordPress will generate the permalink to the page. You will see an 'Edit' link just beside the permalink. 51 | 1. Click 'Edit' and type in `useronline` in the text field and click 'Save'. 52 | 1. Type `[page_useronline]` in the post's content area 53 | 1. Click 'Publish' 54 | 55 | If you ARE NOT using nice permalinks, you need to go to `WP-Admin -> Settings -> UserOnline` and under 'UserOnline URL', you need to fill in the URL to the UserOnline Page you created above. 56 | 57 | ### To Display Most Number Of Users Online 58 | * Use: 59 | ```php 60 | 61 |

Most Users Ever Online Is On

62 | 63 | ``` 64 | 65 | ### To Display Users Browsing Site 66 | * Use: 67 | ```php 68 | 69 |
70 | 71 | ``` 72 | 73 | ### To Display Users Browsing A Page 74 | * Use: 75 | ```php 76 | 77 |
78 | 79 | ``` 80 | 81 | ### Error on activation: "Parse error: syntax error, unexpected..." 82 | 83 | Make sure your host is running PHP 5. The only foolproof way to do this is to add this line to wp-config.php (after the opening `templates['useronline']; 10 | $template = str_ireplace( '%PAGE_URL%', UserOnline_Core::$options->url, $template ); 11 | $template = str_ireplace( '%MOSTONLINE_COUNT%', get_most_users_online(), $template ); 12 | $template = str_ireplace( '%MOSTONLINE_DATE%', get_most_users_online_date(), $template ); 13 | 14 | return UserOnline_Template::format_count( get_users_online_count(), 'user', $template ); 15 | } 16 | 17 | ### Function: Display UserOnline Count 18 | function users_online_count() { 19 | echo number_format_i18n( get_useronline_count() ); 20 | } 21 | 22 | function get_users_online_count() { 23 | return UserOnline_Core::get_user_online_count(); 24 | } 25 | 26 | ### Function: Display Max UserOnline 27 | function most_users_online() { 28 | echo number_format_i18n( get_most_users_online() ); 29 | } 30 | 31 | function get_most_users_online() { 32 | return intval( UserOnline_Core::$most->count ); 33 | } 34 | 35 | ### Function: Display Max UserOnline Date 36 | function most_users_online_date() { 37 | echo get_most_users_online_date(); 38 | } 39 | 40 | function get_most_users_online_date() { 41 | return UserOnline_Template::format_date( UserOnline_Core::$most->date ); 42 | } 43 | 44 | ### Function: Display Users Browsing The Site 45 | function users_browsing_site() { 46 | echo get_users_browsing_site(); 47 | } 48 | 49 | function get_users_browsing_site() { 50 | return UserOnline_Template::compact_list( 'site' ); 51 | } 52 | 53 | ### Function: Display Users Browsing The ( Current ) Page 54 | function users_browsing_page( $page_url = '' ) { 55 | echo get_users_browsing_page( $page_url ); 56 | } 57 | 58 | function get_users_browsing_page( $page_url = '' ) { 59 | return UserOnline_Template::compact_list( 'page', 'html', $page_url ); 60 | } 61 | 62 | ### Function: UserOnline Page 63 | function users_online_page() { 64 | global $wpdb; 65 | 66 | $usersonline = $wpdb->get_results( "SELECT * FROM $wpdb->useronline ORDER BY timestamp DESC" ); 67 | 68 | $user_buckets = array(); 69 | foreach ( $usersonline as $useronline ) 70 | $user_buckets[$useronline->user_type][] = $useronline; 71 | 72 | $user_buckets = apply_filters( 'useronline_buckets', $user_buckets ); 73 | 74 | $counts = UserOnline_Template::get_counts( $user_buckets ); 75 | 76 | $nicetexts = array(); 77 | foreach ( array( 'user', 'member', 'guest', 'bot' ) as $user_type ) 78 | $nicetexts[$user_type] = UserOnline_Template::format_count( $counts[$user_type], $user_type ); 79 | 80 | $text = _n( 81 | 'There is %s online now: %s, %s and %s.', 82 | 'There are a total of %s online now: %s, %s and %s.', 83 | $counts['user'], 'wp-useronline' 84 | ); 85 | 86 | $output = 87 | html( 'div id="useronline-details"', 88 | html( 'p', vsprintf( $text, $nicetexts ) ) 89 | .html( 'p', UserOnline_Template::format_most_users() ) 90 | .UserOnline_Template::detailed_list( $counts, $user_buckets, $nicetexts ) 91 | ); 92 | 93 | return apply_filters( 'useronline_page', $output ); 94 | } 95 | 96 | ### Function Check If User Is Online 97 | function is_user_online( $user_id ) { 98 | global $wpdb; 99 | 100 | return (bool) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->useronline WHERE user_id = %d LIMIT 1", $user_id ) ); 101 | } 102 | 103 | function get_useronline_( $output, $type = 'site' ) { 104 | return UserOnline_Template::compact_list( $type, $output ); 105 | } 106 | 107 | class UserOnline_Template { 108 | 109 | private static $cache = array(); 110 | 111 | static function compact_list( $type, $output = 'html', $page_url = '') { 112 | UserOnline_Core::$add_script = true; 113 | 114 | if ( !isset( self::$cache[$type] ) ) { 115 | global $wpdb; 116 | 117 | if ( 'site' == $type ) { 118 | $where = ''; 119 | } elseif ( 'page' == $type ) { 120 | if ( empty($page_url) ) 121 | $page_url = $_SERVER['REQUEST_URI']; 122 | $where = $wpdb->prepare( 'WHERE page_url = %s', $page_url ); 123 | } 124 | 125 | self::$cache[$type . $page_url] = $wpdb->get_results( "SELECT * FROM $wpdb->useronline $where ORDER BY timestamp DESC" ); 126 | } 127 | 128 | $users = self::$cache[$type . $page_url]; 129 | 130 | if ( 'list' == $output ) 131 | return $users; 132 | 133 | $buckets = array(); 134 | foreach ( $users as $user ) 135 | $buckets[$user->user_type][] = $user; 136 | 137 | if ( 'buckets' == $output ) 138 | return $buckets; 139 | 140 | $counts = self::get_counts( $buckets ); 141 | 142 | if ( 'counts' == $output ) 143 | return $counts; 144 | 145 | // Template - Naming Conventions 146 | $naming = UserOnline_Core::$options->naming; 147 | 148 | // Template - User(s) Browsing Site 149 | $template = UserOnline_Core::$options->templates["browsing$type"]; 150 | 151 | // Nice Text For Users 152 | $output = self::format_count( $counts['user'], 'user', $template['text'] ); 153 | 154 | // Print Member Name 155 | $temp_member = ''; 156 | $members = @$buckets['member']; 157 | if ( $members ) { 158 | $temp_member = array(); 159 | foreach ( $members as $member ) 160 | $temp_member[] = self::format_name( $member ); 161 | $temp_member = implode( $template['separators']['members'], $temp_member ); 162 | } 163 | $output = str_ireplace( '%MEMBER_NAMES%', $temp_member, $output ); 164 | 165 | // Counts 166 | foreach ( array( 'member', 'guest', 'bot' ) as $user_type ) { 167 | if ( $counts[$user_type] > 1 ) 168 | $number = str_ireplace( '%COUNT%', number_format_i18n( $counts[$user_type] ), $naming[$user_type . 's'] ); 169 | elseif ( $counts[$user_type] == 1 ) 170 | $number = $naming[$user_type]; 171 | else 172 | $number = ''; 173 | $output = str_ireplace( "%{$user_type}S%", $number, $output ); 174 | } 175 | 176 | // SEPARATORs 177 | $separator = ( $counts['member'] && $counts['guest'] ) ? $template['separators']['guests'] : ''; 178 | $output = str_ireplace( '%GUESTS_SEPARATOR%', $separator, $output ); 179 | 180 | $separator = ( ( $counts['guest'] || $counts['member'] ) && $counts['bot'] ) ? $template['separators']['bots'] : ''; 181 | $output = str_ireplace( '%BOTS_SEPARATOR%', $separator, $output ); 182 | 183 | return $output; 184 | } 185 | 186 | static function detailed_list( $counts, $user_buckets, $nicetexts ) { 187 | UserOnline_Core::$add_script = true; 188 | 189 | if ( $counts['user'] == 0 ) 190 | return html( 'h2', __( 'No one is online now.', 'wp-useronline' ) ); 191 | 192 | $_on = __( 'on', 'wp-useronline' ); 193 | $_url = __( 'url', 'wp-useronline' ); 194 | $_referral = __( 'referral', 'wp-useronline' ); 195 | 196 | $output = ''; 197 | foreach ( array( 'member', 'guest', 'bot' ) as $user_type ) { 198 | if ( !$counts[$user_type] ) 199 | continue; 200 | 201 | $count = $counts[$user_type]; 202 | $users = $user_buckets[$user_type]; 203 | $nicetext = $nicetexts[$user_type]; 204 | 205 | $output .= html( 'h2', $nicetext . ' ' . __( 'Online Now', 'wp-useronline' ) ); 206 | 207 | $i=1; 208 | foreach ( $users as $user ) { 209 | $nr = number_format_i18n( $i++ ); 210 | $name = self::format_name( $user ); 211 | $user_ip = self::format_ip( $user ); 212 | $date = self::format_date( $user->timestamp, true ); 213 | 214 | if ( current_user_can( 'edit_users' ) || false === strpos( $user->page_url, 'wp-admin' ) ) { 215 | $page_title = esc_html( $user->page_title ); 216 | $current_link = self::format_link( $user->page_url, $_url ); 217 | $referral_link = self::format_link( $user->referral, $_referral ); 218 | } 219 | 220 | $output .= apply_filters("useronline_custom_template", "

#$nr - $name $user_ip $_on $date
$page_title $current_link $referral_link

\n", $nr, $user); 221 | } 222 | } 223 | 224 | return $output; 225 | } 226 | 227 | static function format_link($url, $title) { 228 | if ( !empty($url) ) 229 | return '[' . html_link( $url, $title ) . ']'; 230 | 231 | return ''; 232 | } 233 | 234 | static function format_ip( $user ) { 235 | $ip = esc_attr( $user->user_ip ); 236 | 237 | if ( current_user_can( 'edit_users' ) && !empty( $ip ) && $ip != 'unknown' ) { 238 | return 239 | html( 'span', array('dir' => 'ltr'), 240 | html( 'a', array( 241 | 'href' => esc_url( 'http://whois.domaintools.com/' . $ip ), 242 | 'title' => esc_attr( $user->user_agent ) 243 | ), $ip ) 244 | ); 245 | } 246 | } 247 | 248 | static function format_date( $date, $mysql = false ) { 249 | if ( $mysql ) 250 | return mysql2date( sprintf( __( '%s @ %s', 'wp-useronline' ), get_option( 'date_format' ), get_option( 'time_format' ) ), $date, true ); 251 | 252 | return date_i18n( sprintf( __( '%s @ %s', 'wp-useronline' ), get_option( 'date_format' ), get_option( 'time_format' ) ), $date ); 253 | } 254 | 255 | static function format_name( $user ) { 256 | return apply_filters( 'useronline_display_user', esc_html( $user->user_name ), $user ); 257 | } 258 | 259 | static function format_count( $count, $user_type, $template = false ) { 260 | $i = ( $count == 1 ) ? '' : 's'; 261 | $string = UserOnline_Core::$options->naming[$user_type . $i]; 262 | 263 | $output = str_ireplace( '%COUNT%', number_format_i18n( $count ), $string ); 264 | 265 | if ( false === $template ) 266 | return $output; 267 | 268 | return str_ireplace( '%USERS%', $output, $template ); 269 | } 270 | 271 | static function format_most_users() { 272 | return sprintf( __( 'Most users ever online were %s, on %s', 'wp-useronline' ), 273 | number_format_i18n( get_most_users_online() ), 274 | get_most_users_online_date() 275 | ); 276 | } 277 | 278 | static function get_counts( $buckets ) { 279 | $counts = array(); 280 | $total = 0; 281 | foreach ( array( 'member', 'guest', 'bot' ) as $user_type ) { 282 | $count = isset( $buckets[$user_type] ) ? count( @$buckets[$user_type] ) : 0; 283 | $total += $counts[$user_type] = $count; 284 | } 285 | 286 | $counts['user'] = $total; 287 | 288 | return $counts; 289 | } 290 | } 291 | 292 | -------------------------------------------------------------------------------- /admin.php: -------------------------------------------------------------------------------- 1 | textdomain = 'wp-useronline'; 7 | 8 | $this->args = array( 9 | 'page_title' => __( 'Users Online Now', $this->textdomain ), 10 | 'menu_title' => __( 'WP-UserOnline', $this->textdomain ), 11 | 'page_slug' => 'useronline', 12 | 'parent' => 'index.php', 13 | 'action_link' => false, 14 | 'capability' => 'list_users', 15 | ); 16 | 17 | add_action( 'rightnow_end', array( $this, 'rightnow' ) ); 18 | } 19 | 20 | function rightnow() { 21 | if ( !current_user_can( 'manage_options' ) ) 22 | return; 23 | 24 | $total_users = get_users_online_count(); 25 | 26 | $str = _n( 27 | "There is %s user online now.", 28 | "There are a total of %s users online now.", 29 | $total_users, 'wp-useronline' 30 | ); 31 | 32 | $out = sprintf( $str, add_query_arg( 'page', $this->args['page_slug'], admin_url( 'index.php' ) ), number_format_i18n( $total_users ) ); 33 | $out .= '
'; 34 | 35 | if ( $tmp = get_users_browsing_site() ) 36 | $out .= $tmp . '
'; 37 | 38 | $out .= UserOnline_Template::format_most_users(); 39 | 40 | echo html( 'p', $out ); 41 | } 42 | 43 | function page_content() { 44 | echo users_online_page(); 45 | } 46 | } 47 | 48 | 49 | class UserOnline_Options extends scbAdminPage { 50 | 51 | public function setup() { 52 | $this->textdomain = 'wp-useronline'; 53 | 54 | $this->args = array( 55 | 'page_title' => __( 'UserOnline Options', $this->textdomain ), 56 | 'menu_title' => __( 'UserOnline', $this->textdomain ), 57 | 'page_slug' => 'useronline-settings', 58 | ); 59 | 60 | $this->option_name = 'useronline'; 61 | } 62 | 63 | public function validate( $options, $old_data = array() ) { 64 | $options['timeout'] = isset( $options['timeout'] ) ? absint( $options['timeout'] ) : 0; 65 | $options['url'] = ! empty( $options['url'] ) ? esc_url_raw( trim( $options['url'] ) ) : ''; 66 | $options['names'] = ! empty( $options['names'] ) ? (int) $options['names'] : 0; 67 | 68 | foreach ( $options['naming'] as $key => $template ) { 69 | $options['naming'][$key] = wp_kses_post( trim( $template ) ); 70 | } 71 | foreach ( $options['templates'] as $key => $template ) { 72 | if ( is_array( $template ) ) { 73 | $options['templates'][$key]['text'] = wp_kses_post( trim( $template['text'] ) ); 74 | if ( ! empty( $template['separators'] ) && is_array( $template['separators'] ) ) { 75 | foreach( $template['separators'] as $seperator_key => $seperator_value ) { 76 | $options['templates'][$key]['separators'][$seperator_key] = wp_kses_post( trim( $seperator_value ) ); 77 | } 78 | } 79 | } else { 80 | $options['templates'][$key] = wp_kses_post( trim( $template ) ); 81 | } 82 | } 83 | 84 | return $options; 85 | } 86 | 87 | public function page_head() { 88 | ?> 89 | 95 | 96 | 109 | options->get(); 114 | $defaults = $this->options->get_defaults(); 115 | 116 | ?> 117 |
118 | nonce ); ?> 119 | 120 | __( 'Time Out', 'wp-useronline' ), 124 | 'type' => 'text', 125 | 'name' => 'timeout', 126 | 'desc' => '
' . __( 'How long until it will remove the user from the database (in seconds).', 'wp-useronline' ), 127 | 'extra' => 'size="4"' 128 | ), 129 | 130 | array( 131 | 'title' => __( 'UserOnline URL', 'wp-useronline' ), 132 | 'type' => 'text', 133 | 'name' => 'url', 134 | 'desc' => '
' . __( 'URL To UserOnline Page
Example: http://www.yoursite.com/useronline/
Example: http://www.yoursite.com/?page_id=2', 'wp-useronline' ), 135 | ), 136 | 137 | array( 138 | 'title' => __( 'Link user names?', 'wp-useronline' ), 139 | 'type' => 'radio', 140 | 'name' => 'names', 141 | 'choices' => array( 1 => __( 'Yes', 'wp-useronline' ), 0 => __( 'No', 'wp-useronline' ) ), 142 | 'desc' => '
' . __( 'Link user names to their author page', 'wp-useronline' ) 143 | ), 144 | ); 145 | 146 | foreach ( $rows as $row ) { 147 | echo $this->table_row( $row ); 148 | } 149 | 150 | ?> 151 | 152 | naming_table( $defaults ); ?> 153 | 154 | 155 | 156 | naming_table( $options ); ?> 157 | 158 | 159 |
160 | 161 |

162 | 163 | 164 | useronline_template_table( $defaults ); ?> 165 | 166 | 167 | 168 | useronline_template_table( $options ); ?> 169 | 170 | 171 | __( 'User(s) Browsing Site:', 'wp-useronline' ), 174 | 'browsingpage' => __( 'User(s) Browsing Page:', 'wp-useronline' ), 175 | ); 176 | foreach ( $templates as $name => $title ) { ?> 177 | 178 | template_table( $title, $name, $defaults ); ?> 179 | 180 | 181 | 182 | template_table( $title, $name, $options ); ?> 183 | 184 | 185 |
186 |

187 | 188 |

189 |
190 | 195 | 196 | 197 |

198 |
199 | - %COUNT%

200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | \n"; 214 | foreach ( array( $tmp, $tmp . 's' ) as $type ) { 215 | echo $this->input( array( 216 | 'type' => 'text', 217 | 'name' => array( 'naming', $type ), 218 | 'extra' => 'size="30"', 219 | 'desc' => html( 'td', $type ) 220 | ), $data ); 221 | } 222 | echo "\n\n"; 223 | } 224 | ?> 225 | 226 |
227 |
228 | 229 | 230 | 235 | 236 | 237 |

238 |
239 | - %USERS%
240 | - %PAGE_URL%
241 | - %MOSTONLINE_COUNT%
242 | - %MOSTONLINE_DATE%

243 | 244 | 245 | 246 | input( array( 247 | 'type' => 'textarea', 248 | 'name' => array( 'templates', 'useronline' ), 249 | ), $data ); ?> 250 | 251 | 252 | 257 | 258 | 259 |

260 |
261 | - %USERS%
262 | - %MEMBERS%
263 | - %MEMBER_NAMES%
264 | - %GUESTS_SEPARATOR%
265 | - %GUESTS%
266 | - %BOTS_SEPARATOR%
267 | - %BOTS%

268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | options->templates[$option]['separators'] ) as $type ) { 281 | echo html( 'td', $this->input( array( 282 | 'type' => 'text', 283 | 'name' => array( 'templates', $option, 'separators', $type ), 284 | 'extra' => "size='15'", 285 | ), $data ) ); 286 | } ?> 287 | 288 |
289 |
290 | input( array( 291 | 'type' => 'textarea', 292 | 'name' => array( 'templates', $option, 'text' ) 293 | ), $data ); ?> 294 | 295 | 296 |