Fórum PunBB sice používá zvýrazňování témat s nepřečtenými příspěvky. To ale není prakticky použitelné. Jednak proto, že se označují pouze nepřečtená témata a nikoliv i příspěvky. A jednak proto, že označování nepracuje tak, jak by to člověk očekával.

Funguje totiž tak, že se do databáze uloží čas poslední návštěvy uživatele a s tímto časem se pak porovnává čas posledního příspěvku v tématu. Tím se zjístí, která támata se mají zvýraznit. Problém však je, že témata zůstanou zvýrazněná i po přečtení. K odznačení zvýraznění dojde teprve po vypršení určité doby(nastavuje administrátor), kdy se do databázové tabulky uživatele uloží aktuální čas jako čas poslední návštěvy. Po vypršení zmiňované doby dojde tedy k odznačení všech příspěvků, tedy i těch, které si člověk nestihl přečíst.

Řešit se to dá nastavním nesmyslně dlouhé prodlevy. Uživatelé pak mohou označit všechny příspěvky jako přečtené kliknutím na odkaz k tomu určený.

Tento článek rozebírá možnost jak upravit punBB fórum, aby zvýrazňovalo skutečně nepřečtená témata a navíc zvýraznilo i nepřečtené příspěvky v tématu.


Poznámka:
Tato úprava je testována a funkční v punBB fóru verze 1.2.15

Abychom toho dosáhli budeme potřebovat novou databázovou tabulku:

SQL:
CREATE TABLE `notread` (
  `id` int(10) NOT NULL,
  `id_user` int(5) NOT NULL,
  `last_visit` int(10) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Pokud používáte prefixy tabulek, tak si skript upravte do požadované podoby.

Dále bude potřeba modifikovat tyto soubory:

index.php - aby se správně označovala fóra
viewforum.php - aby se správně označovala témata
viewtopic.php - aby se také označovaly příspěvky a aby se provedlo odznačení přečteného tématu
misc.php - aby fungoval link pro označení všeho jako přečteného
search.php - aby fungovala funkce "Zobrazit nové příspěvky od poslední návštěvy" a také označení nových příspěvků ve výsledcích vyhledávání
include/function.php - aby v databázi nezůstavalo smetí, kvůli smazaným tématům + jedna pomocná funkce

Popis atributů tabulky notread
id - id nepřečteného tématu (odpovídá topics.id)
id_user - id uživatele, který nemá něco přečteno.
last_visit - časové razítko poslední návštěvy uživatele (pro představu - odpovídá času, kdy uživatel navštívil dané téma naposledy)

Úprava souboru index.php

Za řádek

PHP:
require PUN_ROOT.'header.php';

doplníme příkaz pro zjíštění nepřečtených témat

PHP:
notRead();

Tuto pasáž

PHP:
// Are there new posts?
    if (!$pun_user['is_guest'] && $cur_forum['last_post']> $pun_user['last_visit'])
    {
        $item_status = 'inew';
        $icon_text = $lang_common['New icon'];
        $icon_type = 'icon inew';
    }

nahradíme novou

PHP:
// Are there new posts?
    $r = $db->query("SELECT * FROM ".$db->prefix."notread AS n, ".$db->prefix."topics AS t WHERE n.id=t.id AND n.id_user=".$pun_user['id']." AND t.forum_id=".$cur_forum['fid']);
    if ($r->num_rows>0){
        $item_status = 'inew';
        $icon_text = $lang_common['New icon'];
        $icon_type = 'icon inew';
    }

Úprava souboru viewforum.php

Tento sql dotaz

PHP:
// Without "the dot"
    $sql = 'SELECT id, poster, subject, posted, last_post, last_post_id, last_poster, num_views, num_replies, closed, sticky, moved_to FROM '.$db->prefix.'topics WHERE forum_id='.$id.' ORDER BY sticky DESC, '.(($cur_forum['sort_by'] == '1') ? 'posted' : 'last_post').' DESC LIMIT '.$start_from.', '.$pun_user['disp_topics'];

Nahradíme tímto

PHP:
$sql = 'SELECT t.id, t.poster, t.subject, t.posted, t.last_post, t.last_post_id, t.last_poster, t.num_views, t.num_replies, t.closed, t.sticky, t.moved_to, n.id AS nid FROM '.$db->prefix.'topics AS t LEFT JOIN (SELECT id FROM '.$db->prefix.'notread WHERE notread.id_user='.$pun_user['id'].') AS n ON t.id=n.id WHERE t.forum_id='.$id.' ORDER BY t.sticky DESC, '.(($cur_forum['sort_by'] == '1') ? 'posted' : 'last_post').' DESC LIMIT '.$start_from.', '.$pun_user['disp_topics'];

Před

PHP:
$result = $db->query($sql) or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());

