All Rights Reserved" in the feed for ?action=atom. If the value of an entry begins with a '<', then feeds.php doesn't automatically add the tag around it. Elements can also be callable functions which are called to generate the appropriate output. For example, to set the RSS 2.0 element to the value of the last author to modify a page, one can set (in local/config.php): $FeedFmt['rss']['item']['author'] = '$LastModifiedBy'; To use the RSS 2.0 element to contain the change summary of the most recent edit, set $FeedFmt['rss']['item']['description'] = '$LastModifiedSummary'; Feeds.php can also be combined with attachments to support podcasting via ?action=rss. Any page such as "PageName" that has an mp3 attachment with the same name as the page ("PageName.mp3") will have an appropriate element in the feed output. The set of allowed attachments can be extended using the $RSSEnclosureFmt array: $RSSEnclosureFmt = array('{$Name}.mp3', '{$Name}.mp4'); References: http://www.atomenabled.org/developers/syndication/ http://dublincore.org/documents/dcmes-xml/ http://en.wikipedia.org/wiki/Podcasting */ ## Settings for ?action=atom SDVA($FeedFmt['atom']['feed'], array( '_header' => 'Content-type: text/xml; charset="$Charset"', '_start' => ' '."\n", '_end' => "\n", 'title' => '$WikiTitle', 'link' => '', 'id' => '{$PageUrl}?action=atom', 'updated' => '$FeedISOTime', 'author' => "$WikiTitle\n", 'generator' => '$Version', 'logo' => '$PageLogoUrl')); SDVA($FeedFmt['atom']['item'], array( '_start' => "\n", 'id' => '{$PageUrl}', 'title' => '{$Title}', 'updated' => '$ItemISOTime', 'link' => "\n", 'author' => "{\$LastModifiedBy}\n", 'summary' => '{$Description}', 'category' => "\n", '_end' => "\n")); ## Settings for ?action=dc SDVA($FeedFmt['dc']['feed'], array( '_header' => 'Content-type: text/xml; charset="$Charset"', '_start' => ' '."\n", '_end' => "\n")); SDVA($FeedFmt['dc']['item'], array( '_start' => "\n", 'dc:title' => '{$Title}', 'dc:identifier' => '{$PageUrl}', 'dc:date' => '$ItemISOTime', 'dc:type' => 'Text', 'dc:format' => 'text/html', 'dc:description' => '{$Description}', 'dc:subject' => "\$Category\n", 'dc:publisher' => '$WikiTitle', 'dc:author' => '{$LastModifiedBy}', '_end' => "\n")); ## RSS 2.0 settings for ?action=rss SDVA($FeedFmt['rss']['feed'], array( '_header' => 'Content-type: text/xml; charset="$Charset"', '_start' => ' '."\n", '_end' => "\n\n", 'title' => '$WikiTitle | {$Group} / {$Title}', 'link' => '{$PageUrl}?action=rss', 'description' => '{$Group}.{$Title}', 'lastBuildDate' => '$FeedRSSTime')); SDVA($FeedFmt['rss']['item'], array( '_start' => "\n", '_end' => "\n", 'title' => '{$Group} / {$Title}', 'link' => '{$PageUrl}', 'description' => '{$Description}', 'dc:contributor' => '{$LastModifiedBy}', 'dc:date' => '$ItemISOTime', 'pubDate' => '$ItemRSSTime', 'enclosure' => 'RSSEnclosure')); ## RDF 1.0, for ?action=rdf SDVA($FeedFmt['rdf']['feed'], array( '_header' => 'Content-type: text/xml; charset="$Charset"', '_start' => ' '."\n", 'title' => '$WikiTitle | {$Group} / {$Title}', 'link' => '{$PageUrl}?action=rdf', 'description' => '{$Group}.{$Title}', 'dc:date' => '$FeedISOTime', 'items' => "\n\n\$FeedRDFSeq\n\n", '_items' => "\n", '_end' => "\n")); SDVA($FeedFmt['rdf']['item'], array( '_start' => "\n", '_end' => "\n", 'title' => '$WikiTitle | {$Group} / {$Title}', 'link' => '{$PageUrl}', 'description' => '{$Description}', 'dc:date' => '$ItemISOTime')); foreach(array_keys($FeedFmt) as $k) { SDV($HandleActions[$k], 'HandleFeed'); SDV($HandleAuth[$k], 'read'); } function HandleFeed($pagename, $auth = 'read') { global $FeedFmt, $action, $PCache, $FmtV, $ISOTimeFmt, $RSSTimeFmt, $FeedOpt, $FeedDescPatterns, $CategoryGroup, $EntitiesTable; SDV($ISOTimeFmt, '%Y-%m-%dT%H:%M:%SZ'); SDV($RSSTimeFmt, 'D, d M Y H:i:s \G\M\T'); SDV($FeedDescPatterns, array('/<[^>]*$/' => ' ', '/\\w+$/' => '', '/<[^>]+>/' => '')); SDVA($FeedPageListOpt, array()); SDVA($FeedCategoryOpt, array('link' => $pagename)); SDVA($FeedTrailOpt, array('trail' => $pagename, 'count' => 10)); $f = $FeedFmt[$action]; $page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT); if (!$page) Abort("?cannot generate feed"); $feedtime = $page['time']; # determine list of pages to display if (@($_REQUEST['trail'] || $_REQUEST['group'] || $_REQUEST['link'] || $_REQUEST['name'])) $opt = $FeedPageListOpt; else if (preg_match("/^$CategoryGroup\\./", $pagename)) $opt = $FeedCategoryOpt; else if ($action != 'dc') $opt = $FeedTrailOpt; else { PCache($pagename, $page); $pagelist = array($pagename); } if (!$pagelist) { $opt = array_merge($opt, @$_REQUEST); $pagelist = MakePageList($pagename, $opt, 0); } # process list of pages in feed $rdfseq = ''; $pl = array(); foreach($pagelist as $pn) { if (!PageExists($pn)) continue; if (!isset($PCache[$pn]['time'])) { $page = ReadPage($pn, READPAGE_CURRENT); PCache($pn, $page); } $pc = & $PCache[$pn]; $pl[] = $pn; if (@$opt['count'] && count($pl) >= $opt['count']) break; $rdfseq .= FmtPageName("\n", $pn); if ($pc['time'] > $feedtime) $feedtime = $pc['time']; } $pagelist = $pl; $FmtV['$FeedRDFSeq'] = $rdfseq; $FmtV['$FeedISOTime'] = gmstrftime($ISOTimeFmt, $feedtime); $FmtV['$FeedRSSTime'] = gmdate($RSSTimeFmt, $feedtime); # format start of feed $out = FmtPageName($f['feed']['_start'], $pagename); # format feed elements foreach($f['feed'] as $k => $v) { if ($k{0} == '_' || !$v) continue; $x = FmtPageName($v, $pagename); if (!$x) continue; $out .= ($v{0} == '<') ? $x : "<$k>$x\n"; } # format items in feed if (@$f['feed']['_items']) $out .= FmtPageName($f['feed']['_items'], $pagename); foreach($pagelist as $pn) { $page = &$PCache[$pn]; $FmtV['$ItemDesc'] = @$page['description']; $FmtV['$ItemISOTime'] = gmstrftime($ISOTimeFmt, $page['time']); $FmtV['$ItemRSSTime'] = gmdate($RSSTimeFmt, $page['time']); $out .= FmtPageName($f['item']['_start'], $pn); foreach((array)@$f['item'] as $k => $v) { if ($k{0} == '_' || !$v) continue; if (is_callable($v)) { $out .= $v($pn, $page, $k); continue; } if (strpos($v, '$LastModifiedBy') !== false && !@$page['author']) continue; if (strpos($v, '$Category') !== false) { if (preg_match_all("/(?<=^|,)$CategoryGroup\\.([^,]+)/", @$page['targets'], $match)) { foreach($match[1] as $c) { $FmtV['$Category'] = $c; $out .= FmtPageName($v, $pn); } } continue; } $x = FmtPageName($v, $pn); if (!$x) continue; $out .= ($v{0} == '<') ? $x : "<$k>$x\n"; } $out .= FmtPageName($f['item']['_end'], $pn); } $out .= FmtPageName($f['feed']['_end'], $pagename); foreach((array)@$f['feed']['_header'] as $fmt) header(FmtPageName($fmt, $pagename)); print str_replace(array_keys($EntitiesTable), array_values($EntitiesTable), $out); } ## RSSEnclosure is called in ?action=rss to generate ## tags for any pages that have an attached "PageName.mp3" file. ## The set of attachments to enclose is given by $RSSEnclosureFmt. function RSSEnclosure($pagename, &$page, $k) { global $RSSEnclosureFmt, $UploadFileFmt, $UploadExts; if (!function_exists('MakeUploadName')) return ''; SDV($RSSEnclosureFmt, array('{$Name}.mp3')); $encl = ''; foreach((array)$RSSEnclosureFmt as $fmt) { $path = FmtPageName($fmt, $pagename); $upname = MakeUploadName($pagename, $path); $filepath = FmtPageName("$UploadFileFmt/$upname", $pagename); if (file_exists($filepath)) { $length = filesize($filepath); $type = @$UploadExts[preg_replace('/.*\\./', '', $filepath)]; $url = LinkUpload($pagename, 'Attach:', $path, '', '', '$LinkUrl'); $encl .= "<$k url='$url' length='$length' type='$type' />"; } } return $encl; } ## Since most feeds don't understand html character entities, we ## convert the common ones to their numeric form here. SDVA($EntitiesTable, array( # entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent" ' ' => ' ', '¡' => '¡', '¢' => '¢', '£' => '£', '¤' => '¤', '¥' => '¥', '¦' => '¦', '§' => '§', '¨' => '¨', '©' => '©', 'ª' => 'ª', '«' => '«', '¬' => '¬', '­' => '­', '®' => '®', '¯' => '¯', '°' => '°', '±' => '±', '²' => '²', '³' => '³', '´' => '´', 'µ' => 'µ', '¶' => '¶', '·' => '·', '¸' => '¸', '¹' => '¹', 'º' => 'º', '»' => '»', '¼' => '¼', '½' => '½', '¾' => '¾', '¿' => '¿', 'À' => 'À', 'Á' => 'Á', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Å' => 'Å', 'Æ' => 'Æ', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'Ì' => 'Ì', 'Í' => 'Í', 'Î' => 'Î', 'Ï' => 'Ï', 'Ð' => 'Ð', 'Ñ' => 'Ñ', 'Ò' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Õ' => 'Õ', 'Ö' => 'Ö', '×' => '×', 'Ø' => 'Ø', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'Ý' => 'Ý', 'Þ' => 'Þ', 'ß' => 'ß', 'à' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'å' => 'å', 'æ' => 'æ', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'í' => 'í', 'î' => 'î', 'ï' => 'ï', 'ð' => 'ð', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ö' => 'ö', '÷' => '÷', 'ø' => 'ø', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'þ' => 'þ', 'ÿ' => 'ÿ', # entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent" '"' => '"', #'&' => '&#38;', #'<' => '&#60;', #'>' => '>', ''' => ''', 'Œ' => 'Œ', 'œ' => 'œ', 'Š' => 'Š', 'š' => 'š', 'Ÿ' => 'Ÿ', 'ˆ' => 'ˆ', '˜' => '˜', ' ' => ' ', ' ' => ' ', ' ' => ' ', '‌' => '‌', '‍' => '‍', '‎' => '‎', '‏' => '‏', '–' => '–', '—' => '—', '‘' => '‘', '’' => '’', '‚' => '‚', '“' => '“', '”' => '”', '„' => '„', '†' => '†', '‡' => '‡', '‰' => '‰', '‹' => '‹', '›' => '›', '€' => '€', # entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent" 'ƒ' => 'ƒ', 'Α' => 'Α', 'Β' => 'Β', 'Γ' => 'Γ', 'Δ' => 'Δ', 'Ε' => 'Ε', 'Ζ' => 'Ζ', 'Η' => 'Η', 'Θ' => 'Θ', 'Ι' => 'Ι', 'Κ' => 'Κ', 'Λ' => 'Λ', 'Μ' => 'Μ', 'Ν' => 'Ν', 'Ξ' => 'Ξ', 'Ο' => 'Ο', 'Π' => 'Π', 'Ρ' => 'Ρ', 'Σ' => 'Σ', 'Τ' => 'Τ', 'Υ' => 'Υ', 'Φ' => 'Φ', 'Χ' => 'Χ', 'Ψ' => 'Ψ', 'Ω' => 'Ω', 'α' => 'α', 'β' => 'β', 'γ' => 'γ', 'δ' => 'δ', 'ε' => 'ε', 'ζ' => 'ζ', 'η' => 'η', 'θ' => 'θ', 'ι' => 'ι', 'κ' => 'κ', 'λ' => 'λ', 'μ' => 'μ', 'ν' => 'ν', 'ξ' => 'ξ', 'ο' => 'ο', 'π' => 'π', 'ρ' => 'ρ', 'ς' => 'ς', 'σ' => 'σ', 'τ' => 'τ', 'υ' => 'υ', 'φ' => 'φ', 'χ' => 'χ', 'ψ' => 'ψ', 'ω' => 'ω', 'ϑ' => 'ϑ', 'ϒ' => 'ϒ', 'ϖ' => 'ϖ', '•' => '•', '…' => '…', '′' => '′', '″' => '″', '‾' => '‾', '⁄' => '⁄', '℘' => '℘', 'ℑ' => 'ℑ', 'ℜ' => 'ℜ', '™' => '™', 'ℵ' => 'ℵ', '←' => '←', '↑' => '↑', '→' => '→', '↓' => '↓', '↔' => '↔', '↵' => '↵', '⇐' => '⇐', '⇑' => '⇑', '⇒' => '⇒', '⇓' => '⇓', '⇔' => '⇔', '∀' => '∀', '∂' => '∂', '∃' => '∃', '∅' => '∅', '∇' => '∇', '∈' => '∈', '∉' => '∉', '∋' => '∋', '∏' => '∏', '∑' => '∑', '−' => '−', '∗' => '∗', '√' => '√', '∝' => '∝', '∞' => '∞', '∠' => '∠', '∧' => '∧', '∨' => '∨', '∩' => '∩', '∪' => '∪', '∫' => '∫', '∴' => '∴', '∼' => '∼', '≅' => '≅', '≈' => '≈', '≠' => '≠', '≡' => '≡', '≤' => '≤', '≥' => '≥', '⊂' => '⊂', '⊃' => '⊃', '⊄' => '⊄', '⊆' => '⊆', '⊇' => '⊇', '⊕' => '⊕', '⊗' => '⊗', '⊥' => '⊥', '⋅' => '⋅', '⌈' => '⌈', '⌉' => '⌉', '⌊' => '⌊', '⌋' => '⌋', '⟨' => '〈', '⟩' => '〉', '◊' => '◊', '♠' => '♠', '♣' => '♣', '♥' => '♥', '♦' => '♦'));