Intro

The goal for this patch was to add diffs of the edits to the RSS feed of RecentChanges. I ended up doing an Atom feed, because it allows to embed HTML in a clean, XML-conforming way. Direct links to the edit and history pages were added and a CSS allows to view the feed in a modern web browser in a nicely formatted fashion.

A new action atom is added. The original RSS feed and the Atom feed are advertised as alternate link in the header of every page. I did not include the Dublin Core and wiki module metadata found in the original RSS feed, because they seem to be unused and ignored by applications.

The included diff is the same as for the rest of the wiki. I recommend the /InlineDiff patch (with 20 surrounding context lines) for a nice readable output.

For an example look at http://fara.cs.uni-potsdam.de/index.php?action=atom (it's in German but you'll get the idea).

Comments

Patch

For installation

Look at your new feed at http://example.com/tavi/index.php?action=atom


Index: lib/url.php
===================================================================
--- lib/url.php    (.../vendor/tavi/release-0.26)    (Revision 1206)
+++ lib/url.php    (.../branches/rss)    (Revision 1206)
@@ -24,7 +24,14 @@
   { $PrefsScript = $ScriptBase . '?action=prefs'; }
 if(!isset($StyleScript))
   { $StyleScript = $ScriptBase . '?action=style'; }
+if(!isset($RssScript))
+  { $RssScript   = $ScriptBase . '?action=rss'; }
+if(!isset($AtomScript))
+  { $AtomScript  = $ScriptBase . '?action=atom'; }
+if(!isset($AtomCss))
+  { $AtomCss     = $TemplateBase . 'atom.css'; }
 
+
 if(!function_exists('viewURL'))
 {
 function viewURL($page, $version = '', $full = '')
Index: lib/main.php
===================================================================
--- lib/main.php    (.../vendor/tavi/release-0.26)    (Revision 1206)
+++ lib/main.php    (.../branches/rss)    (Revision 1206)
@@ -90,6 +90,7 @@
                 'prefs'   => array('action/prefs.php', 'action_prefs', 'view'),
                 'macro'   => array('action/macro.php', 'action_macro', 'search'),
                 'rss'     => array('action/rss.php', 'action_rss', 'view'),
+                'atom'    => array('action/atom.php', 'action_atom', 'view'),
                 'style'   => array('action/style.php', 'action_style', '')
               );
 
Index: lib/defaults.php
===================================================================
--- lib/defaults.php    (.../vendor/tavi/release-0.26)    (Revision 1206)
+++ lib/defaults.php    (.../branches/rss)    (Revision 1206)
@@ -41,6 +41,9 @@
 $ExtRef = array ('[', ']');
 // $ExtRef = array ('', ''); // Use this if you don't want anything
 
+// 'Tavi version
+$TaviVersion = '0.26';
+
 // !!!WARNING!!!
 // If $AdminEnabled is set to 1, the script admin/index.php will be accessible.
 //   This allows administrators to lock pages and block IP addresses.  If you