// If there are topics in this forum.

Vložíme

PHP:
notRead();

Tento řádek

PHP:
if (!$pun_user['is_guest'] && $cur_topic['last_post']> $pun_user['last_visit'] && $cur_topic['moved_to'] == null)

nahradíme za

PHP:
if ($cur_topic['nid'] != "")

Úprava souboru viewtopic.php

Před

PHP:
// Fetch some info about the topic
if (!$pun_user['is_guest'])
    $result = $db->query('SELECT t.subject, t.closed, t.num_replies, t.sticky, f.id AS forum_id, f.forum_name, f.moderators, fp.post_replies, s.user_id AS is_subscribed FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'subscriptions AS s ON (t.id=s.topic_id AND s.user_id='.$pun_user['id'].') LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.id='.$id.' AND t.moved_to IS NULL') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
else
    $result = $db->query('SELECT t.subject, t.closed, t.num_replies, t.sticky, f.id AS forum_id, f.forum_name, f.moderators, fp.post_replies, 0 FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.id='.$id.' AND t.moved_to IS NULL') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());

doplníme

PHP:
if (!$pun_user['is_guest']) notRead();
if ($id>0) $r = $db->query("SELECT last_visit FROM ".$db->prefix."notread WHERE id = ".$id." AND id_user = ".$pun_user['id']);
$tmp = $r->fetch_assoc();
$last_visit  = $tmp['last_visit'];

Za

PHP:
// Do signature parsing/caching
    if ($cur_post['signature'] != '' && $pun_user['show_sig'] != '0')
    {
        if (isset($signature_cache[$cur_post['poster_id']]))
            $signature = $signature_cache[$cur_post['poster_id']];
        else
        {
            $signature = parse_signature($cur_post['signature']);
            $signature_cache[$cur_post['poster_id']] = $signature;
        }
    }

doplníme

PHP:
$new_post = (isset($last_visit)&&($last_visit<$cur_post['posted']))?" new":"";

Řádek

PHP:
<div id="p<?php echo $cur_post['id'] ?>" class="blockpost<?php echo $vtbg ?><?php if (($post_count + $start_from) == 1) echo ' firstpost'; ?>">

upravíme takto

PHP:
<div id="p<?php echo $cur_post['id'] ?>" class="blockpost<?php echo $vtbg ?><?php echo $new_post ?><?php if (($post_count + $start_from) == 1) echo ' firstpost'; ?>">

Před

PHP:
// Increment "num_views" for topic
$low_prio = ($db_type == 'mysql') ? 'LOW_PRIORITY ' : '';
$db->query('UPDATE '.$low_prio.$db->prefix.'topics SET num_views=num_views+1 WHERE id='.$id) or error('Unable to update topic', __FILE__, __LINE__, $db->error());

doplníme

PHP:
if ($id>0){ 
    $db->query("DELETE FROM ".$db->prefix."notread WHERE id=".$id." AND id_user=".$pun_user['id']);
    $db->query('UPDATE '.$db->prefix.'users SET last_visit='.time().' WHERE id='.$pun_user['id']) or error('Unable to update user last visit data', __FILE__, __LINE__, $db->error());
}

Úprava souboru misc.php

