This method uses Google Reader and its public API to organize the news feeds you want to feature on your Drupal pages. For example, we show headlines from local bloggers, local media, national news, politics, etc. grouped by category.
This works with any version of Drupal and will not break with updates. It eliminates tedious maintenance of feeds in Drupal Aggregator, and eliminates tremendous cron/database overhead on your server for keeping Aggregator feeds freshened if all you want to do is display some headlines.
The example code demonstrates how to use the Google Reader API for public/shared feeds in javascript or PHP and can be easily adapted for other applications.
Summary:
1. Setup Google Reader account, subscribe to some feeds, organize them into folders.
2. Make the folders public on Google Reader -> subscriptions -> manage subscriptions -> folders and tags
3. Get the public URL of the folder items using 'put a clip on your site'
4. Use PHP curl to get the public "clip"
5. Convert it using PHP json_decode
6. Parse out the headlines and links and sources or whatever, format it, and output it
Discussion and sample code:
To use it, setup a Google Reader account, create some folders for your categories, such as local blogs, local media, etc., then subscribe to some feeds in each category. Then go to 'manage subscriptions' in Google reader (under the 'Subscriptions' dropdown) and go to the 'folders and tags' page. On this page, click on the RSS icon for each folder/topic/tag you want to make 'public'. Once you do that, you will see some settings for each folder. Click the "put a clip on your site" option. This will reveal some HTML with links to the Google API. The second one will have a script source link that looks something like this:
http://www.google.com/reader/public/javascript/user/03791372163446595667/label/Local Papers?n=5&callback=GRC_p(%7Bc%3A%22blue%22%2Ct%3A%22%5C%22Local%20Papers%5C%22%20via%20R.%20Neal%22%2Cs%3A%22false%22%2Cn%3A%22true%22%2Cb%3A%22false%22%7D)%3Bnew%20GRC"
All we need is this part:
http://www.google.com/reader/public/javascript/user/03791372163446595667/label/Local Papers?n=5
Repeat and save the link for each folder/topic you want to show on your website. Tip: You will have to replace any spaces in the feed folder names, like this:
http://www.google.com/reader/public/javascript/user/03791372163446595667/label/Local%20Papers?n=5
You can also modify 'n=5' to the number of items you want returned.
Loading this page returns a javascript object of stuff about the items in the feeds. You can display them using your own javascript by making the 'callback' point to your script, like this:
<script type="text/javascript">
window.ContainerID = "";
function FormatGoogleClip (blog) {
if (!blog || !blog.items) return;
var container=document.getElementById(window.ContainerID);
var code="<ul>";
for (var i = 0; i < blog.items.length; i++) {
var item = blog.items[i];
code=code+"<li><a href='"+item.alternate.href+"' target='_blank'>" + item.title + "</a> <i>(<a href='" + item.origin.htmlUrl + "' target='_blank'>" + item.origin.title + "</a>)</i></li>";
}
code=code+"</ul>";
code=code.replace(new RegExp('Knoxville News Sentinel Stories: News', 'g'), 'Knoxville News Sentinel');
code=code.replace(new RegExp('Knoxville News Sentinel Stories: Local Business', 'g'), 'Knoxville News Sentinel');
code=code.replace(new RegExp('WATE \\- __Local News headlines on main news page \\*\\* assign as headline', 'g'), 'WATE');
container.innerHTML=code;
}
</script>
<h2>Local Papers</h2>
<div id="localpaper"> </div>
<script type="text/javascript">window.ContainerID="localpaper";</script>
<script type="text/javascript" src="http://www.google.com/reader/public/javascript/user/03791372163446595667/label/Local Papers?n=8&callback=FormatGoogleClip"></script>
<h2>Local TV News</h2>
<div id="localtv"> </div>
<script type="text/javascript">window.ContainerID="localtv";</script>
<script type="text/javascript" src="http://www.google.com/reader/public/javascript/user/03791372163446595667/label/Local TV?n=8&callback=FormatGoogleClip"></script>
(NOTE: The regex replacements are to clean up goofy feed titles setup by the feed creators. Unfortunately, the Google Reader API does not return the name you give the feed in your Google Reader subscriptions.)
Modify this script with the names and titles of your public Google Reader subscriptions, paste it in a block, and you are good to go.
I did this for a while and it works great. I have a bunch of feed categories, though, so there's a lot of javascripting and calls to the Google Reader API going on every time the page loads. This isn't real efficient for the client, and isn't playing nice with Google's servers if you have a lot of traffic/page views.
I wanted some way to cache it, similar to the Drupal Aggregator database cache, but didn't want the database and cron overhead (which I wanted to eliminate by using the Google Reader API). So I came up a server side PHP script with caching:
<?PHP
$cache_file = '/home/myacct/public_html/files/kv_feeds.txt';
$cache_life = '600'; //caching time, in seconds
$filemtime = @filemtime($cache_file); // returns FALSE if file does not exist
if (!$filemtime or (time() - $filemtime >= $cache_life)){
$block = getfeeds();
file_put_contents($cache_file,$block);
}else{
$block=file_get_contents($cache_file);
}
print $block;
function getfeeds() {
/* urls and titles */
$fl = array();
$fl[]=array("http://www.google.com/reader/public/javascript/user/03791372163446595667/label/Local%20Papers?n=10","Local Paper");
$fl[]=array("http://www.google.com/reader/public/javascript/user/03791372163446595667/label/Local%20TV?n=10","Local TV News");
/* title cleanup replacements */
$rl = array();
$rl[]=array("WATE - __Local News headlines on main news page ** assign as headline","WATE");
$rl[]=array("Knoxville News Sentinel Stories: News","Knoxville News Sentinel");
$rl[]=array("Knoxville News Sentinel Stories: Local Business","Knoxville News Sentinel");
$feeds='';
foreach ($fl as $f) {
$feeds.=getfeed($f[0],$f[1]);
}
foreach ($rl as $r) {
$feeds = str_replace($r[0],$r[1],$feeds);
}
return $feeds;
}
function getfeed($url,$title) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
$jdata = curl_exec($ch);
curl_close($ch);
$pdata = json_decode($jdata);
$items = $pdata->items;
$output = "<h2>".$title."</h2><ul>";
foreach ($items as $item) {
$output.="<li><a href='".$item->alternate->href."' target='_blank'>".$item->title."</a> (<a href='".$item->origin->htmlUrl."' target='_blank'>".$item->origin->title."</a>)</li>";
}
$output.="</ul>";
return $output;
}
?>
Modify the cache file name and life, then modify the arrays to include your public feed folders and titles, add any title replacements, paste it in a block, and you are good to go. It is completely independent of any Drupal databses, modules, or APIs.
With this method, the Google Reader API is only called every ten minutes at most (or whatever expiration you want) and only once by the first user to encounter the expired cache file.
Now it is easy to add/remove feeds from your categories by simply adding/removing them from your Google Reader subscriptions. You only need to change this script if you add a new Google Reader subscription folder.
See it in action at http://www.knoxviews.com (lower right column)
Note: If you have some code to parse atom feeds, change /public/javascript/ in the Google Reader API URL to /public/atom/ and you will get the list in atom feed format instead of a javascript array.