RSS and Atom Feed Subscription Implementation
RSS and Atom feeds allow readers to subscribe to updates via aggregators (Feedly, Inoreader, Reeder). Feeds are also used by news aggregators and SEO tools for indexing fresh content.
Laravel: RSS Feed
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cache;
class FeedController extends Controller
{
public function rss(): Response
{
$feed = Cache::remember('rss_feed', 900, fn() => $this->buildRss()); // 15 minutes
return response($feed, 200)->header('Content-Type', 'application/rss+xml; charset=utf-8');
}
private function buildRss(): string
{
$articles = Article::published()
->latest('published_at')
->limit(50)
->get();
$lastBuild = $articles->first()?->published_at ?? now();
return view('feeds.rss', compact('articles', 'lastBuild'))->render();
}
public function atom(): Response
{
$feed = Cache::remember('atom_feed', 900, fn() => $this->buildAtom());
return response($feed, 200)->header('Content-Type', 'application/atom+xml; charset=utf-8');
}
}
<!-- resources/views/feeds/rss.blade.php -->
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
<channel>
<title>{{ config('app.name') }}</title>
<link>{{ url('/') }}</link>
<description>{{ config('app.description') }}</description>
<language>en</language>
<lastBuildDate>{{ $lastBuild->toRssString() }}</lastBuildDate>
<atom:link href="{{ route('feed.rss') }}" rel="self" type="application/rss+xml"/>
<image>
<url>{{ url('/logo.png') }}</url>
<title>{{ config('app.name') }}</title>
<link>{{ url('/') }}</link>
</image>
@foreach($articles as $article)
<item>
<title><![CDATA[{{ $article->title }}]]></title>
<link>{{ route('articles.show', $article->slug) }}</link>
<guid isPermaLink="true">{{ route('articles.show', $article->slug) }}</guid>
<pubDate>{{ $article->published_at->toRssString() }}</pubDate>
<author>{{ $article->author->email }} ({{ $article->author->name }})</author>
<description><![CDATA[{{ $article->excerpt }}]]></description>
@if($article->cover_image)
<media:content url="{{ $article->cover_url }}" medium="image"/>
@endif
@foreach($article->tags as $tag)
<category>{{ $tag->name }}</category>
@endforeach
</item>
@endforeach
</channel>
</rss>
Routes and Autodiscovery
// routes/web.php
Route::get('/feed', [FeedController::class, 'rss'])->name('feed.rss');
Route::get('/feed/atom', [FeedController::class, 'atom'])->name('feed.atom');
Route::get('/feed/{category}', [FeedController::class, 'category'])->name('feed.category');
<!-- In <head> for browser and aggregator autodiscovery -->
<link rel="alternate" type="application/rss+xml" title="{{ config('app.name') }} RSS" href="{{ route('feed.rss') }}">
<link rel="alternate" type="application/atom+xml" title="{{ config('app.name') }} Atom" href="{{ route('feed.atom') }}">
Implementation Timeline
RSS + Atom feed with caching and autodiscovery for Laravel: 0.5–1 day. With category/tag feeds and categorization: 1–2 days.







