👀 Get a glimpse of Kirby 5 Learn more
Skip to content

Content from an RSS feed

Fetch your Medium blog into your own site. In this example we will create pages from an RSS feed.

For this example, we use Medium's RSS feeds to integrate articles as virtual pages into our own site.

To start, we create a parent page, e.g. rssfeed in the /content folder and inside it an rssfeed.txt text file.

Let's give our parent page a title and maybe a short intro.

/content/rssfeed/rssfeed.txt
Title: My virtual feed

----

Intro: This page lists articles from an RSS feed.

Creating the virtual subpages

To fetch the virtual children, we create a new Rssfeed page model which will read the RSS feed and create a virtual child page for each entry on the fly. The Remote class is our friend and helps us with handling this remote request.

/site/models/rssfeed.php
<?php

use Kirby\Uuid\Uuid;

class RssfeedPage extends Page {

    public function children(): Pages
    {
        if ($this->children instanceof Pages) {
            return $this->children;
        }

        $results = [];
        $pages   = [];

        // use the URL of the feed you want to fetch
        $request = Remote::get('https://open.nytimes.com/feed');

        // if the request was sucessfully, parse feed as $results
        if ($request->code() === 200) {
            $results = Xml::parse($request->content());
        }

        // if we have any results, create the child page props for each result
        if (count($results) > 0) {
            foreach ($results['channel']['item'] as $item) {
                $pages[] = [
                    'slug'     => Str::slug($item['title']),
                    'template' => 'feeditem',
                    'model'    => 'feeditem',
                    'content'  => [
                        'title'       => $item['title'],
                        'date'        => $item['pubDate'] ?? '',
                        'description' => $item['description'] ?? '',
                        'link'        => $item['link'] ?? '',
                        'text'        => $item['contentencoded'] ?? '',
                        'categories'  => isset($item['category']) ? implode(',', $item['category']) : '',
                        'author'      => $item['dccreator'] ?? '',
                        'uuid'        => Uuid::generate(),
                    ]
                ];
            }
        }

        // create a Pages collection for the child pages
        return $this->children = Pages::factory($pages, $this);
    }

}

Unless you have disabled UUIDs in your config, you have to pass a uuid field in the content array to prevent Kirby from generating the page in the file system when the $page->uuid() method is called.

If you generate the UUIDs automatically like in the example above, they will change at every load. However, if you want to reference your virtual pages anywhere with their UUID, make sure to use a unique string that does not change.

The template

With this new page model in place, we can now render all feed articles in our rssfeed.php template as if they were regular Kirby children pages.

/site/templates/rssfeed.php
<?php snippet('header') ?>

<main>
  <header>
    <h1><?= $page->title() ?></h1>
  </header>


  <div class="feed">
    <?php foreach ($page->children()->sortBy('date', 'desc') as $item): ?>
    <article>
      <header class="article-header">
        <a href="<?= $item->url() ?>">
          <h2><?= $item->title() ?></h2>
          <time><?= $item->date()->toDate('d F Y') ?></time>
        </a>
      </header>
    </article>
    <?php endforeach ?>
  </div>

</main>
<?php snippet('footer') ?>

Subpages

Each article will automatically get its own subpage. Routing will work out of the box and you can create an feeditem.php template (as we defined above when setting the child page props) to render each individual article.

/site/templates/feeditem.php
<?php snippet('header') ?>

<main>
  <article class="feedarticle">
    <header class="article-header">
      <h1><?= $page->title() ?></h1>
      <time><?= $page->date()->toDate('d F Y') ?></time>
      <?php if ($page->categories()->isNotEmpty()): ?>
        <p class="tags"><?= $page->categories() ?></p>
      <?php endif ?>
    </header>

    <div class="article-body">
      <?php if ($page->author()->isNotEmpty()): ?>
        <p>by <?= $page->author() ?></p>
      <?php endif ?>
      <?= $page->text()->excerpt(500) ?>
      <a href="<?= $page->link() ?>">Continue reading on Medium</a>
    </div>
  </article>
</main>

<?php snippet('footer') ?>