mirror of
https://github.com/processwire/processwire.git
synced 2025-08-13 10:15:28 +02:00
Improvements to MarkupRSS core module, mostly with code tweaks and new phpdoc
This commit is contained in:
@@ -7,12 +7,13 @@
|
||||
* This is intended to be used directly from a template file. See usage below.
|
||||
*
|
||||
* USAGE
|
||||
* -----
|
||||
* ~~~~~~
|
||||
* $rss = $modules->get("MarkupRSS");
|
||||
* $rss->title = "Latest updates";
|
||||
* $rss->description = "The most recent pages updated on my site";
|
||||
* $items = $pages->find("limit=10, sort=-modified"); // or any pages you want
|
||||
* $rss->render($items);
|
||||
* ~~~~~~
|
||||
*
|
||||
* See also the $defaultConfigData below (first thing in the class) to see what
|
||||
* options you can change at runtime.
|
||||
@@ -20,11 +21,40 @@
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @property string $title
|
||||
* @property string $url
|
||||
* @property string $description
|
||||
* @property string $xsl
|
||||
* @property string $css
|
||||
* @property string $copyright
|
||||
* @property int $ttl
|
||||
* @property bool $stripTags
|
||||
* @property string $itemTitleField
|
||||
* @property string $itemDateField
|
||||
* @property string $itemDescriptionField
|
||||
* @property string $itemDescriptionLength
|
||||
* @property string $itemAuthorField
|
||||
* @property string $itemAuthorElement
|
||||
* @property string $header
|
||||
* @property array|PageArray $feedPages
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class MarkupRSS extends WireData implements Module, ConfigurableModule {
|
||||
|
||||
/**
|
||||
* Return general info about the module for ProcessWire
|
||||
*
|
||||
*/
|
||||
public static function getModuleInfo() {
|
||||
return array(
|
||||
'title' => 'Markup RSS Feed',
|
||||
'version' => 103,
|
||||
'summary' => 'Renders an RSS feed. Given a PageArray, renders an RSS feed of them.',
|
||||
);
|
||||
}
|
||||
|
||||
protected static $defaultConfigData = array(
|
||||
'title' => 'Untitled RSS Feed',
|
||||
@@ -43,73 +73,90 @@ class MarkupRSS extends WireData implements Module, ConfigurableModule {
|
||||
'itemAuthorElement' => 'dc:creator', // may be 'dc:creator' or 'author'
|
||||
'header' => 'Content-Type: application/xml; charset=utf-8;',
|
||||
'feedPages' => array(),
|
||||
);
|
||||
|
||||
/**
|
||||
* Return general info about the module for ProcessWire
|
||||
*
|
||||
*/
|
||||
public static function getModuleInfo() {
|
||||
return array(
|
||||
'title' => 'Markup RSS Feed',
|
||||
'version' => 102,
|
||||
'summary' => 'Renders an RSS feed. Given a PageArray, renders an RSS feed of them.',
|
||||
'permanent' => false,
|
||||
'singular' => false,
|
||||
'autoload' => false,
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the default config data
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
foreach(self::$defaultConfigData as $key => $value) {
|
||||
$this->set($key, $value);
|
||||
}
|
||||
parent::__construct();
|
||||
$this->setArray(self::$defaultConfigData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Necessary to fulfill Module interface, even though not using it currently
|
||||
* Module init
|
||||
*
|
||||
*/
|
||||
public function init() { }
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
protected function ent1($str) {
|
||||
return $this->wire('sanitizer')->entities1($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
protected function ent($str) {
|
||||
return $this->wire('sanitizer')->entities($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render RSS header
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
protected function renderHeader() {
|
||||
|
||||
$out = "<?xml version='1.0' encoding='utf-8' ?>\n";
|
||||
|
||||
if($this->xsl) $out .= "<?xml-stylesheet type='text/xsl' href='{$this->xsl}' ?>\n";
|
||||
if($this->css) $out .= "<?xml-stylesheet type='text/css' href='{$this->css}' ?>\n";
|
||||
|
||||
if(!$this->url) $this->url = $this->page->httpUrl;
|
||||
|
||||
$out .= "<rss version='2.0' xmlns:dc='http://purl.org/dc/elements/1.1/'>\n" .
|
||||
"<channel>\n" .
|
||||
"\t<title>{$this->title}</title>\n" .
|
||||
"\t<link>{$this->url}</link>\n" .
|
||||
"\t<description>{$this->description}</description>\n" .
|
||||
"\t<pubDate>" . date(DATE_RSS) . "</pubDate>\n";
|
||||
$xsl = $this->ent1($this->xsl);
|
||||
$css = $this->ent1($this->css);
|
||||
$title = $this->ent1($this->title);
|
||||
$url = $this->ent1($this->url);
|
||||
$description = $this->ent1($this->description);
|
||||
$pubDate = date(\DATE_RSS);
|
||||
$ttl = (int) $this->ttl;
|
||||
$copyright = $this->ent1($this->copyright);
|
||||
|
||||
if($this->copyright) $out .= "\t<copyright>{$this->copyright}</copyright>\n";
|
||||
if($this->ttl) $out .= "\t<ttl>{$this->ttl}</ttl>\n";
|
||||
$out = "<?xml version='1.0' encoding='utf-8' ?>\n";
|
||||
if($xsl) $out .= "<?xml-stylesheet type='text/xsl' href='$xsl' ?>\n";
|
||||
if($css) $out .= "<?xml-stylesheet type='text/css' href='$css' ?>\n";
|
||||
|
||||
$out .=
|
||||
"<rss version='2.0' xmlns:dc='http://purl.org/dc/elements/1.1/'>\n" .
|
||||
"<channel>\n" .
|
||||
"\t<title>$title</title>\n" .
|
||||
"\t<link>$url</link>\n" .
|
||||
"\t<description>$description</description>\n" .
|
||||
"\t<pubDate>$pubDate</pubDate>\n";
|
||||
|
||||
if($copyright) $out .= "\t<copyright>$copyright</copyright>\n";
|
||||
if($ttl) $out .= "\t<ttl>$ttl</ttl>\n";
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render individual RSS item
|
||||
*
|
||||
* @param Page $page
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
protected function renderItem(Page $page) {
|
||||
|
||||
$title = strip_tags($page->get($this->itemTitleField));
|
||||
if(empty($title)) return '';
|
||||
|
||||
$title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
|
||||
$title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
|
||||
$title = str_replace(''', ''', $title);
|
||||
@@ -123,29 +170,38 @@ class MarkupRSS extends WireData implements Module, ConfigurableModule {
|
||||
$author = '';
|
||||
if($this->itemAuthorField) {
|
||||
$author = $page->getUnformatted($this->itemAuthorField);
|
||||
if($author instanceof Page) $author = $page->get('title|name');
|
||||
$author = (string) $author;
|
||||
if(strlen($author)) {
|
||||
$author = $this->wire('sanitizer')->entities($author);
|
||||
$author = $this->ent($author);
|
||||
$author = "\t\t<$this->itemAuthorElement>$author</$this->itemAuthorElement>\n";
|
||||
} else $author = '';
|
||||
} else {
|
||||
$author = '';
|
||||
}
|
||||
}
|
||||
|
||||
$description = $page->get($this->itemDescriptionField);
|
||||
if(is_null($description)) $description = '';
|
||||
$description = $this->truncateDescription(trim($description));
|
||||
$description = $description === null ? '' : $this->ent1($this->truncateDescription($description));
|
||||
$description = '<![CDATA[' . $description . ']]';
|
||||
|
||||
$out = "\t<item>\n" .
|
||||
"\t\t<title>$title</title>\n" .
|
||||
"\t\t<description><![CDATA[$description]]></description>\n" .
|
||||
$pubDate . $author .
|
||||
"\t\t<link>{$page->httpUrl}</link>\n" .
|
||||
"\n\t<guid>{$page->httpUrl}</guid>\n" .
|
||||
"\t</item>\n";
|
||||
$out =
|
||||
"\t<item>\n" .
|
||||
"\t\t<title>$title</title>\n" .
|
||||
"\t\t<description>$description</description>\n" .
|
||||
$pubDate .
|
||||
$author .
|
||||
"\t\t<link>$page->httpUrl</link>\n" .
|
||||
"\n\t<guid>$page->httpUrl</guid>\n" .
|
||||
"\t</item>\n";
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the feed and return it
|
||||
*
|
||||
* @param PageArray|null $feedPages
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function renderFeed(PageArray $feedPages = null) {
|
||||
@@ -166,6 +222,9 @@ class MarkupRSS extends WireData implements Module, ConfigurableModule {
|
||||
|
||||
/**
|
||||
* Render the feed and echo it (with proper http header)
|
||||
*
|
||||
* @param PageArray|null $feedPages
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function render(PageArray $feedPages = null) {
|
||||
@@ -176,11 +235,16 @@ class MarkupRSS extends WireData implements Module, ConfigurableModule {
|
||||
|
||||
/**
|
||||
* Truncate the description to a specific length and then truncate to avoid splitting any words.
|
||||
*
|
||||
* @param string $str
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
protected function truncateDescription($str) {
|
||||
|
||||
$str = trim($str);
|
||||
$maxlen = $this->itemDescriptionLength;
|
||||
|
||||
if(!$maxlen) return $str;
|
||||
|
||||
// note: tags are not stripped if itemDescriptionLength == 0 and stripTags == true
|
||||
@@ -214,10 +278,17 @@ class MarkupRSS extends WireData implements Module, ConfigurableModule {
|
||||
|
||||
/**
|
||||
* Provide fields for configuring this module
|
||||
*
|
||||
* @param array $data
|
||||
* @return InputfieldWrapper
|
||||
*
|
||||
*/
|
||||
public function getModuleConfigInputfields(array $data) {
|
||||
|
||||
/** @var Modules $modules */
|
||||
$modules = $this->wire('modules');
|
||||
|
||||
/** @var InputfieldWrapper $inputfields */
|
||||
$inputfields = $this->wire(new InputfieldWrapper());
|
||||
$inputfields->description =
|
||||
"Select the default options for any given feed. Each of these may be overridden in the API, " .
|
||||
@@ -228,73 +299,83 @@ class MarkupRSS extends WireData implements Module, ConfigurableModule {
|
||||
if(!isset($data[$key])) $data[$key] = $value;
|
||||
}
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldText');
|
||||
/** @var InputfieldText $f */
|
||||
$f = $modules->get('InputfieldText');
|
||||
$f->attr('name', 'title');
|
||||
$f->attr('value', $data['title']);
|
||||
$f->label = "Default Feed Title";
|
||||
$inputfields->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldURL');
|
||||
/** @var InputfieldURL $f */
|
||||
$f = $modules->get('InputfieldURL');
|
||||
$f->attr('name', 'url');
|
||||
$f->attr('value', $data['url']);
|
||||
$f->label = "Default Feed URL";
|
||||
$f->description = "The URL on your site that serves as a feed index. May also be left blank.";
|
||||
$inputfields->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldText');
|
||||
/** @var InputfieldText $f */
|
||||
$f = $modules->get('InputfieldText');
|
||||
$f->attr('name', 'description');
|
||||
$f->attr('value', $data['description']);
|
||||
$f->label = "Default Feed Description";
|
||||
$f->description = "The default description for a feed. May also be left blank.";
|
||||
$inputfields->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldURL');
|
||||
/** @var InputfieldURL $f */
|
||||
$f = $modules->get('InputfieldURL');
|
||||
$f->attr('name', 'xsl');
|
||||
$f->attr('value', $data['xsl']);
|
||||
$f->label = "Default Link to XSL Stylesheet";
|
||||
$f->description = "Optional URL/link to an XSL stylesheet. Default is none.";
|
||||
$inputfields->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldURL');
|
||||
$f = $modules->get('InputfieldURL');
|
||||
$f->attr('name', 'css');
|
||||
$f->attr('value', $data['css']);
|
||||
$f->label = "Default Link to CSS Stylesheet";
|
||||
$f->description = "Optional URL/link to a CSS stylesheet. Default is none.";
|
||||
$inputfields->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldText');
|
||||
/** @var InputfieldText $f */
|
||||
$f = $modules->get('InputfieldText');
|
||||
$f->attr('name', 'copyright');
|
||||
$f->attr('value', $data['copyright']);
|
||||
$f->label = "Default Feed Copyright";
|
||||
$f->description = "The default copyright statement for a feed. Default is blank.";
|
||||
$inputfields->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldInteger');
|
||||
/** @var InputfieldInteger $f */
|
||||
$f = $modules->get('InputfieldInteger');
|
||||
$f->attr('name', 'ttl');
|
||||
$f->attr('value', (int) $data['ttl']);
|
||||
$f->label = "Default Feed TTL";
|
||||
$f->description = "TTL stands for \"time to live\" in minutes. It indicates how long a channel can be cached before refreshing from the source. Default is 60.";
|
||||
$inputfields->add($f);
|
||||
|
||||
$f1 = $this->wire('modules')->get('InputfieldSelect');
|
||||
/** @var InputfieldSelect $f1 */
|
||||
$f1 = $modules->get('InputfieldSelect');
|
||||
$f1->attr('name', 'itemTitleField');
|
||||
$f1->attr('value', $data['itemTitleField']);
|
||||
$f1->label = "Default Feed Item Title Field";
|
||||
$f1->description = "The default field to use as an individual feed item's title.";
|
||||
|
||||
$f2 = $this->wire('modules')->get('InputfieldSelect');
|
||||
/** @var InputfieldSelect $f2 */
|
||||
$f2 = $modules->get('InputfieldSelect');
|
||||
$f2->attr('name', 'itemDescriptionField');
|
||||
$f2->attr('value', $data['itemDescriptionField']);
|
||||
$f2->label = "Default Feed Item Description Field";
|
||||
$f2->description = "The default field to use as an individual feed item's description (typically a summary or body field).";
|
||||
|
||||
$f2a = $this->wire('modules')->get('InputfieldInteger');
|
||||
/** @var InputfieldInteger $f2a */
|
||||
$f2a = $modules->get('InputfieldInteger');
|
||||
$f2a->attr('name', 'itemDescriptionLength');
|
||||
$f2a->attr('value', (int) $data['itemDescriptionLength']);
|
||||
$f2a->label = "Maximum Characters for Item Description Field";
|
||||
$f2a->description = "The item description will be truncated to be no longer than the max length provided. Specify '0' for no max length. When there is no max length, markup tags will not be stripped.";
|
||||
|
||||
$f3 = $this->wire('modules')->get('InputfieldSelect');
|
||||
/** @var InputfieldSelect $f3 */
|
||||
$f3 = $modules->get('InputfieldSelect');
|
||||
$f3->attr('name', 'itemDateField');
|
||||
$f3->attr('value', $data['itemDateField']);
|
||||
$f3->label = "Default Feed Item Date Field";
|
||||
|
Reference in New Issue
Block a user