2025-04-22, 03:22 PM
<?php
/**
* MyBB Plugin: Thread Viewers & Visit Counter
* Author: CreativeDev
* Website: https://example.com
* License: GPLv3
* Version: 1.1
* Description: Shows a list of users who viewed the thread along with their personal view counts and profile links.
*/
if (!defined('IN_MYBB')) {
die('Direct initialization of this file is not allowed.');
}
/**
* Plugin info (must match filename 'thread_viewers.php')
*/
function thread_viewers_info()
{
return [
'name' => 'Thread Viewers & Visit Counter',
'description' => 'Displays users who viewed a thread, their individual view counts, and profile links.',
'website' => 'https://example.com',
'author' => 'CreativeDev',
'authorsite' => 'https://example.com',
'version' => '1.1',
'compatibility' => '18*'
];
}
// Register hooks (global scope)
$plugins->add_hook('install', 'thread_viewers_install');
$plugins->add_hook('uninstall', 'thread_viewers_uninstall');
$plugins->add_hook('showthread_start', 'thread_viewers_track_view');
// Display before the first post (between forum header and posts)
$plugins->add_hook('showthread_start', 'thread_viewers_display');
$plugins->add_hook('template_global_end', 'thread_viewers_css');
/**
* Install: create table
*/
function thread_viewers_install()
{
global $db;
if (!$db->table_exists('thread_viewers')) {
$collation = $db->build_create_table_collation();
$db->query(
"CREATE TABLE `{$db->table_prefix}thread_viewers` (
`tid` INT(10) UNSIGNED NOT NULL,
`uid` INT(10) UNSIGNED NOT NULL,
`username` VARCHAR(120) NOT NULL,
`views` INT(10) UNSIGNED NOT NULL DEFAULT 1,
`last_view` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`tid`, `uid`)
) ENGINE=MyISAM {$collation};"
);
}
}
/**
* Uninstall: drop table
*/
function thread_viewers_uninstall()
{
global $db;
if ($db->table_exists('thread_viewers')) {
$db->drop_table('thread_viewers');
}
}
/**
* Track views per user
* Auto-creates table if missing
*/
function thread_viewers_track_view()
{
global $db, $thread, $mybb;
$tid = intval($thread['tid']);
$uid = intval($mybb->user['uid']);
if ($tid <= 0 || $uid <= 0) {
return;
}
if (!$db->table_exists('thread_viewers')) {
thread_viewers_install();
}
$time = TIME_NOW;
$existing = $db->simple_select('thread_viewers', 'views', "tid={$tid} AND uid={$uid}");
if ($db->num_rows($existing) > 0) {
$db->update_query(
'thread_viewers',
['views' => 'views + 1', 'last_view' => $time],
"tid={$tid} AND uid={$uid}",
'',
true
);
} else {
$db->insert_query('thread_viewers', [
'tid' => $tid,
'uid' => $uid,
'username' => $db->escape_string($mybb->user['username']),
'views' => 1,
'last_view' => $time
]);
}
}
/**
* Display viewers list before posts
*/
function thread_viewers_display()
{
global $db, $thread, $mybb;
$tid = intval($thread['tid']);
if ($tid <= 0 || !$db->table_exists('thread_viewers')) {
return;
}
// Fetch top 10 viewers with UID, username, views
$query = $db->query(
"SELECT uid, username, views FROM {$db->table_prefix}thread_viewers WHERE tid={$tid} ORDER BY views DESC, last_view DESC LIMIT 10"
);
$viewers = [];
while ($row = $db->fetch_array($query)) {
$uid_row = intval($row['uid']);
$views_text = intval($row['views']) . ' view' . ($row['views'] > 1 ? 's' : '');
$profile_url = $mybb->settings['bburl'] . "/member.php?action=profile&uid={$uid_row}";
$viewers[] = '<li><a href="' . $profile_url . '" target="_blank"><strong>' .
htmlspecialchars_uni($row['username']) . '</strong></a>: ' . $views_text . '</li>';
}
if (!empty($viewers)) {
echo '<div class="thread-viewers-box">'
. '<h3>Top Viewers</h3>'
. '<ul>' . implode('', $viewers) . '</ul>'
. '</div>';
}
}
/**
* Inject CSS
*/
function thread_viewers_css()
{
echo "<style>
.thread-viewers-box { margin:20px 0; padding:15px; background:#f9f9f9; border:1px solid #ddd; border-radius:5px; }
.thread-viewers-box h3 { margin:0 0 10px; font-size:1.1em; }
.thread-viewers-box ul { list-style:none; margin:0; padding:0; }
.thread-viewers-box li { margin-bottom:5px; }
.thread-viewers-box li a { text-decoration:none; }
.thread-viewers-box li a:hover { text-decoration:underline; }
</style>";
}
?>