Compact archives for sNews 1.7

Comments (21)

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 ...as 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.

// ARCHIVE - COMPACT STYLE
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 a.category=c.id
            AND a.date <= 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 a.category=c.id
                AND a.date <= 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> ';
                        $i++;
                    } 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\'
            '.$a1.'
            '.$a2.'
        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[] = 'a.id ='.$r['id'];
            }
            $or_id = implode(' OR ',$or_id);
            $query = 'SELECT
                title,a.seftitle AS asef,a.date AS date,
                c.name AS name,c.seftitle AS csef,
                x.name AS xname,x.seftitle AS xsef
            FROM '._PRE.'articles'.' AS a
            LEFT OUTER JOIN '._PRE.'categories'.' as c
                ON category = c.id
            LEFT OUTER JOIN '._PRE.'categories'.' as x
                ON c.subcat =  x.id
            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 />';
            }
            echo'</p></div>';
        }
    }
}

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 {
line-height:1.6em;
font-family:"lucida console";
font-size:1.1em;
text-transform:uppercase;
text-align:justify;
}
.arc_list p {
text-align:left;
}
.arc_list p a {
color:#386E80;
}
bookmark / share this: Bookmark and Share
rated 4.4/5 (5 votes)


21 comments

Add a new comment »

asundrus asundrus said:
Apr 9th, 2009 at 2:45 am

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.


Matt Matt said:
Apr 10th, 2009 at 7:38 am

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.


Poppoll Poppoll said:
Apr 10th, 2009 at 5:35 pm

As always great job Matt.
Thanks,
PP


Sven - Philippe Sven - Philippe said:
Apr 17th, 2009 at 9:31 am

As usual, it doesn't work for me. :-D
Nothing is extracted:
(http://carnet.hiseo.fr/archive/)
Another bug due to the DB prefix?


Matt Matt said:
Apr 17th, 2009 at 11:03 am

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.


Sven - Philippe Sven - Philippe said:
Apr 17th, 2009 at 11:15 am

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


Matt Matt said:
Apr 17th, 2009 at 11:36 am

Sven,

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;

<?php
setlocale(LC_ALL , 'fr_FR');
?>

or add this on the first line of the archives function to just make date/time localized to French;

<?php
setlocale(LC_TIME , 'fr_FR');
?>

Let me know if that doesn't make sense, or you need any help.


Sven - Philippe Sven - Philippe said:
Apr 23rd, 2009 at 2:25 am

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.


Poppoll Poppoll said:
May 4th, 2009 at 7:44 pm

Matt,
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 http://nieuwerkerken-aalst.be/snews/archive/

PP


Matt Matt said:
May 4th, 2009 at 7:56 pm

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

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


Poppoll Poppoll said:
May 4th, 2009 at 9:31 pm

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

PP


Fred K Fred K said:
Aug 10th, 2009 at 9:46 am

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.)


konga konga said:
Aug 25th, 2009 at 11:39 am

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

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


Patric Patric said:
Jan 25th, 2010 at 9:42 am

Damn this was a better one...


Sven/Philippe Sven/Philippe said:
Feb 19th, 2010 at 10:13 am

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

http://on-air.hiseo.fr/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.
Weirdo.


Matt Matt said:
Feb 19th, 2010 at 11:20 am

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
        ORDER BY year DESC;


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... :/


Sven/Philippe Sven/Philippe said:
Feb 20th, 2010 at 3:02 am

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. ???


Matt Matt said:
Feb 20th, 2010 at 10:13 am

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


Sven/Philippe Sven/Philippe said:
Feb 21st, 2010 at 5:01 am

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


Sven/Philippe Sven/Philippe said:
Feb 21st, 2010 at 5:03 am

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


Matt Matt said:
Feb 21st, 2010 at 8:19 am

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.



Write a comment

* = required field

:

:

:

:

You may insert urls in plain text, urls will be automatically linkified for trusted users and on seasoned posts only. All first comments are moderated, so use your email if you want to be remembered.


Back to top