Bringing the Feed Back
After I recently launched the new look for this web site, I noticed something interesting about my traffic: a lot of 404
responses for /feed
or /feed.xml
.
grep feed /var/log/nginx/access.log | grep -v Mozilla | grep -ahoE '"[^"]+"$' | sort | uniq -c | sort -nr
189 "davefeedread v0.4.14"
176 "PlanetPHPAggregator/0.2 (PHP5) (http://planet-php.org/)"
124 "Tiny Tiny RSS/21.02-a42e8aad9 (http://tt-rss.org/)"
108 "Tiny Tiny RSS/20.11-328d7b55c (http://tt-rss.org/)"
99 "Tiny Tiny RSS/20.06-06cc6e3 (http://tt-rss.org/)"
92 "Fever/1.31 (Feed Parser; http://feedafever.com; Allow like Gecko)"
85 "Tiny Tiny RSS/17.12 (http://tt-rss.org/)"
85 "MagpieRSS/0.72 \x5C(+http://magpierss.sf.net\x5C)"
85 "MagpieRSS/0.72 (+http://magpierss.sf.net)"
49 "Fever/1.39 (Feed Parser; http://feedafever.com; Allow like Gecko)"
18 "rogerbot/1.0 (http://www.moz.com/dp/rogerbot, rogerbot-crawler@moz.com)"
14 "FeedFetcher-Google; (+http://www.google.com/feedfetcher.html)"
4 "Feedspot/1.0 (+https://www.feedspot.com/fs/fetcher; like FeedFetcher-Google)"
2 "NetNewsWire (RSS Reader; https://ranchero.com/netnewswire/)"
1 "RSSMicro.com RSS/Atom Feed Robot"
1 "Feedly/1.0 (+http://www.feedly.com/fetcher.html; 9 subscribers; like FeedFetcher-Google)"
I originally suspected that the feed from my old site wasn't in wide use, so I didn't bother porting it over when I migrated the site. However, the new site launch provided traffic that disproved my suspicion. So, I decided to bring the feed back.
But now that the new site was using Statamic, I wasn't sure of the best way to go about it. I had to do some research to come up with a solution and thought I'd take a post to discuss the particulars.
No Luck with Addons
A cursory search turned up an addon that, upon closer inspection, turned out to be for Statamic 2, where I'm using Statamic 3.
I found and joined the Statamic Discord and ended up speaking to the author of that addon, who linked me to a partially done port for Statamic 3.
I wasn't able to get this port to work and filed a few issues against its repository. The author encouraged me to submit pull requests or create my own fork, but with related documentation for extending Statamic being on the sparse side, I suspected that was more effort than I wanted to invest.
A Laravel Solution
The solution I settled on, while not as easily reusable as I would like, will work well enough as an interim measure until I can figure out how to convert it into an addon.
Statamic is built on Laravel, so I opted to pull the spatie/laravel-feed
Laravel package into my web site project.
Per the package's installation instructions, I added a call to its Route::feeds()
macro to the routes/web.php
file.
When I tried to publish the config file, I received this error: Unable to locate publishable resources.
However, it turns out this wasn't necessary and I was able to manually copy the config file example from the package README to config/feed.php
. The package worked fine once I had configured it properly.
The Configuration
Getting this configuration right took some digging through source code and dd()
calls. I'm using the Cool Writings starter kit, but you should be able to tweak this to work with your installation.
<?php
use Spatie\Feed\FeedItem;
use Statamic\Entries\Entry;
use Statamic\Facades\User;
return [
'feeds' => [
'main' => [
'items' => fn() => Entry::query()
->where('collection', 'articles')
->where('published', true)
->where('date', '<=', now())
->orderBy('date', 'desc')
->orderBy('title')
->limit(20)
->get()
->map(function(Entry $entry): FeedItem {
return FeedItem::create([
'id' => $entry->url(),
'title' => $entry->get('title'),
'summary' => $entry->excerpt ?? '',
'updated' => $entry->date(),
'link' => $entry->url(),
'author' => implode(', ', $entry->authors()->map(
fn($id) => User::find($id)->name
)->all()),
]);
}),
'url' => '/feed.xml',
'title' => 'Matthew Turland',
'description' => 'Blog posts from matthewturland.com',
'language' => 'en-US',
'view' => 'feed::feed',
],
],
];
This fetches the 20 most recent published entries with a date on or before today and converts them into FeedItem
instances that the spatie/laravel-feed
package can then render as feed entries.
Feed Links
Now that I had a rendering feed, I needed to link to it in the <head>
tag of my Antlers layout template.
Unfortunately, spatie/laravel-feed
uses Blade, the Cool Writings starter kit templates use Antlers, and it turns out it's not possible to embed Blade templates in Antlers templates, so I wasn't able to use the view macro provided by spatie/laravel-feed
.
However, adding this snippet of markup to my layout template seemed to do the trick.
{{ foreach:config:feed.feeds as="feed" }}
<link rel="alternate" type="{{ feed.type ?? 'application/atom+xml' }}" href="{{ feed.url }}" title="{{ feed.title }}">
{{ /foreach:config:feed.feeds }}
Static Generation
I'm using statamic/ssg
to generate a static build of my site, which is what you're viewing now.
By default, this addon doesn't generate static versions of routes like the one that spatie/laravel-feed
creates for the feed.
To include this route in the build process, I had to open config/statamic/ssg.php
and modify the array it returns to include this segment.
<?php
return [
'urls' => [
'/feed.xml',
],
// ...
];
Ideally, this would dynamically pull in all defined feeds, but I haven't been successful in accessing content or configuration from other addons from the statamic/ssg
configuration. Hopefully, this is a shortcoming that I can address in an addon.
Lastly, the base URL for links needs to be set in configuration for it to be correct in the static build. I found the relevant setting in config/app.php
.
<?php
return [
// ...
// Commented this out
// 'url' => env('APP_URL', 'http://localhost'),
// Added this
'url' => 'https://matthewturland.com',
// ...
];
Some Finishing Touches
One drawback of statamic/ssg
is that the static output of the /feed.xml
route is actually written to /feed.xml/index.html
with no option to customize the destination.
To address this, I tacked some additional commands onto the build
script in my composer.json
file to move the file to the correct path in the build.
mv ./storage/app/static/feed.xml/index.html /tmp/feed.xml
rm -fR ./storage/app/static/feed.xml
mv /tmp/feed.xml ./storage/app/static/feed.xml
Lastly, in order to allow /feed
to resolve as well as /feed.xml
, I added a rewrite
directive to my nginx configuration.
rewrite ^/feed/?$ /feed.xml permanent;
Epilogue
I hope that the Statamic community grows and that the barrier to entry for extending it becomes lower over time.
That said, I'm glad I was at least able to hack together a working solution for those accessing my content via feeds in the meantime.
I hope you found this post useful, or at least interesting. Thanks for reading!