Obsluhu akce markread doplníme o řádek:

PHP:
$db->query("DELETE FROM ".$db->prefix."notread WHERE id_user = ".$pun_user['id']);

Úprava souboru include/function.php

Funkci delete_topic doplníme o řádek, který odstraní z databáze záznamy právě mazaných, nepřečtených témat.

Začátek funkce bude tedy vypadat takto:

PHP:
function delete_topic($topic_id)
{
    global $db;

    //smaze z databaze zaznamy o neprectenosti prave mazaneho topicu
    $db->query('DELETE FROM '.$db->prefix.'notread WHERE id='.$topic_id);

Na konec souporu function.php přidáme funkci pro zaznamenání všech nepřečtených témat do databáze

PHP:
function notRead(){
    global $db, $pun_config, $pun_user;
    if (!$pun_user['is_guest']){

    $r = $db->query("SELECT t.id FROM ".$db->prefix."topics AS t, ".$db->prefix."posts AS p WHERE t.last_post> ".$pun_user['last_visit']." AND t.last_post_id=p.id AND p.poster_id != ".$pun_user['id']." AND t.id NOT IN (SELECT id FROM ".$db->prefix."notread WHERE notread.id_user=".$pun_user['id'].")") ;
    while($row = $r->fetch_array()){
        $db->query("INSERT INTO ".$db->prefix."notread SET id=".$row['id'].", id_user=".$pun_user['id'].", last_visit = ".$pun_user['last_visit']);
        }
    }
}

Nyní si ještě upravíme styly pro zvýraznění nových příspěvků
Například pro styl cobalt dopíšeme na konec souboru style/imports/Cobalt_cs.css toto

CSS:
DIV.new H2 {BACKGROUND-COLOR: #FF6600}

Úprava souboru search.php

V souboru search.php najdeme část podobnou této:

PHP:
// If it's a search for new posts
if ($action == 'show_new')
{
    if ($pun_user['is_guest'])
        message($lang_common['No permission']);

    //$result = $db->query('SELECT t.id FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.last_post>'.$pun_user['last_visit'].' AND t.moved_to IS NULL') or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());

    $result = $db->query('SELECT t.id FROM '.$db->prefix.'notread AS t WHERE id_user = '.$pun_user['id']) or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
       
    $num_hits = $db->num_rows($result);

    if (!$num_hits)
        message($lang_search['No new posts']);
}

Zakomentovaný SELECT (původní) nahradíme SELECTem, který vybere nepřečtená témata z databáze dle id přihlášeného uživatele.

Pro správné zvýrazňování nepřečtených príspěvků ve výsledcích vyhledávání a v seznamu nepřečtených témat, musíme provést ještě toto:

Část:

PHP:
if (!$pun_user['is_guest'] && $search_set[$i]['last_post']> $pun_user['last_visit'])
$icon = '<div class="icon inew"><div class="nosize">'.$lang_common['New icon'].'</div></div>'."\n";

Nahradit za:

PHP:
$r = $db->query("SELECT * FROM ".$db->prefix."notread WHERE id_user=".$pun_user['id']." AND id=".$search_set[$i]['tid']);
$tmp = $r->fetch_assoc();
$last_visit  = $tmp['last_visit'];
if (!$pun_user['is_guest'] && isset($last_visit) && $last_visit <$search_set[$i]['pposted'])
$icon = '<div class="icon inew"><div class="nosize">'.$lang_common['New icon'].'</div></div>'."\n";

Část:

PHP:
if (!$pun_user['is_guest'] && $search_set[$i]['last_post']> $pun_user['last_visit'])

Nahradit za:

PHP:
$r = $db->query("SELECT * FROM ".$db->prefix."notread WHERE id_user=".$pun_user['id']." AND id=".$search_set[$i]['tid']);
if (!$pun_user['is_guest'] && $r->num_rows> 0)

Pokud máte jakékoliv problémy s implementací uvedeného řešení, můžete si napsat o radu do našeho fóra.