diff --git a/.gitignore b/.gitignore index 864a81b..d331e65 100644 --- a/.gitignore +++ b/.gitignore @@ -68,4 +68,5 @@ Icon # --------------- /kirby -/site/plugins +/site/plugins/* +!/site/plugins/kirby-helpers diff --git a/site/plugins/kirby-helpers/index.php b/site/plugins/kirby-helpers/index.php new file mode 100644 index 0000000..e1615e8 --- /dev/null +++ b/site/plugins/kirby-helpers/index.php @@ -0,0 +1,7 @@ + 'src/RssFeed.php' +], __DIR__); diff --git a/site/plugins/kirby-helpers/src/RssFeed.php b/site/plugins/kirby-helpers/src/RssFeed.php new file mode 100644 index 0000000..2cfed7b --- /dev/null +++ b/site/plugins/kirby-helpers/src/RssFeed.php @@ -0,0 +1,151 @@ +createWriter(); + $this->initialiseDocument(); + $this->writeMetadata(); + + foreach ($this->articles as $article) { + /** @var Kirby\Cms\Page $article */ + $this->writeArticle($article); + } + + $this->finishDocument(); + + return $this->writer->outputMemory(); + } + + private function createWriter(): void + { + $this->writer = new XMLWriter(); + $this->writer->openMemory(); + $this->writer->setIndent(true); + $this->writer->setIndentString(' '); + } + + private function initialiseDocument(): void + { + $this->writer->startDocument('1.0', 'UTF-8', 'yes'); + $this->writer->startElement('rss'); + $this->writer->writeAttribute('version', '2.0'); + $this->writer->writeAttributeNs('xmlns', 'atom', null, 'http://www.w3.org/2005/Atom'); + } + + private function writeMetadata(): void + { + $this->openElement('channel'); + $this->writer->writeElement('title', $this->title()); + $this->writer->writeElement('link', url()); + $this->writer->writeElement('description', $this->description()); + $this->writer->writeElement('language', 'en-GB'); + $this->writer->writeElement('lastBuildDate', $this->lastBuildDate()); + $this->writer->writeElement('generator', 'Kirby CMS'); + $this->writer->writeElement('docs', 'https://www.rssboard.org/rss-specification'); + + $this->writeMetadataAtomLink(); + $this->writeMetadataImage(); + } + + private function writeMetadataAtomLink(): void + { + $this->openElementNs('atom', 'link', null); + $this->writer->writeAttribute('href', url($this->path)); + $this->writer->writeAttribute('rel', 'self'); + $this->writer->writeAttribute('type', 'application/rss+xml'); + $this->closeElement(); + } + + private function writeMetadataImage(): void + { + $this->openElement('image'); + $this->writer->writeElement('url', url('/assets/img/favicon/favicon.png')); + $this->writer->writeElement('title', $this->title()); + $this->writer->writeElement('link', url()); + $this->closeElement(); + } + + private function writeArticle(Page $article): void + { + $this->openElement('item'); + + $this->writer->writeElement('title', $article->title()->toString()); + $this->writer->writeElement('link', url($article->url())); + $this->writer->writeElement('guid', url($article->url())); + $this->writer->writeElement('pubDate', $article->date()->toDate(DATE_RSS)); + + $this->openElement('description'); + $this->writer->writeCdata($article->text()->kirbytext()->toString()); + $this->closeElement(); // description + + $this->closeElement(); // item + } + + private function finishDocument(): void + { + $this->closeRemainingElements(); + $this->writer->endDocument(); + } + + private function title(): string + { + return $this->site->title()->toString(); + } + + private function description(): string + { + return $this->site->description()->toString(); + } + + private function lastBuildDate(): string + { + return $this->articles->first()->date()->toDate(DATE_RSS); + } + + private function openElement(string $name): void + { + $this->writer->startElement($name); + $this->openElements++; + } + + private function openElementNs( + ?string $prefix, + string $name, + ?string $namespace + ): void { + $this->writer->startElementNs($prefix, $name, $namespace); + $this->openElements++; + } + + private function closeElement(): void + { + $this->writer->endElement(); + $this->openElements--; + } + + private function closeRemainingElements(): void + { + while ($this->openElements > 0) { + $this->closeElement(); + } + } +}