Table of Contents
In this post, I'll explain how to create an RSS feed.
First create a route that will respond with a feed, in this example I'm using a controller called BlogController and a method called feed.
Route::get('feed', 'BlogController@feed');
In your feed method query a model, in this case ordering by a created_at column and take the first 20 records, pass the data to a view:
public function feed()
{
$posts = Post::orderBy('created_at', 'desc')->take(20)->get();
return view('feed')->with(compact('posts'));
}
At the top of the view use a Request header to set the content type to application/xml
Start an rss and channel tags, set the title, description and link url
{{ Request::header('Content-Type : application/xml') }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ config('app.name') }}</title>
<description>RSS Feed</description>
<link>{{ url('/') }}</link>
Next loop through the data
@foreach ($posts as $post)
Now create a blade php block, inside the @php using str_replace swap & and & and chate quotes.
Remove any slashes from the title, description, and slug.
Optionally an image can be embedded, in this case, a check is made to see if an image column is not empty, if so create an image tag.
@php
$post->title = str_replace("&", "&amp;", $post->title);
$post->description = str_replace("&rdquo;", "”", $post->description);
$post->description = str_replace("&ldquo;", "“", $post->description);
$post->title = stripslashes($post->title);
$post->description = stripslashes($post->description);
$post->slug = stripslashes($post->slug);
if ($post->image !='') {
$img = "<img src='".url($post->image)."' alt='".$post->title."' width='600'>";
} else {
$img = null;
}
@endphp
Next, create an item tag and display the following tags:
title - the title of the post
description - using CDATA display the img variable and description
pubDate - the date the post was created using date & strtotime to format the date lastly set the timezone.
link and guid - the url to the post
atomLlink - the link to the post
NOTE I make use of a column called $slug this is a custom field that holds a search engine friendly version of the title.
<item>
<title>{{ $post->title }}</title>
<description><![CDATA[{!! $img !!} {!! $post->description !!}]]></description>
<pubDate>{{ date('D, d M Y H:i:s', strtotime($post->created_at)) }} GMT</pubDate>
<link>{{ url($post->slug) }}</link>
<guid>{{ url($post->slug) }}</guid>
<atom:link href="{{ url($post->slug) }}" rel="self" type="application/rss+xml"/>
</item>
Lastly, close the foreach and tags.
@endforeach
</channel>
</rss>
Putting it all together
{{ Request::header('Content-Type : application/xml') }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ config('app.name') }}</title>
<description>RSS Feed</description>
<link>{{ url('/') }}</link>
@foreach ($posts as $post)
@php
$post->title = str_replace("&", "&amp;", $post->title);
$post->description = str_replace("&rdquo;", "”", $post->description);
$post->description = str_replace("&ldquo;", "“", $post->description);
$post->title = stripslashes($post->title);
$post->description = stripslashes($post->description);
$post->slug = stripslashes($post->slug);
if ($post->image !='') {
$img = "<img src='".url($post->image)."' alt='".$post->title."' width='600'>";
} else {
$img = null;
}
@endphp
<item>
<title>{{ $post->title }}</title>
<description><![CDATA[{!! $img !!} {!! $post->description !!}]]></description>
<pubDate>{{ date('D, d M Y H:i:s', strtotime($post->created_at)) }} GMT</pubDate>
<link>{{ url($post->slug) }}</link>
<guid>{{ url($post->slug) }}</guid>
<atom:link href="{{ url($post->slug) }}" rel="self" type="application/rss+xml"/>
</item>
@endforeach
</channel>
</rss>
An optional step is to add a link tag to your html head section.
<link href='{{ url('feed') }}' rel='alternate' title='RSS' type='application/rss+xml'/>