Wiki source for RSSHandler
===== A single class for RSS feed generation =====
As of the latest release (1.1.6.1), Wikka has a quite limited [[RSS]] support, both as output and input. Before thinking of possible [[SyndicatingWikka | extensions]], we need to implement in a more consistent way the available RSS-related services.
=== RSS as input ===
>>**See also:**
~-JwRssTest
~-NewRssAction
>>As for **[[RSSInfo | RSS embedding]]**, which can be used to feed content to Wikka from external servers, we are switching to a new parser (like [[http://magpierss.sourceforge.net/ | Magpie]]): Magpie is less buggy and way more flexible than the current one (Onyx).
=== RSS as output ===
As for **RSS generation**, at the moment (1.1.6.1) Wikka has two separate handlers to generate feeds for page revisions and recently changed pages.
== The problem ==
There are many issues with the current feed generation tools:
- feed generation is hardcoded in these handlers, so it cannot be easily modified or extended;
- these handlers produce feeds based on different standards: RSS 2.0 (page revisions) and RSS 0.92 (recently changed pages)
- only the //recently changed pages// has a dedicated stylesheet.
== The solution ==
Instead of manually fixing the current handlers, why not create some general feed generation utility that we can adapt to the specific kind of output to be produced? And instead of writing it ourselves and reinventing the wheel, why not simply write a wrapper around an existing feed generation class? There are many examples of light, flexible and GPL'ed PHP classes for feed generation that we could integrate with Wikka.
One that looks quite promising is: [[http://feedcreator.org/]]
Here's the feature list reported from its website:
##""FeedCreator.class.php""## //provides an easy way to create RSS feeds from within PHP using ease to use classes.//
//Features:
~-creates valid feeds according to RSS 0.91, 1.0 or 2.0 as well as PIE 0.1 (deprecated), OPML 1.0, Unix mbox, ATOM 0.3, or customizable HTML or Javascript format.
~- configurable feed caching
~- very well documented and easy to use
~- feed image
~- includes almost all RSS 0.91 attributes
~- decide which version to create during runtime
~- easy to use and well documented class interface
~- intelligently truncates strings when needed
//
Now, what we need to do is simply integrate such a class into Wikka and create a wrapper method to provide more flexibility and configurability. This will allow us to create //on the fly// new handlers for specific kinds of output and in multiple formats. The number and choice of formats to be displayed might be determined by Wiki Admins in the system configuration.
=== Test implementation: a new ##feed.xml.php## handler ===
This is a replacement for the current ##recentchanges## feed.
==Installation and setup==
Download the ##[[http://mypapit.net/drop/files/feedcreator-1.7.2-ppt.zip | FeedCreator]]## class. Unzip the package and save the class in a comfortable location, e.g. ##3rdparty/plugins/feedcreator/feedcreator.class.php##.
Add the following line to ##wikka.config.php##, immediately before the GeSHi related entries:
%%
"feedcreator_path" => "3rdparty/plugins/feedcreator",
%%
==Usage==
Append ##""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml">/feed.xml</a>""## or ##""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=ATOM1.0">/feed.xml?f=FORMAT</a>""## (##/feed.xml&f=FORMAT## if mod_rewrite is disabled) to a page URL, where ##FORMAT## can be any of the following: ##RSS0.91, RSS1.0, RSS2.0, ATOM1.0##. If no format or an unknown format is specified, then ##RSS2.0## is used.
==Validation==
~-**RSS 0.91** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=RSS0.91" title="RSS 0.91"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DRSS0.91" title="valid RSS feed"><img src="images/icons/done.png" alt="√" /></a>""
~-**RSS 1.0** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=RSS1.0" title="RSS 1.0"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DRSS1.0" title="valid RSS feed"><img src="images/icons/done.png" alt="√" /></a>""
~-**RSS 2.0** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=RSS2.0" title="RSS 2.0"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DRSS2.0" title="valid RSS feed"><img src="images/icons/done.png" alt="√" /></a>""
~-**ATOM 1.0** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=ATOM1.0" title="ATOM 1.0"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DATOM1.0" title="valid ATOM feed"><img src="images/icons/done.png" alt="√" /></a>""
==Changelog==
~-**##0.3.1##**
~~-dropped the author value for RSS 0.91 and 2.0 feeds, since if it's specified it must contain an email address, and we don't want to disclose user email addresses. RSS 1.0 and Atom 1.0 accept an author without email;
~~-added feed image support;
~~-added css support;
~~-valid formats stored as CVS constant;
==To do==
~-add missing parameters;
~-add author/contributor elements;
~-create CSS/XSL for different formats;
~-move default settings to configuration file;
==The code==
Save the following code as ##handlers/page/feed.xml.php##
%%(php;1)
<?php
/**
* Creates a feed with recently changed pages
*
* This handler generates a list of recently changed pages on the current server. The output
* format can be specified in the URL.
*
* @package Handlers
* @name recentchanges.xml
*
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli}
* @version 0.3.1
* @access public
* @since wikka 1.1.X.X
* @uses wakka::config
* @uses FeedCreator (1.7.2-ppt)
* @todo - move defaults to wiki configuration files
*
* @input string $f optional: output format, can be any of the following:
* RSS0.91, RSS1.0, RSS2.0, ATOM1.0
* default: RSS2.0
* the default format can be overridden by providing a URL parameter 'f'.
* @output feed for recently changed pages in the specified format.
*/
//defaults
define('VALID_FORMATS', "RSS0.91,RSS1.0,RSS2.0,ATOM1.0");
define('DEFAULT_OUTPUT_FORMAT',"RSS2.0");
define('DESCRIPTION_TRUNCATE_SIZE',"500"); #character limit to truncate description
define('DESCRIPTION_HTML_SYNDICATE',"TRUE"); #Indicates whether the description field should be rendered in HTML
//stylesheets & images
define('FEED_CSS',"http://wikka.jsnx.com/css/xml.css");
define('IMAGE_URL',"http://wikka.jsnx.com/images/wikka_logo.jpg");
//i18n strings
define('FEED_TITLE',"%s - recently changed pages");
define('FEED_DESCRIPTION',"New and recently changed pages from %s");
define('IMAGE_TITLE',"Wikka logo");
define('IMAGE_DESCRIPTION',"Feed provided by Wikka");
//initialize variables
$f = '';
//get URL parameters
$formats = explode(",",VALID_FORMATS);
$f = (in_array($_GET['f'], $formats))? $_GET['f'] : DEFAULT_OUTPUT_FORMAT;
//create objects
include_once($this->config['feedcreator_path'].'/feedcreator.class.php');
$rss = new UniversalFeedCreator();
$rss->useCached(); #make this configurable
$rss->title = sprintf(FEED_TITLE, $this->GetConfigValue("wakka_name"));
$rss->description = sprintf(FEED_DESCRIPTION, $this->GetConfigValue("wakka_name"));
$rss->cssStyleSheet = FEED_CSS;
$rss->descriptionTruncSize = DESCRIPTION_TRUNCATE_SIZE;
$rss->descriptionHtmlSyndicated = DESCRIPTION_HTML_SYNDICATE;
$rss->link = $this->GetConfigValue("base_url").$this->GetConfigValue("root_page");
$rss->syndicationURL = $this->Href($this->method,'','f='.$f);
//feed image
$image = new FeedImage();
$image->title = IMAGE_TITLE;
$image->url = IMAGE_URL;
$image->link = $this->GetConfigValue("base_url").$this->GetConfigValue("root_page");
$image->description = IMAGE_DESCRIPTION;
$image->descriptionTruncSize = DESCRIPTION_TRUNCATE_SIZE;
$image->descriptionHtmlSyndicated = DESCRIPTION_HTML_SYNDICATE;
$rss->image = $image;
//get feed items
if ($pages = $this->LoadRecentlyChanged())
{
$max = $this->GetConfigValue("xml_recent_changes");
$c = 0;
foreach ($pages as $page)
{
$c++;
if (($c <= $max) || !$max)
{
$item = new FeedItem();
$item->title = $this->GetConfigValue("wakka_name").' - '.$page['tag'];
$item->link = $this->Href("show", $page["tag"], "time=".urlencode($page["time"]));
$item->description = ($page['note'] ? ' - '.$page['note'] : '');
$item->date = date('r',strtotime($page['time']));
$item->source = $this->GetConfigValue("base_url");
if (($f == 'ATOM1.0' || $f == 'RSS1.0') && $this->LoadUser($page['user']))
{
$item->author = $page['user']; # RSS0.91 and RSS2.0 require authorEmail
}
$rss->addItem($item);
}
}
}
//print feed
echo $rss->createFeed($f);
?>
%%
Feedback welcome
----
CategoryDevelopmentSyndication
As of the latest release (1.1.6.1), Wikka has a quite limited [[RSS]] support, both as output and input. Before thinking of possible [[SyndicatingWikka | extensions]], we need to implement in a more consistent way the available RSS-related services.
=== RSS as input ===
>>**See also:**
~-JwRssTest
~-NewRssAction
>>As for **[[RSSInfo | RSS embedding]]**, which can be used to feed content to Wikka from external servers, we are switching to a new parser (like [[http://magpierss.sourceforge.net/ | Magpie]]): Magpie is less buggy and way more flexible than the current one (Onyx).
=== RSS as output ===
As for **RSS generation**, at the moment (1.1.6.1) Wikka has two separate handlers to generate feeds for page revisions and recently changed pages.
== The problem ==
There are many issues with the current feed generation tools:
- feed generation is hardcoded in these handlers, so it cannot be easily modified or extended;
- these handlers produce feeds based on different standards: RSS 2.0 (page revisions) and RSS 0.92 (recently changed pages)
- only the //recently changed pages// has a dedicated stylesheet.
== The solution ==
Instead of manually fixing the current handlers, why not create some general feed generation utility that we can adapt to the specific kind of output to be produced? And instead of writing it ourselves and reinventing the wheel, why not simply write a wrapper around an existing feed generation class? There are many examples of light, flexible and GPL'ed PHP classes for feed generation that we could integrate with Wikka.
One that looks quite promising is: [[http://feedcreator.org/]]
Here's the feature list reported from its website:
##""FeedCreator.class.php""## //provides an easy way to create RSS feeds from within PHP using ease to use classes.//
//Features:
~-creates valid feeds according to RSS 0.91, 1.0 or 2.0 as well as PIE 0.1 (deprecated), OPML 1.0, Unix mbox, ATOM 0.3, or customizable HTML or Javascript format.
~- configurable feed caching
~- very well documented and easy to use
~- feed image
~- includes almost all RSS 0.91 attributes
~- decide which version to create during runtime
~- easy to use and well documented class interface
~- intelligently truncates strings when needed
//
Now, what we need to do is simply integrate such a class into Wikka and create a wrapper method to provide more flexibility and configurability. This will allow us to create //on the fly// new handlers for specific kinds of output and in multiple formats. The number and choice of formats to be displayed might be determined by Wiki Admins in the system configuration.
=== Test implementation: a new ##feed.xml.php## handler ===
This is a replacement for the current ##recentchanges## feed.
==Installation and setup==
Download the ##[[http://mypapit.net/drop/files/feedcreator-1.7.2-ppt.zip | FeedCreator]]## class. Unzip the package and save the class in a comfortable location, e.g. ##3rdparty/plugins/feedcreator/feedcreator.class.php##.
Add the following line to ##wikka.config.php##, immediately before the GeSHi related entries:
%%
"feedcreator_path" => "3rdparty/plugins/feedcreator",
%%
==Usage==
Append ##""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml">/feed.xml</a>""## or ##""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=ATOM1.0">/feed.xml?f=FORMAT</a>""## (##/feed.xml&f=FORMAT## if mod_rewrite is disabled) to a page URL, where ##FORMAT## can be any of the following: ##RSS0.91, RSS1.0, RSS2.0, ATOM1.0##. If no format or an unknown format is specified, then ##RSS2.0## is used.
==Validation==
~-**RSS 0.91** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=RSS0.91" title="RSS 0.91"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DRSS0.91" title="valid RSS feed"><img src="images/icons/done.png" alt="√" /></a>""
~-**RSS 1.0** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=RSS1.0" title="RSS 1.0"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DRSS1.0" title="valid RSS feed"><img src="images/icons/done.png" alt="√" /></a>""
~-**RSS 2.0** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=RSS2.0" title="RSS 2.0"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DRSS2.0" title="valid RSS feed"><img src="images/icons/done.png" alt="√" /></a>""
~-**ATOM 1.0** --- ""<a href="http://wikka.jsnx.com/RSSHandler/feed.xml?f=ATOM1.0" title="ATOM 1.0"><img src="images/xml.png" alt="XML icon" /></a> <a href="http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwikka.jsnx.com%2FRSSHandler%2Ffeed.xml%3Ff%3DATOM1.0" title="valid ATOM feed"><img src="images/icons/done.png" alt="√" /></a>""
==Changelog==
~-**##0.3.1##**
~~-dropped the author value for RSS 0.91 and 2.0 feeds, since if it's specified it must contain an email address, and we don't want to disclose user email addresses. RSS 1.0 and Atom 1.0 accept an author without email;
~~-added feed image support;
~~-added css support;
~~-valid formats stored as CVS constant;
==To do==
~-add missing parameters;
~-add author/contributor elements;
~-create CSS/XSL for different formats;
~-move default settings to configuration file;
==The code==
Save the following code as ##handlers/page/feed.xml.php##
%%(php;1)
<?php
/**
* Creates a feed with recently changed pages
*
* This handler generates a list of recently changed pages on the current server. The output
* format can be specified in the URL.
*
* @package Handlers
* @name recentchanges.xml
*
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli}
* @version 0.3.1
* @access public
* @since wikka 1.1.X.X
* @uses wakka::config
* @uses FeedCreator (1.7.2-ppt)
* @todo - move defaults to wiki configuration files
*
* @input string $f optional: output format, can be any of the following:
* RSS0.91, RSS1.0, RSS2.0, ATOM1.0
* default: RSS2.0
* the default format can be overridden by providing a URL parameter 'f'.
* @output feed for recently changed pages in the specified format.
*/
//defaults
define('VALID_FORMATS', "RSS0.91,RSS1.0,RSS2.0,ATOM1.0");
define('DEFAULT_OUTPUT_FORMAT',"RSS2.0");
define('DESCRIPTION_TRUNCATE_SIZE',"500"); #character limit to truncate description
define('DESCRIPTION_HTML_SYNDICATE',"TRUE"); #Indicates whether the description field should be rendered in HTML
//stylesheets & images
define('FEED_CSS',"http://wikka.jsnx.com/css/xml.css");
define('IMAGE_URL',"http://wikka.jsnx.com/images/wikka_logo.jpg");
//i18n strings
define('FEED_TITLE',"%s - recently changed pages");
define('FEED_DESCRIPTION',"New and recently changed pages from %s");
define('IMAGE_TITLE',"Wikka logo");
define('IMAGE_DESCRIPTION',"Feed provided by Wikka");
//initialize variables
$f = '';
//get URL parameters
$formats = explode(",",VALID_FORMATS);
$f = (in_array($_GET['f'], $formats))? $_GET['f'] : DEFAULT_OUTPUT_FORMAT;
//create objects
include_once($this->config['feedcreator_path'].'/feedcreator.class.php');
$rss = new UniversalFeedCreator();
$rss->useCached(); #make this configurable
$rss->title = sprintf(FEED_TITLE, $this->GetConfigValue("wakka_name"));
$rss->description = sprintf(FEED_DESCRIPTION, $this->GetConfigValue("wakka_name"));
$rss->cssStyleSheet = FEED_CSS;
$rss->descriptionTruncSize = DESCRIPTION_TRUNCATE_SIZE;
$rss->descriptionHtmlSyndicated = DESCRIPTION_HTML_SYNDICATE;
$rss->link = $this->GetConfigValue("base_url").$this->GetConfigValue("root_page");
$rss->syndicationURL = $this->Href($this->method,'','f='.$f);
//feed image
$image = new FeedImage();
$image->title = IMAGE_TITLE;
$image->url = IMAGE_URL;
$image->link = $this->GetConfigValue("base_url").$this->GetConfigValue("root_page");
$image->description = IMAGE_DESCRIPTION;
$image->descriptionTruncSize = DESCRIPTION_TRUNCATE_SIZE;
$image->descriptionHtmlSyndicated = DESCRIPTION_HTML_SYNDICATE;
$rss->image = $image;
//get feed items
if ($pages = $this->LoadRecentlyChanged())
{
$max = $this->GetConfigValue("xml_recent_changes");
$c = 0;
foreach ($pages as $page)
{
$c++;
if (($c <= $max) || !$max)
{
$item = new FeedItem();
$item->title = $this->GetConfigValue("wakka_name").' - '.$page['tag'];
$item->link = $this->Href("show", $page["tag"], "time=".urlencode($page["time"]));
$item->description = ($page['note'] ? ' - '.$page['note'] : '');
$item->date = date('r',strtotime($page['time']));
$item->source = $this->GetConfigValue("base_url");
if (($f == 'ATOM1.0' || $f == 'RSS1.0') && $this->LoadUser($page['user']))
{
$item->author = $page['user']; # RSS0.91 and RSS2.0 require authorEmail
}
$rss->addItem($item);
}
}
}
//print feed
echo $rss->createFeed($f);
?>
%%
Feedback welcome
----
CategoryDevelopmentSyndication