Here's a more complete fix that I have briefly tested. It changes the 'you have no unread posts' text to 'view your unread posts' even if the only unread posts are global announcements, and it now allows the user to mark a global announcement as unread. It is still true that if the only unread posts you have are global announcements, none of the forums on the index are marked as unread, but that's because that is the regular behaviour of phpbb3 and if you want a different result you should install a mod for that (note that there is a mod by barrycarlyon (
) that in fact allows you to put global announcements on the index page, thereby fixing the problem).
Please keep in mind that the fixes below require an extra db query and therefore might slow up a really big board to some extent.
Code: Select all
#
#-----[ OPEN ]------------------------------------------
#
includes/functions_view_or_mark_unread_posts.php
#
#-----[ FIND ]------------------------------------------
#
/**
* checks to see if the user has any unread posts in the forum
* (returns true if there are unread posts and false if there are not)
*/
function check_unread_posts()
#
#-----[ BEFORE, ADD ]------------------------------------------
#
/**
* checks to see if the user has any unread global announcements in the forum
* (returns true if there are unread posts and false if there are not)
*/
function check_unread_global_announcements()
{
global $db, $user;
// test to see if there are any unread global announcements (note that running this block of code
// triggers an extra db query so people with large borads may want to comment the block out)
$sql = 'SELECT t.topic_id
FROM ' . TOPICS_TABLE . ' t
LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (t.forum_id = 0 AND t.topic_id = tt.topic_id AND tt.user_id = ' . $user->data['user_id'] . ')
WHERE
(
t.topic_last_post_time > tt.mark_time
OR (tt.mark_time IS NULL AND t.topic_last_post_time > ' . $user->data['user_lastmark'] . ')
)
AND t.topic_moved_id = 0';
$result = $db->sql_query_limit($sql,1);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (isset($row['topic_id']))
{
// if we get here, the user has at least one unread global announcement
return true;
}
// if we get here, the user has no unread global announcements
return false;
}
#
#-----[ FIND ]------------------------------------------
#
// functions_display has already been called (user is on index) but there are no unreads
#
#-----[ AFTER, ADD ]------------------------------------------
#
// let's check to see if any unread global announcements before concluding there are no unreads
if (check_unread_global_announcements())
{
// user has at least one unread global announcement, so return true
return true;
}
// user has no unreads and no unread global announcements, so return false
#
#-----[ FIND ]------------------------------------------
#
// if we get here, we've been through all forums for this user and none have unread posts, so return false
#
#-----[ REPLACE WITH ]------------------------------------------
#
// if we get here, we've been through all forums for this user and none have unread posts
// let's check to see if any unread global announcements before concluding there are no unreads
if (check_unread_global_announcements())
{
// user has at least one unread global announcement, so return true
return true;
}
// user has no unreads and no unread global announcements, so return false
#
#-----[ FIND ]------------------------------------------
#
// Only proceed if the post, topic and forum exist and the user is allowed to read it
if (!$topic_id || !$forum_id || !$auth->acl_get('f_read', $forum_id))
{
trigger_error('NO_TOPIC');
}
#
#-----[ REPLACE WITH ]------------------------------------------
#
// Only proceed if the post and topic exist and the forum_id is 0 (global announcments) or the user is allowed to read it;
// so, trigger an error if (a) topic does not exist or (b) forum_id is not 0 and user is not allowed to read it
if (!$topic_id || ($forum_id && !$auth->acl_get('f_read', $forum_id)))
{
trigger_error('NO_TOPIC');
}
#
#-----[ FIND ]------------------------------------------
#
// now, tinker with the forums_track and topics_track tables in accorance with these rules:
//
// - calculate the forum_tracking_info time using the method that appears in display_forums();
//
// - if a post being marked unread has a post time less than the
// forum_tracking_info, then add a new topics_track entry
// (with mark_time = forum_tracking_info before it gets changed)
// for each other topic in the forum that meets all of the following tests:
//
// 1. does not already have a topics_track entry for the user and
//
// 2. has a last post time less than or equal to the then current forum_tracking_info mark_time
//
// 3. has a last post time greater than the new $mark_time that will be used for the forums_track table
//
// - update or insert a forums_track mark_time to the time of the post minus 1
//
// - make sure that user's forums_track mark_time for forum 0 is the max of all
// mark_times for that user in the forums track table
// first step, calculate the forum_tracking_info (most of the code is adapted from display_forums() in functions_display.php)
$sql = 'SELECT mark_time
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id = ' . $forum_id . '
AND user_id = ' . $user->data['user_id'];
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$forum_tracking_info = (!empty($row['mark_time'])) ? $row['mark_time'] : $user->data['user_lastmark'];
// next, check to see if the post being marked unread has a post_time before $forum_tracking _info
if ($post_time < $forum_tracking_info )
{
// ok, post being marked unread has post time before $forum_tracking_info, so we will
// need to create special topics_track entries for all topics that
// meet the three tests described in the comment that appears before the $sql definition above
// (since these are the topics that are currently considered 'read' and would otherwise
// no longer be considered read when we change the forums_track entry to an earlier mark_time
// later in the script)
// so, fetch the topic_ids for the topics in this forum that meet the three tests
$sql = 'SELECT t.topic_id, t.topic_last_post_time, tt.mark_time
FROM ' . TOPICS_TABLE . ' t
LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (t.topic_id = tt.topic_id AND tt.user_id = ' . $user->data['user_id'] . ')
WHERE tt.mark_time IS NULL
AND t.forum_id = ' . $forum_id . '
AND t.topic_last_post_time <= ' . $forum_tracking_info . '
AND t.topic_last_post_time > ' . $mark_time;
$result = $db->sql_query($sql);
while($row = $db->sql_fetchrow($result))
{
// for each of the topics meeting the three tests, create a topics_track entry
$sql = 'INSERT INTO ' . TOPICS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => $user->data['user_id'],
'topic_id' => $row['topic_id'],
'forum_id' => $forum_id,
'mark_time' => $forum_tracking_info,
));
$db->sql_query($sql);
}
$db->sql_freeresult($result);
// finally, move the forums_track time back to $mark_time by inserting or updating the relevant row
// to do that, find out if there already is an entry for this user_id and forum_id
$sql = 'SELECT forum_id
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id = ' . $forum_id . '
AND user_id = ' . $user->data['user_id'];
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (isset($row['forum_id']))
{
// in this case there is already an entry for this user and forum_id
// in the forums_track table, so update the entry for the forum_id
$sql = 'UPDATE ' . FORUMS_TRACK_TABLE . '
SET mark_time = ' . $mark_time . '
WHERE forum_id = ' . $forum_id . '
AND user_id = ' . $user->data['user_id'];
$db->sql_query($sql);
}
else
{
// in this case there is no entry for this user and forum_id
// in the forums_track table, so insert one
$sql = 'INSERT INTO ' . FORUMS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => $user->data['user_id'],
'forum_id' => $forum_id,
'mark_time' => $mark_time,
));
$db->sql_query($sql);
}
// find out if there already is an entry for this user_id and forum_id of 0
$sql = 'SELECT forum_id
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id = 0
AND user_id = ' . $user->data['user_id'];
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (isset($row['forum_id']))
{
// in this case there is already an entry for this user and forum_id of 0
// in the forums_track table, so update the entry to whatever the max mark time
// is for the user in the forum_tracks table
$sql = 'SELECT mark_time
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id != 0
AND user_id = ' . $user->data['user_id'] . '
ORDER BY mark_time DESC';
$result = $db->sql_query_limit($sql,1);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$sql = 'UPDATE ' . FORUMS_TRACK_TABLE . '
SET mark_time = ' . $row['mark_time'] . '
WHERE forum_id = 0
AND user_id = ' . $user->data['user_id'];
$db->sql_query($sql);
}
else
{
// in this case there is no entry for this user and forum_id of 0
// in the forums_track table, so insert one with the new $mark_time
$sql = 'INSERT INTO ' . FORUMS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => $user->data['user_id'],
'forum_id' => 0,
'mark_time' => $mark_time,
));
$db->sql_query($sql);
}
}
$meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
meta_refresh(3, $meta_info);
$message = $user->lang['POST_MARKED_UNREAD'] . '<br /><br />';
$message .= sprintf($user->lang['RETURN_FORUM'], '<a href="' . $meta_info . '">', '</a>') . '<br /><br />';
$message .= sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
trigger_error($message);
#
#-----[ REPLACE WITH ]------------------------------------------
#
// if $forum_id is not zero (so this is not a global announcement), continue with the code below that deals with
// resettting the forums_track table and then gives user a screen allowing him to redirect to forum or index;
// but if $forum_id is zero, this is a global announcement so skip the forums_track code and allow user only to
// redirect to the index
if ($forum_id)
{
// now, tinker with the forums_track and topics_track tables in accorance with these rules:
//
// - calculate the forum_tracking_info time using the method that appears in display_forums();
//
// - if a post being marked unread has a post time less than the
// forum_tracking_info, then add a new topics_track entry
// (with mark_time = forum_tracking_info before it gets changed)
// for each other topic in the forum that meets all of the following tests:
//
// 1. does not already have a topics_track entry for the user and
//
// 2. has a last post time less than or equal to the then current forum_tracking_info mark_time
//
// 3. has a last post time greater than the new $mark_time that will be used for the forums_track table
//
// - update or insert a forums_track mark_time to the time of the post minus 1
//
// - make sure that user's forums_track mark_time for forum 0 is the max of all
// mark_times for that user in the forums track table
// first step, calculate the forum_tracking_info (most of the code is adapted from display_forums() in functions_display.php)
$sql = 'SELECT mark_time
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id = ' . $forum_id . '
AND user_id = ' . $user->data['user_id'];
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$forum_tracking_info = (!empty($row['mark_time'])) ? $row['mark_time'] : $user->data['user_lastmark'];
// next, check to see if the post being marked unread has a post_time before $forum_tracking _info
if ($post_time < $forum_tracking_info )
{
// ok, post being marked unread has post time before $forum_tracking_info, so we will
// need to create special topics_track entries for all topics that
// meet the three tests described in the comment that appears before the $sql definition above
// (since these are the topics that are currently considered 'read' and would otherwise
// no longer be considered read when we change the forums_track entry to an earlier mark_time
// later in the script)
// so, fetch the topic_ids for the topics in this forum that meet the three tests
$sql = 'SELECT t.topic_id, t.topic_last_post_time, tt.mark_time
FROM ' . TOPICS_TABLE . ' t
LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (t.topic_id = tt.topic_id AND tt.user_id = ' . $user->data['user_id'] . ')
WHERE tt.mark_time IS NULL
AND t.forum_id = ' . $forum_id . '
AND t.topic_last_post_time <= ' . $forum_tracking_info . '
AND t.topic_last_post_time > ' . $mark_time;
$result = $db->sql_query($sql);
while($row = $db->sql_fetchrow($result))
{
// for each of the topics meeting the three tests, create a topics_track entry
$sql = 'INSERT INTO ' . TOPICS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => $user->data['user_id'],
'topic_id' => $row['topic_id'],
'forum_id' => $forum_id,
'mark_time' => $forum_tracking_info,
));
$db->sql_query($sql);
}
$db->sql_freeresult($result);
// finally, move the forums_track time back to $mark_time by inserting or updating the relevant row
// to do that, find out if there already is an entry for this user_id and forum_id
$sql = 'SELECT forum_id
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id = ' . $forum_id . '
AND user_id = ' . $user->data['user_id'];
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (isset($row['forum_id']))
{
// in this case there is already an entry for this user and forum_id
// in the forums_track table, so update the entry for the forum_id
$sql = 'UPDATE ' . FORUMS_TRACK_TABLE . '
SET mark_time = ' . $mark_time . '
WHERE forum_id = ' . $forum_id . '
AND user_id = ' . $user->data['user_id'];
$db->sql_query($sql);
}
else
{
// in this case there is no entry for this user and forum_id
// in the forums_track table, so insert one
$sql = 'INSERT INTO ' . FORUMS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => $user->data['user_id'],
'forum_id' => $forum_id,
'mark_time' => $mark_time,
));
$db->sql_query($sql);
}
// find out if there already is an entry for this user_id and forum_id of 0
$sql = 'SELECT forum_id
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id = 0
AND user_id = ' . $user->data['user_id'];
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (isset($row['forum_id']))
{
// in this case there is already an entry for this user and forum_id of 0
// in the forums_track table, so update the entry to whatever the max mark time
// is for the user in the forum_tracks table
$sql = 'SELECT mark_time
FROM ' . FORUMS_TRACK_TABLE . '
WHERE forum_id != 0
AND user_id = ' . $user->data['user_id'] . '
ORDER BY mark_time DESC';
$result = $db->sql_query_limit($sql,1);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$sql = 'UPDATE ' . FORUMS_TRACK_TABLE . '
SET mark_time = ' . $row['mark_time'] . '
WHERE forum_id = 0
AND user_id = ' . $user->data['user_id'];
$db->sql_query($sql);
}
else
{
// in this case there is no entry for this user and forum_id of 0
// in the forums_track table, so insert one with the new $mark_time
$sql = 'INSERT INTO ' . FORUMS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => $user->data['user_id'],
'forum_id' => 0,
'mark_time' => $mark_time,
));
$db->sql_query($sql);
}
}
$meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
meta_refresh(3, $meta_info);
$message = $user->lang['POST_MARKED_UNREAD'] . '<br /><br />';
$message .= sprintf($user->lang['RETURN_FORUM'], '<a href="' . $meta_info . '">', '</a>') . '<br /><br />';
$message .= sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
trigger_error($message);
}
// if we get here, $forum_id is 0 (global announcement), so redirect to index
$meta_info = append_sid("{$phpbb_root_path}index.$phpEx", 'f=' . $forum_id);
meta_refresh(3, $meta_info);
$message = $user->lang['POST_MARKED_UNREAD'] . '<br /><br />';
$message .= sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
trigger_error($message);