Index: template/atom.php
===================================================================
--- template/atom.php    (.../vendor/tavi/release-0.26)    (Revision 0)
+++ template/atom.php    (.../branches/rss)    (Revision 1206)
@@ -0,0 +1,48 @@
+<?php
+
+// The Atom template is passed an associative array with the following
+// elements:
+//
+//   items    =>  A string containing the entry elements for the syndication.
+//   updated  =>  Timestamp of the latest updated page
+
+function template_atom($args)
+{
+  global $ScriptBase, $WikiName, $WikiLogo, $MetaDescription, $InterWikiPrefix;
+  global $Charset, $TaviVersion, $RssScript, $AtomScript, $AtomCss;
+
+  header('Content-type: application/atom+xml');
+
+  $xmlLang = '';
+  if( defined('LANGUAGE_CODE') ){
+    $xmlLang = 'xml:lang="' . LANGUAGE_CODE . '"';
+  }
+?>
+<?php print '<?xml version="1.0" encoding="'.$Charset."\"?>\n"; ?>
+<?php print '<?xml-stylesheet href="'.$AtomCss."\" type=\"text/css\"?>\n"; ?>
+<feed xmlns="http://www.w3.org/2005/Atom" <?php print $xmlLang; ?>>
+  <!--
+      Add a "days=nnn" URL parameter to get nnn days of information
+      (the default is 2).  Use days=-1 to show entire history.
+      Add a "min=nnn" URL parameter to force a minimum of nnn entries
+      in the output (the default is 10).
+  -->
+  <title type="text"><?php print $WikiName; ?></title>
+  <subtitle><?php print $MetaDescription; ?></subtitle>
+  <link rel="alternate" type="application/xhtml+xml"
+    href="<?php print $ScriptBase; ?>" />
+  <link rel="alternate" type="application/rss+xml"
+    href="<?php print $RssScript; ?>" />
+  <link rel="self" type="application/atom+xml"
+    href="<?php print $AtomScript; ?>" />
+  <updated><?php print $args['updated']; ?></updated>
+  <generator uri="http://tavi.sourceforge.net/" version="<?php print $TaviVersion; ?>">
+    WikkiTikkiTavi
+  </generator>
+  <logo><?php print $WikiLogo; ?></logo>
+  <id><?php print $ScriptBase; ?></id>
+<?php print $args['items']; ?>
+</feed>
+<?php
+}
+?>
Index: template/atom.css
===================================================================
--- template/atom.css    (.../vendor/tavi/release-0.26)    (Revision 0)
+++ template/atom.css    (.../branches/rss)    (Revision 1206)
@@ -0,0 +1,96 @@
+/* atom feed style sheet. */
+
+feed {
+  display:block;
+  font-family:verdana, sans-serif;
+  margin:2%;
+  font-size:90%;
+  color:#000000;
+  background:#ffffff;
+}
+
+title {
+  display:block;
+  font-size:1.3em;
+  color:inherit;
+  background:inherit;
+  font-weight:bold;
+  color:#dd4400;
+}
+
+subtitle {
+  display:block;
+  font-size:0.9em;
+}
+
+id, generator, logo {
+  display:none;
+}
+
+subtitle:after {
+  float:right;
+  content:url(http://example.com/logo.png);
+}
+
+updated {
+  display:block;
+  color:#999999;
+}
+
+entry {
+  display:block;
+  color:inherit;
+  background:inherit;
+  padding:0;
+  margin:10px 10px 40px 10px;
+}
+
+entry updated, entry name {
+  display:inline;
+  color:#999999;
+  background:inherit;
+  font-size:0.7em;
+  padding:0px 0px 0px 10px;
+}
+
+entry summary {
+  display:inline;
+  font-weight:bold;
+}
+
+entry id {
+  display:none;
+}
+
+entry title {
+  display:block;
+  font-size:1em;
+  font-weight:bold;
+  background:inherit;
+  padding:1px 1px 0px 1px;
+  margin:0;
+  border-top:solid 1px #dddddd;
+}
+
+entry p.summary {
+  display:none;
+}
+
+content {
+  display:block;
+  font-size:0.9em;
+  color:inherit;
+  background:inherit;
+  padding:10px 10px 10px 10px;
+  margin:10px 10px 10px 10px;
+  border:dotted 1px #dddddd;
+}
+
+.diff del {
+  background: #ffb;
+  text-decoration: none;
+}
+.diff ins {
+  background: #cfc;
+  text-decoration: none;
+}
Index: template/rss.php
===================================================================
--- template/rss.php    (.../vendor/tavi/release-0.26)    (Revision 1206)
+++ template/rss.php    (.../branches/rss)    (Revision 1206)
@@ -12,7 +12,7 @@
   global $ScriptBase, $WikiName, $MetaDescription, $InterWikiPrefix;
   global $Charset;
 
-  header('Content-type: text/plain');
+  header('Content-type: application/rss+xml');
 ?>
 <?php print '<?xml '; ?>version="1.0" encoding="<?php print $Charset; ?>"?>
 <rdf:RDF
Index: template/common.php
===================================================================
--- template/common.php    (.../vendor/tavi/release-0.26)    (Revision 1206)
+++ template/common.php    (.../branches/rss)    (Revision 1206)
@@ -22,7 +22,8 @@
 function template_common_prologue($args)
 {
   global $WikiName, $HomePage, $WikiLogo, $MetaKeywords, $MetaDescription;
-  global $StyleScript, $SeparateTitleWords, $SeparateHeaderWords;
+  global $StyleScript, $RssScript, $AtomScript;
+  global $SeparateTitleWords, $SeparateHeaderWords;
 
   $keywords = ' ' . html_split_name($args['headlink']);
   $keywords = str_replace('"', '&quot;', $keywords);
@@ -49,6 +50,8 @@
   }
 ?>
 <link rel="STYLESHEET" href="<?php print $StyleScript; ?>" type="text/css" />
+<link rel="alternate" type="application/rss+xml" title="<?php print $WikiName.' / ' . PARSE_RecentChanges . ' (RSS)'?>" href="<?php print $RssScript; ?>" />
+<link rel="alternate" type="application/atom+xml" title="<?php print $WikiName.' / ' . PARSE_RecentChanges . ' (Atom)'?>" href="<?php print $AtomScript; ?>" />
 <title><?php print $args['title'] . ' - ' . $WikiName; ?></title>
 </head>
 <body>
Index: action/atom.php
===================================================================
--- action/atom.php    (.../vendor/tavi/release-0.26)    (Revision 0)
+++ action/atom.php    (.../branches/rss)    (Revision 1206)
@@ -0,0 +1,104 @@
+<?php
+
+require(TemplateDir . '/atom.php');
+require('parse/main.php');
+require('parse/html.php');
+require('parse/macros.php');
+require('lib/diff.php');
+
+function action_atom()
+{
+  global $pagestore, $min, $days, $AtomScript;
+
+  $items  = '';
+  $updated = '';
+
+  if($min == 0)  { $min = 10; }
+  if($days == 0) { $days = 2; }
+
+  $pages = $pagestore->allpages();
+
+  usort($pages, 'catSort');
+  $now = time();
+
+  for($i = 0; $i < count($pages); $i++)
+  {
+    $editTime = mktime(substr($pages[$i][0], 8, 2),
+                       substr($pages[$i][0], 10, 2),
+                       substr($pages[$i][0], 12, 2),
+                       substr($pages[$i][0], 4, 2),
+                       substr($pages[$i][0], 6, 2),
+                       substr($pages[$i][0], 0, 4));
+    if ($updated == '') {
+      $updated = get_iso_8601_date($editTime);
+    }
+    if($days >= 0 && ($now - $editTime) > $days * 24 * 60 * 60 && $i >= $min)
+      { break; }
+
+    $pageTitle = $pages[$i][1];
+    $page1 = $pagestore->page($pageTitle);
+    $page1->version = $pages[$i][7];
+    $page2 = $pagestore->page($pageTitle);
+    $page2->version = $pages[$i][7] - 1;
+    $diff = diff_compute($page2->read(), $page1->read());
+    $diff_html = diff_parse($diff);
+
+    $editorName = $pages[$i][3];
+    if( $editorName == '' ){
+      $editorName = $pages[$i][2];
+    }
+    $summary = parse_htmlisms($pages[$i][5]);
+
+    $items .=
+      "  <entry>\n" .
+      '    <title type="text">' . $pageTitle . "</title>\n" .
+      '    <link rel="alternate" type="text/html"' . "\n" .
+      '      href="' . historyURL($pageTitle) . "\"/>\n" .
+      '    <link rel="self" type="application/atom+xml"' . "\n" .
+      "      href=\"$AtomScript\"/>\n" .
+      "    <id>" . getUniqueId($pageTitle, $pages[$i][7]) . "</id>\n" .
+      '    <updated>' . get_iso_8601_date($editTime) . "</updated>\n" .
+      "    <author><name>$editorName</name></author>\n";
+    if( $pages[$i][5] != '' ){
+      $items .=
+      '    <summary>' . $summary . "</summary>\n";
+    }
+    $items .=
+      "    <content type=\"xhtml\">\n" .
+      "      <div xmlns=\"http://www.w3.org/1999/xhtml\">\n" .
+      '        <p class="summary">' .
+      "          $editorName: <b>$summary</b>" .
+      '        </p>' .
+      '        <p class="links">' .
+      "          " . html_ref($pageTitle, $pageTitle) .
+                 ' | <a href="' . historyURL($pageTitle) . '">' . TMPL_ViewDocHistory . '</a>' .
+                 ' | <a href="' . editURL($pageTitle) . '">' . TMPL_EditDocument . '</a>' .
+      "        </p><hr />\n" .
+               $diff_html .
+      "\n      </div>\n" .
+      "    </content>\n" .
+      "  </entry>\n";
+  }
+
+  template_atom(array(
+      'items'   => $items,
+      'updated' => $updated,
+  ));
+}
+
+function getUniqueId($pageTitle, $pageVersion)
+{
+  return viewURL($pageTitle, $pageVersion);
+}
+
+function get_iso_8601_date($int_date)
+{
+  //$int_date: current date in UNIX timestamp
+  $date_mod = date('Y-m-d\TH:i:s', $int_date);
+  $pre_timezone = date('O', $int_date);
+  $time_zone = substr($pre_timezone, 0, 3).":".substr($pre_timezone, 3, 2);
+  $date_mod .= $time_zone;
+  return $date_mod;
+}
+
+?>
Index: action/rss.php
===================================================================
--- action/rss.php    (.../vendor/tavi/release-0.26)    (Revision 1206)
+++ action/rss.php    (.../branches/rss)    (Revision 1206)
@@ -38,7 +38,8 @@
                 '    <item rdf:about="' . viewURL($pages[$i][1], $pages[$i][7]) . '">' . "\n" .
                 '        <title>' . $pages[$i][1] . '</title>' . "\n" .
                 '        <link>' . viewURL($pages[$i][1]) . '</link>' . "\n" .
-                '        <description>' . $pages[$i][5] . '</description>' . "\n" .
+                '        <description>' . parse_htmlisms($pages[$i][5]) .
+                         '</description>' . "\n" .
                 '        <dc:date>' . html_gmtime($pages[$i][0]) . '</dc:date>' . "\n" .
                 '        <dc:contributor>' . "\n" .
                 '            <rdf:Description wiki:host="' . $pages[$i][2] . '"'. ($pages[$i][3] == '' ? '' : (' link="' . viewURL($pages[$i][3]) . '"')) . '>' . "\n" .