Statamic RSS/Atom Feed

Published on Mar 13, 2021
Topics: Meta, Statamic, Coding

I added an RSS/Atom feed to the blog. It wasn't all that difficult to do, but I am surprised this isn't baked in to Statamic somehow. The way I have it implemented was straight-forward and might benefit from some caching (preferably by letting NGINX cache a static file). I'm never going to see the kind traffic that would make this optimization worthwhile.

Also, my use case is crazy simple. My blog posts have almost no data, I don't include the author field or any pictures. It is just one feed, for one content type. There are certainly better ways to do this if you have a more complex use case.

Get On With It

Add Some Routes

I added two routes to return views (with no parent layout) and set the appropriate content types (atom is a special keyword in Statamic).

// routes/web.php
Route::statamic('/feed/rss', 'feed.rss', ['layout' => '', 'content_type' => 'application/rss+xml']);
Route::statamic('/feed/atom', 'feed.atom', ['layout' => '', 'content_type' => 'atom']);

Create Some Views

I then created two views to pull in articles and load them with XML, based on specs I found at for RSS and Atom, and also this guide from Craft, which helped show me how simple of a project this was really was (if you can write HTML you can make an RSS/Atom feed).

The Atom Template

{{# resources/views/feed/atom.antlers.html #}}
<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>{{ config:app:url }}{{ current_uri }}</id>
    <title>{{ settings:site_name }}</title>
    {{ collection:articles limit="1" as="articles" }}
    {{# Using last published article as our build date #}}
        <updated>{{ date format="r" }}</updated>
    {{ /collection:articles }}
    <link rel="self" type="application/atom+xml" href="{{ config:app:url }}{{ current_uri }}" />
    <link rel="alternate" type="text/html" href="{{ config:app:url }}" />

    {{ collection:articles limit="20" as="articles" }}
        {{ articles }}
            <entry>
                <id>{{ id }}</id>
                <title>{{ title }}</title>
                {{ if topics }}
                    {{ topics }}
                        <category term="{{ slug }}" name="{{ title }}" />
                    {{ /topics }}
                {{ /if }}
                <published>{{ date format="r" }}</published>
                <updated>{{ last_modified format="r" }}</updated>
                <link rel="alternate" type="text/html" href="{{ config:app:url }}{{ url }}" />
                {{# <author>
                    <name>@{{ entry.author.fullName }}</name>
                </author> #}}
                <summary>{{ excerpt }}</summary>
                <content type="html">
                    <![CDATA[{{ content }}]]>
                </content>
            </entry>
        {{ /articles }}
    {{ /collection:articles }}
</feed>

The RSS Template

{{# resources/views/feed/rss.antlers.html #}}
<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>{{ settings:site_name }}</title>
        <link>{{ config:app:url }}</link>
        <atom:link href="{{ config:app:url }}{{ current_uri }}" rel="self" type="application/rss+xml" />
        <description>{{ settings:site_description }}</description>
        <language>EN</language>
        <pubDate>{{ now format="r" }}</pubDate>
        {{ collection:articles limit="1" as="articles" }}
            {{# Using last published article as our build date #}}
            <lastBuildDate>{{ date format="r" }}</lastBuildDate>
        {{ /collection:articles }}
        {{ collection:articles limit="20" as="articles" }}
            {{ articles }}
                <item>
                    <title>{{ title }}</title>
                    {{ if topics }}
                        {{ topics }}
                            <category domain="{{ url }}">{{ title }}</category>
                        {{ /topics }}
                    {{ /if }}
                    <link>{{ config:app:url }}{{ url }}</link>
                    <pubDate>{{ date format="r" }}</pubDate>
                    <guid>{{ id }}</guid>
                    <description>
                        {{ excerpt }}
                    </description>
                </item>
            {{ /articles }}
        {{ /collection:articles }}
    </channel>
</rss>