Compact archives for sNews 1.7

Compact archives for sNews 1.7

Anyone that's running sNews and writes as many articles as me has no doubt encountered the limitations of the current archives page. Basically it's just an enormously long chronological list.

Here's a handy little replacement function to display the archives by year, with clickable months if in fact the month contains articles. A user can click a specific month to view listings from only that month, or by year to view the entire year's articles. View my archives page for a demo.

First add the following to your language file;

#compact archives
$l['archive_by_date'] = 'By Date';

Now upload your language file.

OK, now for the logic, this is a simple drop-in replacement archive function, so the first step is always... BACK-UP your snews.php file and work off of a copy. Now find the function archive and rename it, I always append "_orig" when renaming function, so I can easily go back, so rename it archive_orig. Now copy the new archive function into your snews.php file, again, I always put new functions at the bottom just above the closing php tag when possible, to separate from the original core code.

function archive($start = 0, $size = 200) {
    echo '<h2><a href="'._SITE.'archive/">'.l('archive').'</a>';
    $break =  explode("/",cleanXSS($_SERVER['REQUEST_URI']));
    $count = count($break);
    $months = array("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12");
    if (in_array($break[$count-2], $months)) { //month is requested
        $year = $break[$count-3];
        $month = $break[$count-2];
    } elseif(strlen($break[$count-2]) == '4') {//just the year requested
        $year = $break[$count-2];
    if ($year >= '1900' && $year <= date('Y')) { // not a BS year
        $a1 = " AND YEAR(date) = $year";
        echo ' / <a href="'._SITE.'archive/'.$year.'/">'.$year.'</a>';
    if (checkdate($month,1,2001)) { // not a BS month
        $date_placeholder = strtotime("$month/01/2001");
        $a2 = " AND MONTH(date)=$month";
        $month_name = strftime("%B", $date_placeholder); // Full month name, based on the locale
        echo ' / '.$month_name;
    if (!$a1 && !$a2) { // YEAR/Month not set, display front page
        echo '</h2><h6>'.l('archive_by_date').'</h6><div class="archive_date"><p>';
        $query = "SELECT DISTINCT YEAR(date) AS year FROM "._PRE."articles a, "._PRE."categories c
        WHERE a.published='1'
            AND a.visible='YES'
            AND c.published='YES'
            AND <= NOW()
        ORDER BY year DESC";
        $result = mysql_query($query);
        while ($row = mysql_fetch_array($result)) {
            $i = "0";
            $year = $row['year'];
            echo '<a href="'._SITE.'archive/'.$year.'/" title="'.$year.'">'.$year.'</a> ';
            $month_query = "SELECT DISTINCT MONTH(date) AS month FROM "._PRE."articles a, "._PRE."categories c
            WHERE YEAR(date) = '$year'
                AND a.published='1'
                AND a.visible='YES'
                AND c.published='YES'
                AND <= NOW()
            ORDER BY month ASC";
            $month_result = mysql_query($month_query);
            $rows = array();
            while($r = mysql_fetch_assoc($month_result)) {array_push($rows, $r);}
                for ($month = 1; $month <= 12; $month += 1) {
                    $date_placeholder = strtotime("$month/01/2001");
                    $month_name = strftime("%B", $date_placeholder); // Full month name, based on the locale
                    $month_abbrev = strftime("%b", $date_placeholder);// Abbreviated month name, based on the locale
                    if ($rows[$i]['month'] == $month) {
                        echo ' <a href="archive/'.$year."/".$month.'/" title="'.$month_name.' '.$year.'">'.strtolower($month_abbrev).'</a> ';
                    } else {
                        echo ' '.strtolower($month_abbrev).' ';
            echo "<br />";  
        echo '</p></div>';
    } else { // Year and/or Month selected, display the appropriate articles
        echo '</h2>';
        $query = 'SELECT id FROM '._PRE.'articles'.'
        WHERE position = 1
            AND published = 1
            AND visible = \'YES\'
        ORDER BY date DESC
        LIMIT '."$start, $size";
        $result = mysql_query($query);
        $count = mysql_num_rows($result);
        if ($count === 0) {
            echo '<p>'.l('no_articles').'</p>';
        } else {
            while ($r = mysql_fetch_array($result)) {
                $or_id[] = ' ='.$r['id'];
            $or_id = implode(' OR ',$or_id);
            $query = 'SELECT
                title,a.seftitle AS asef, AS date,
       AS name,c.seftitle AS csef,
       AS xname,x.seftitle AS xsef
            FROM '._PRE.'articles'.' AS a
            LEFT OUTER JOIN '._PRE.'categories'.' as c
                ON category =
            LEFT OUTER JOIN '._PRE.'categories'.' as x
                ON c.subcat =
            WHERE ('.$or_id.')
                AND a.published = 1
                AND c.published =\'YES\'
                AND (x.published =\'YES\' || x.published IS NULL)
            ORDER BY date DESC
                LIMIT '."$start, $size";
            $result = mysql_query($query);
            $month_names = explode(', ', l('month_names'));
            echo '<div class="arc_list"><p>';
            while ($r = mysql_fetch_array($result)) {
                $year = substr($r['date'], 0, 4);
                $month = substr($r['date'], 5, 2) -1;
                $day = substr($r['date'], 8, 2);
                $month_name = (substr($month, 0, 1) == 0) ? $month_names[substr($month, 1, 1)] : $month_names[$month];
                if ($last <> $year.$month) {
                    echo '<strong>'.$month_name.', '.$year.'</strong><br />';
                $last = $year.$month;
                $link = isset($r['xsef']) ? $r['xsef'].'/'.$r['csef'] : $r['csef'];
                echo l('divider').' <a href="'._SITE.$link.'/'.$r['asef'].'/">
                '.$r['title'].' ('.$r['name'].')</a><br />';

OK, now upload your modified sNews.php file and then check out your archive page, it should look similar to mine now.

You may also add styles to your archive, the DIV containing the date list on the front page has a class of archive_date, and the actual article listings are inside a div with the class of arc_list, these are the styles I use, feel free to use this code if you like;

.archive_date p {
font-family:"lucida console";
.arc_list p {
.arc_list p a {



You might like


Nice job, working perfectly, actually alot better than my original idea, which was adding all months in my sidebare, I know made a link for 2009 instead, which is more simpler, so again, thanks alot for your efforts.

Thanks asundrus, I'm glad you found it useful. Your idea about the sidebar isn't a bad idea either, it shouldn't be too hard to make a WordPress style sidebar "archives" list function that works in conjunction with this one.

As always great job Matt.

As usual, it doesn't work for me. :-D
Nothing is extracted:
Another bug due to the DB prefix?

Sven, yep, it's the DB prefix again :), I threw this one up in a real hurry too, so I was expecting problems.

I've updated the function now.

"(...) so I was expecting problems."
And I came.
Thanks a lot Matt. It's working like a charme now.


Looks good, ecept it appears your PHP locale is set to English, which results in "March" instead of "Mars".

This is an easy runtime fix; you can either add this to the top of your snews.php file to make it run French (I assume that's French :P) language;

setlocale(LC_ALL , 'fr_FR');
or add this on the first line of the archives function to just make date/time localized to French;

setlocale(LC_TIME , 'fr_FR');
Let me know if that doesn't make sense, or you need any help.

That makes sense, Matt. I placed setlocale(LC_ALL, 'fr_FR.utf8'); at the top of my snews.
And now my snews speaks french better than inspecteur Clouseau. :-D

Have a nice day pal.

I have a problem with this mod.
The years and months are correctly displayed on the archive page.
But when I click a month or a year, nothing happens..
I use a db prefix.
Online at


Hey PP, I see the problem, it's b/c your install is in a subfolder, that subfolder is part of the request_uri.

<strong>I have updated this function to work with subfolders now</strong>. Should work no matter no many folders deep you install sNews now.

Yes yes yes that's it... :-)
Thanks again Matt.


Thanks for this Matt. Very useful and ever so easy to hack for own purposes (I needed output in lists and with long month names but that's a cinch with the things included in the setup.)

Just found that mod, which is another great one!!

Thanks again for all your work for the snews community ;)

Damn this was a better one...

Uh oh.
Hey Matt when you got time check out my archive.

There's a bug with this extra line withe a year=0.

There's something to see with the server: locally I don't have this extra line.

Sven, something must be wrong with an article date, as that part is as simple as it gets. Try running this SQL command in your DB admin tool;

SELECT DISTINCT YEAR(date) AS year FROM articles

See what that returns, and don't forget your table prefix :)

Oh yeah, and check your spam folder for the email comment notification stuff, seems like a lot the notification emails are ending up in people's spam folders... :/

As usual it was a Sven bug which has been corrected now. Thanks a lot for having helped.

I just checked my spam folder: there is no mail from you in it. ???

Looks like 1and1 didn't like my MX record and kicked it back, I think I've fixed that now. I've removed your notification entry, so next time you try to subscribe, it should hopefully send you the verify email.

That's why it's still very beta :P

Oh okey. I was wondering if it was sent by sea or airmail. I'll be waiting for internet in Europe.

Man you're a genious!!!
It works and it's damn great!
Where do I send my karma?

LOL Sven, thanks.

There's still a few features I need to finish on the notification mod, once I finish and release my spam mod I'll get back to working on it again.

I use a cronjob to send batch notifications, as an example, if you're subscribed to 3 articles and they each get 2 new comments before the cronjob, then you'll only get 1 email, notifying you of the new comments, with the links to each article, etc.

Another thing you may notice is if you respond to a new comment before the cronjob is run, it won't send that one to you, as you've obviously seen it if you've already responded to it.


a nice one mod! But I have a question like allways :/

How did you get your archive like so:
By Date
By Category
? my archive is on By Date?! :D

p.s.: Kick my ass for bottering you so much!


Mine is just customized further, that's all :)

It just spits out a list of all cats/articles, basically a copy and paste of most of the sitemap function, with pages removed :)

Really good job Matt :) already thanks..! (from turkey)

Comments are closed. No new comments allowed.

Copyleft 2002 - 2017 Matt Jones
Hand crafted with HTML5 & CSS3
↑ Back to top