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 Feed Generator Bundle Laravel Package

markocupic/rss-feed-generator-bundle

A Contao bundle for generating RSS feeds from your site content. Configure feed channels, map pages and archives, and publish valid RSS/Atom XML at customizable URLs for readers and aggregators, with straightforward setup through the Contao backend.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and enable. composer require markocupic/rss-feed-generator-bundle. With Symfony Flex it should register itself; otherwise add it manually to config/bundles.php. In a Contao 4/5 setup, also clear the container cache (bin/console cache:clear) so the bundle's services are compiled into the app.

  2. Find the service first. Before writing a line of code, list what the bundle actually gives you:

    bin/console debug:container | grep -i rss
    ls vendor/markocupic/rss-feed-generator-bundle/src
    

    The package is deliberately small, so the useful surface is one generator class plus maybe a DI extension. Read src/ and DependencyInjection/ — it's a five-minute read and it will save you guessing at method names.

  3. First use case: a "latest posts" feed. Create a controller action that fetches your newest entities and hands them to the generator:

    #[Route('/feed/news.xml', name: 'news_feed', defaults: ['_format' => 'xml'])]
    public function newsFeed(PostRepository $posts, RssGenerator $rss, UrlGeneratorInterface $urls): Response
    {
        foreach ($posts->findLatest(50) as $post) {
            $rss->addItem(
                title: $post->getTitle(),
                link: $urls->generate('post_show', ['slug' => $post->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
                description: $post->getTeaser(),
                pubDate: $post->getPublishedAt(),
                guid: 'post-'.$post->getId(),
            );
        }
    
        return new Response($rss->render(), 200, ['Content-Type' => 'application/rss+xml; charset=UTF-8']);
    }
    

    Exact class/method names will vary — mirror whatever src/ exposes. If the bundle returns a Response itself, skip the wrapper and just return it.

Implementation Patterns

Thin controller, fat query. Keep the controller to query → map → render. Put the "what belongs in the feed" logic in a repository method (findLatestFeedItems($limit)) so you can unit-test it and reuse it for sitemaps or JSON APIs. Always add an explicit ORDER BY publishedAt DESC and a LIMIT; unbounded feeds are the fastest way to blow up memory and response times.

Absolute URLs, always. RSS readers have no base URL. Generate every <link>, <guid>, and <enclosure> with UrlGeneratorInterface::ABSOLUTE_URL, and set framework.router.default_uri / trusted proxies so the host is correct behind a load balancer or during CLI-warmed cache.

Multiple feeds from one code path. Parameterize by a slug or query arg and validate against an allowlist rather than reflecting raw input:

$feeds = ['news' => Post::class, 'events' => Event::class];
$entity = $feeds[$request->query->get('channel')] ?? throw $this->createNotFoundException();

This gives you /feed/{channel}.xml with one controller and one test.

Route requirements to avoid content-negotiation surprises. Constrain the suffix so _format is deterministic:

#[Route('/feed/{channel}.xml', requirements: ['channel' => 'news|events'], defaults: ['_format' => 'xml'])]

Cache aggressively but correctly. Feeds are read-mostly. Wrap the response in Symfony's HTTP cache:

$response->setPublic();
$response->setMaxAge(900);
$response->setLastModified($latestPost->getUpdatedAt());

Also consider an ETag built from the item count + max updatedAt. Combine with #[Cache(...)] on the controller or an ESI-friendly reverse proxy. Refresh-on-publish is usually enough; don't bother with a message-driven cache purge unless feeds are huge.

Item payload checklist. For each entry populate: title, link, description (plain text teaser, not full HTML), pubDate (RFC 2822), guid that is stable across renames, plus optional author, category, and enclosure for media. Readers de-duplicate on guid, so make it a permalink or an immutable ID.

Reuse through a base class. If you have three or four feeds (news, blog, events, podcast), extract an abstract AbstractFeedController with getItems(): iterable and a shared render(). The bundle stays a serializer; your app owns the domain mapping.

Test it as a functional test, not a unit test. The valuable assertion is the HTTP contract:

$client->request('GET', '/feed/news.xml');
$this->assertResponseIsSuccessful();
$this->assertResponseHeaderSame('Content-Type', 'application/rss+xml; charset=UTF-8');
$this->assertStringContainsString('<rss', $client->getResponse()->getContent());

Then parse with simplexml_load_string() to confirm it's well-formed and count <item> nodes.

Contao-specific integration. If you're running this under Contao, decide whether you want a Contao front-end module / news-reader feed or a plain Symfony route. The bundle is the plain route; keep it that way unless you need page-level permissions, and register the route under a Contao page's alias only if you need it inside the site structure.

Gotchas and Tips

  • Verify the API before you build on it. With two stars and zero dependents, treat the public surface as "whatever src/ shows today." Pin the version in composer.json ("^1.0" or exact) and be ready to swap it for laminas/laminas-feed or debril/rss-atom-bundle — the exit cost is one class.
  • Double-escaping and broken XML. The classic failure is passing HTML containing &nbsp; or unescaped & into a description. Either strip tags to plain text or let the generator/CDATA wrapper handle it — never both. Validate with xmllint --noout feed.xml or the W3C Feed Validator before shipping.
  • Dates. Use \DateTimeInterface::format(DATE_RSS) and make sure entities return DateTimeImmutable with a real timezone. Naive DateTime objects and UTC-vs-local mismatches cause items to appear out of order in readers.
  • Content-Type matters. text/xml or a missing charset will break some readers and clients. Set application/rss+xml; charset=UTF-8 explicitly; don't rely on _format: xml alone.
  • Caching hides publishes. A five-minute public cache means editors publish and see nothing. Log the TTL in the docs, or key the cache on a content_version value you bump on save.
  • Empty or malformed channels. RSS requires <title>, <link>, and <description> on the channel even when there are zero items. If your generator is silent on those, add them. Test the empty-feed case — it's the one nobody writes a fixture for.
  • Container wiring outside Flex. Private services and missing autowiring aliases are the usual "Cannot autowire" symptom. Run debug:container RssGenerator after a cache clear; if there's no alias, define one in config/services.yaml.
  • Behind a proxy. Absolute URL generation will produce http://localhost in CLI-warmed or proxied environments. Configure trusted_proxies and framework.router.default_uri early — debugging this after launch is painful because readers cache the broken links.
  • Extension point. If you need to change rendering, decorate the generator service (RssGenerator → your DecoratingRssGenerator) rather than forking the bundle. That keeps composer updates painless and makes the eventual library swap a one-file change.
  • Observability. Feeds fail quietly — a 200 with an empty body looks fine in a browser tab. Add a smoke test to your CI pipeline that hits each feed route and asserts well-formed XML; it catches the "Doctrine query broke and returned nothing" class of incident.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console