10-21-2025, 10:43 PM
Go to inc/plugins > nudge.php
PHP Code:
<?php
/**
* WORKS WITHOUT MYALERTS
* Uses correct template variable method per MyBB documentation
*/
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.");
}
function nudge_info()
{
return array(
"name" => "Nudge System",
"description" => "Nudge users with scrolling tab title notification + PM",
"website" => "https://bbmodz.com",
"author" => "BBModz",
"authorsite" => "https://bbmodz.com",
"version" => "5.0",
"guid" => "",
"codename" => "nudge",
"compatibility" => "18*"
);
}
function nudge_install()
{
global $db;
$db->write_query("CREATE TABLE IF NOT EXISTS ".TABLE_PREFIX."nudges (
nid int unsigned NOT NULL auto_increment,
sender_uid int unsigned NOT NULL,
receiver_uid int unsigned NOT NULL,
dateline int unsigned NOT NULL,
PRIMARY KEY (nid),
KEY receiver_uid (receiver_uid)
) ENGINE=MyISAM");
$setting_group = array(
'name' => 'nudge',
'title' => 'Nudge System Settings',
'description' => 'Settings for the nudge system',
'disporder' => 1,
'isdefault' => 0
);
$gid = $db->insert_query("settinggroups", $setting_group);
$settings = array(
'nudge_enabled' => array(
'title' => 'Enable Nudge System',
'description' => 'Enable or disable the nudge system',
'optionscode' => 'yesno',
'value' => '1',
'disporder' => 1
),
'nudge_cooldown' => array(
'title' => 'Nudge Cooldown (seconds)',
'description' => 'Time users must wait between sending nudges',
'optionscode' => 'numeric',
'value' => '30',
'disporder' => 2
),
'nudge_pm_enabled' => array(
'title' => 'Enable PM Notification',
'description' => 'Send a PM when someone is nudged',
'optionscode' => 'yesno',
'value' => '1',
'disporder' => 3
)
);
foreach($settings as $name => $setting)
{
$setting['name'] = $name;
$setting['gid'] = $gid;
$db->insert_query('settings', $setting);
}
rebuild_settings();
}
function nudge_is_installed()
{
global $db;
return $db->table_exists("nudges");
}
function nudge_uninstall()
{
global $db;
$db->delete_query("settings", "name IN ('nudge_enabled', 'nudge_cooldown', 'nudge_pm_enabled')");
$db->delete_query("settinggroups", "name = 'nudge'");
$db->drop_table("nudges");
rebuild_settings();
}
function nudge_activate()
{
global $db;
require_once MYBB_ROOT."/inc/adminfunctions_templates.php";
// Create nudge button template
$template = '<div class="nudge_button_container" style="margin: 15px 0; text-align: center;">
<a href="misc.php?action=nudge&uid={$memprofile[\'uid\']}" class="button" style="background: linear-gradient(135deg, #00ff00 0%, #00cc00 100%); border: 2px solid #00ff00; color: #0a0a0a; padding: 12px 25px; border-radius: 5px; font-weight: bold; text-decoration: none; display: inline-block; box-shadow: 0 0 15px rgba(0, 255, 0, 0.6);">
<span style="font-size: 1.2em;">👋</span> Nudge {$memprofile[\'username\']}
</a>
</div>';
$insert_array = array(
'title' => 'member_profile_nudge',
'template' => $db->escape_string($template),
'sid' => '-1',
'version' => '',
'dateline' => TIME_NOW
);
$db->insert_query("templates", $insert_array);
// Add nudge button to profile
find_replace_templatesets("member_profile", "#".preg_quote('{$warning_level}')."#", '{$warning_level}{$nudge_button}');
// THE KEY FIX: Add {$nudge_system_js} variable to headerinclude template
find_replace_templatesets("headerinclude", "#".preg_quote('{$stylesheets}')."#", '{$stylesheets}{$nudge_system_js}');
}
function nudge_deactivate()
{
global $db;
require_once MYBB_ROOT."/inc/adminfunctions_templates.php";
$db->delete_query("templates", "title = 'member_profile_nudge'");
find_replace_templatesets("member_profile", "#".preg_quote('{$nudge_button}')."#", '', 0);
// Remove {$nudge_system_js} variable from headerinclude
find_replace_templatesets("headerinclude", "#".preg_quote('{$nudge_system_js}')."#", '', 0);
}
// Add hooks
$plugins->add_hook("member_profile_end", "nudge_profile_button");
$plugins->add_hook("misc_start", "nudge_process");
$plugins->add_hook("misc_start", "nudge_ajax_check");
$plugins->add_hook("global_start", "nudge_load_javascript");
function nudge_profile_button()
{
global $mybb, $templates, $nudge_button, $memprofile;
if($mybb->settings['nudge_enabled'] != 1 || !$mybb->user['uid'] || $mybb->user['uid'] == $memprofile['uid'])
{
return;
}
eval("\$nudge_button = \"".$templates->get("member_profile_nudge")."\";");
}
function nudge_process()
{
global $mybb, $db;
if($mybb->get_input('action') != 'nudge')
{
return;
}
if(!$mybb->user['uid'])
{
error_no_permission();
}
$receiver_uid = $mybb->get_input('uid', MyBB::INPUT_INT);
if(!$receiver_uid || $receiver_uid == $mybb->user['uid'])
{
error("Invalid user specified.");
}
// Check cooldown
$query = $db->simple_select("nudges", "*", "sender_uid='".$mybb->user['uid']."' AND receiver_uid='".$receiver_uid."'", array("order_by" => "dateline", "order_dir" => "DESC", "limit" => 1));
$last_nudge = $db->fetch_array($query);
if($last_nudge && (TIME_NOW - $last_nudge['dateline']) < $mybb->settings['nudge_cooldown'])
{
$wait_time = $mybb->settings['nudge_cooldown'] - (TIME_NOW - $last_nudge['dateline']);
error("Please wait {$wait_time} seconds before sending another nudge!");
}
// Insert nudge
$insert_array = array(
'sender_uid' => $mybb->user['uid'],
'receiver_uid' => $receiver_uid,
'dateline' => TIME_NOW
);
$db->insert_query("nudges", $insert_array);
// Send PM
if($mybb->settings['nudge_pm_enabled'] == 1)
{
require_once MYBB_ROOT."inc/datahandlers/pm.php";
$pmhandler = new PMDataHandler();
$pm = array(
"subject" => "You've been nudged!",
"message" => "[b]{$mybb->user['username']}[/b] just nudged you!\n\n[color=#00ff00]Hey Hit Me Up <3[/color]\n\n[url={$mybb->settings['bburl']}/member.php?action=profile&uid={$mybb->user['uid']}]View their profile[/url]",
"icon" => 0,
"fromid" => $mybb->user['uid'],
"toid" => array($receiver_uid),
"ipaddress" => $mybb->session->packedip,
"do" => '',
"pmid" => '',
"saveasdraft" => 0,
"options" => array(
"signature" => 0,
"disablesmilies" => 0,
"savecopy" => 0,
"readreceipt" => 0
)
);
$pmhandler->set_data($pm);
if($pmhandler->validate_pm())
{
$pmhandler->insert_pm();
}
}
redirect("member.php?action=profile&uid=".$receiver_uid, "Nudge sent successfully!");
}
function nudge_ajax_check()
{
global $mybb, $db;
if($mybb->get_input('action') != 'check_nudge')
{
return;
}
header('Content-Type: application/json');
if(!$mybb->user['uid'])
{
echo json_encode(array('nudged' => false));
exit;
}
// Check for nudges
$query = $db->simple_select("nudges", "*", "receiver_uid='".$mybb->user['uid']."' AND dateline > ".(TIME_NOW - 5), array("order_by" => "dateline", "order_dir" => "DESC", "limit" => 1));
$nudge = $db->fetch_array($query);
if($nudge)
{
$sender = get_user($nudge['sender_uid']);
$db->delete_query("nudges", "nid='".$nudge['nid']."'");
echo json_encode(array(
'nudged' => true,
'sender' => htmlspecialchars_uni($sender['username']),
'uid' => $mybb->user['uid']
));
exit;
}
echo json_encode(array('nudged' => false));
exit;
}
// THIS IS THE KEY FUNCTION - Sets the JavaScript variable that was inserted into headerinclude template
function nudge_load_javascript()
{
global $mybb, $nudge_system_js;
// Only load for logged in users when nudge is enabled
if(!$mybb->user['uid'] || $mybb->settings['nudge_enabled'] != 1)
{
$nudge_system_js = '';
return;
}
// Build the JavaScript as a string
$nudge_system_js = '<style>
.nudge-message {
position: fixed !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
background: rgba(0, 0, 0, 0.95) !important;
border: 5px solid #00ff00 !important;
padding: 40px 60px !important;
border-radius: 15px !important;
z-index: 999999 !important;
box-shadow: 0 0 100px rgba(0, 255, 0, 1) !important;
}
.nudge-message h1 {
color: #00ff00 !important;
font-size: 3em !important;
margin: 0 !important;
text-align: center !important;
text-shadow: 0 0 30px rgba(0, 255, 0, 1) !important;
font-family: Arial, sans-serif !important;
animation: pulse 1s ease-in-out infinite !important;
}
.nudge-message p {
color: #00ff00 !important;
font-size: 1.3em !important;
margin: 15px 0 0 0 !important;
text-align: center !important;
font-family: Arial, sans-serif !important;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
</style>
<script type="text/javascript">
// NUDGE SYSTEM v5.0 - User ID: '.$mybb->user['uid'].'
console.log("[NUDGE] System loaded for UID: '.$mybb->user['uid'].'");
(function() {
var userID = '.$mybb->user['uid'].';
var checkInterval;
var soundEnabled = false;
var audioContext = null;
// Enable sound on any interaction
document.addEventListener("click", function() {
if(!soundEnabled) {
try {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
soundEnabled = true;
console.log("[NUDGE] Sound enabled");
} catch(e) {
console.log("[NUDGE] Sound failed:", e);
}
}
}, {once: true});
function playSound() {
if(!soundEnabled || !audioContext) return;
try {
for(var i = 0; i < 3; i++) {
setTimeout(function() {
var osc = audioContext.createOscillator();
var gain = audioContext.createGain();
osc.connect(gain);
gain.connect(audioContext.destination);
osc.frequency.value = 800;
osc.type = "square";
gain.gain.setValueAtTime(0.3, audioContext.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.2);
osc.start(audioContext.currentTime);
osc.stop(audioContext.currentTime + 0.2);
}, i * 200);
}
} catch(e) {
console.log("[NUDGE] Sound play error:", e);
}
}
function doNudgeNotification(sender) {
console.log("[NUDGE] *** NUDGED BY:", sender, "***");
// Save original title
var originalTitle = document.title;
var scrollText = "👋👋👋 NUDGE BY " + sender.toUpperCase() + " 👋👋👋 ";
var position = 0;
var flashCount = 0;
var maxFlashes = 30;
// Scrolling title animation
var titleInterval = setInterval(function() {
if(flashCount >= maxFlashes) {
document.title = originalTitle;
clearInterval(titleInterval);
return;
}
var displayText = scrollText.substring(position) + scrollText.substring(0, position);
document.title = displayText.substring(0, 50);
position++;
if(position >= scrollText.length) {
position = 0;
flashCount++;
}
}, 200);
// Show popup
var message = document.createElement("div");
message.className = "nudge-message";
message.innerHTML = "<h1>👋 " + sender + " NUDGED YOU! 👋</h1><p>Check your messages! 💚</p>";
document.body.appendChild(message);
// Play sound
playSound();
// Vibrate
if(navigator.vibrate) {
navigator.vibrate([300, 100, 300, 100, 300]);
}
// Remove popup after 5 seconds
setTimeout(function() {
if(message.parentNode) {
message.style.opacity = "0";
message.style.transition = "opacity 0.5s";
setTimeout(function() {
if(message.parentNode) {
message.parentNode.removeChild(message);
}
}, 500);
}
}, 5000);
// Click to stop
var clickHandler = function() {
document.title = originalTitle;
clearInterval(titleInterval);
document.removeEventListener("click", clickHandler);
};
document.addEventListener("click", clickHandler);
}
function checkNudge() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "misc.php?action=check_nudge&t=" + Date.now(), true);
xhr.onload = function() {
if(xhr.status === 200) {
try {
var data = JSON.parse(xhr.responseText);
console.log("[NUDGE] Check:", data);
if(data.nudged) {
doNudgeNotification(data.sender);
}
} catch(e) {
console.log("[NUDGE] Parse error:", e);
}
}
};
xhr.onerror = function() {
console.log("[NUDGE] Request failed");
};
xhr.send();
}
// Start checking
console.log("[NUDGE] Starting checks every 2 seconds");
checkNudge();
checkInterval = setInterval(checkNudge, 2000);
window.addEventListener("beforeunload", function() {
if(checkInterval) clearInterval(checkInterval);
});
})();
</script>';
}
?>