Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rss Laravel Package

thujohn/rss

thujohn/rss is a lightweight RSS feed generator for Laravel applications. It provides a simple API for defining channels, adding items, and outputting valid RSS/XML, making it easy to expose blog posts, news, or other dynamic content as syndication feeds.

View on GitHub
Deep Wiki
Context7

Getting Started

Requires Laravel 4 only — do not attempt to install this on L5+. Pull it in with Composer:

composer require thujohn/rss

Register the service provider and facade alias in app/config/app.php:

'providers' => [
    // ...
    'Thujohn\Rss\RssServiceProvider',
],

'aliases' => [
    // ...
    'RSS' => 'Thujohn\Rss\RssFacade',
],

The first thing to look at is vendor/thujohn/rss/src/Thujohn/Rss/Rss.php — it is a very thin wrapper around suin/php-rss-writer, so the API surface is basically feed(), channel(), item(), and render(). Everything else (valid channel elements, item elements) is documented by that upstream library, not by this package.

A minimal working feed route (app/routes.php):

Route::get('feed', function () {
    RSS::feed('2.0', 'UTF-8');

    RSS::channel([
        'title'       => 'My Blog',
        'description' => 'Recent posts',
        'link'        => URL::to('/'),
    ]);

    foreach (Post::latest()->take(20)->get() as $post) {
        RSS::item([
            'title'       => $post->title,
            'description' => $post->excerpt,
            'link'        => URL::to("posts/{$post->slug}"),
            'pubDate'     => $post->created_at->toRfc2822String(),
            'guid'        => URL::to("posts/{$post->slug}"),
        ]);
    }

    return Response::make(RSS::render(), 200, [
        'Content-Type' => 'application/rss+xml; charset=UTF-8',
    ]);
});

That last part is the whole point of the package: you build the feed imperatively and get back an XML string. Serving it with the right Content-Type is your job, not the package's.

Implementation Patterns

Dedicated feed controller. Keep feed-building out of closures as soon as you have more than one feed. A FeedController with one method per feed (posts, comments, podcast) makes routes readable and lets you reuse a private respond() helper that wraps RSS::render() with the correct headers.

One request, one feed. The facade resolves a shared instance; treat each feed as a self-contained method that starts with RSS::feed(...). If you need two feeds in one request (rare — e.g. an index page rendering two previews), build and render() the first before starting the second, and verify the output because state leakage produces feeds with duplicated items.

Loop + array mapping. The idiomatic pattern is to chunk your query and map models into plain arrays:

Post::latest()->take(50)->get()->each(function ($post) {
    RSS::item([
        'title'       => $post->title,
        'link'        => route('posts.show', $post->slug),
        'description' => strip_tags($post->body),
        'pubDate'     => $post->created_at->toRfc2822String(),
        'guid'        => route('posts.show', $post->slug),
        'author'      => $post->author->email . ' (' . $post->author->name . ')',
    ]);
});

Cache aggressively. Feeds are read by crawlers far more often than they change. Cache::remember('feed.posts', 15, function () { ... return RSS::render(); }) and return the cached string — this also sidesteps the cost of hydrating hundreds of Eloquent models on every poll.

Podcasts / media. Use the enclosure item key with url, length, and type for audio. This is the main reason people reach for a hand-rolled builder instead of a static feed generator.

Atom when required. RSS::feed('atom', 'UTF-8') switches the output format; the channel()/item() call shape stays the same, but element names and the required-element set change (Atom wants id, updated, author). Validate separately — RSS 2.0-valid code is not automatically Atom-valid.

Header via a filter or response macro. If you have several feeds, register a response macro or after-filter in L4 that sets application/rss+xml whenever the route name starts with feed., so nobody forgets the header on a new endpoint.

Gotchas and Tips

  • This is Laravel 4-only, end of life. Laravel 4 itself is unsupported. If you are starting anything new, use spatie/laravel-feed or willvincent/feed; keep this knowledge for maintaining legacy apps. That constraint explains the low dependents count.
  • Missing Content-Type is the #1 bug. Without the header, browsers render the XML as plain text or, worse, as HTML with tags stripped. Always return a Response with application/rss+xml.
  • Order matters. feed() must come first, channel() before any item(). The underlying writer throws if you add an item before a channel exists. Putting channel() inside the loop is a classic mistake and yields duplicated channel metadata.
  • No items throws. render() on a feed with zero items raises an exception from the upstream writer rather than returning an empty feed. Guard with if ($posts->isEmpty()) { return Response::make('', 404); } or always emit a placeholder.
  • pubDate is a string, not a DateTime. The package passes values straight through to the XML writer. Hand it a Carbon instance and you get either a stringified object or a malformed date. Always ->toRfc2822String() (or date('r', $timestamp)) for RSS 2.0.
  • Escaping is automatic; HTML is not. The writer escapes entities, so <strong> in a description becomes escaped text in many readers. If you intend rendered HTML in descriptions, wrap in CDATA explicitly — the upstream writer does not do this for you, so either pre-format the string or accept plain text via strip_tags().
  • Debugging output. Dump RSS::render() to a file (file_put_contents('/tmp/feed.xml', RSS::render())) and run it through xmllint --noout plus the W3C Feed Validator. Errors from the upstream writer are often terse; validating the XML is faster than reading stack traces.
  • Extension points are thin. If you need an element the wrapper doesn't expose, either pass an extra key through the arrays (the upstream writer forwards unknown keys in some versions — verify against your installed version) or extend the service provider and bind your own subclass. There is no event system or decorator hook.
  • Don't return RSS::render(); from a controller. In L4 that becomes a 200 response with text/html, and every browser tab shows markup instead of the feed. Wrap it, always.
  • Charset consistency. Pass 'UTF-8' to feed() and ensure your database and strip_tags()-processed strings are actually UTF-8; mismatched encoding yields invalid XML that validators reject with byte-level errors that are painful to trace back.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin