-
Notifications
You must be signed in to change notification settings - Fork 94
Multiple Feeds
Rumen Damyanov edited this page Jul 29, 2025
·
2 revisions
This guide shows how to create and manage multiple feeds for different content types, categories, or audiences.
Multiple feeds are useful when you have:
- Different content types (blog posts, news, tutorials, products)
- Multiple categories or topics
- Different audiences (general public, technical users, etc.)
- Various content formats (articles, podcasts, videos)
Here's how to create different feeds for different content types:
<?php
require 'vendor/autoload.php';
use Rumenx\Feed\FeedFactory;
// Get the requested feed type
$feedType = $_GET['type'] ?? 'blog';
switch ($feedType) {
case 'news':
generateNewsFeed();
break;
case 'tutorials':
generateTutorialsFeed();
break;
case 'products':
generateProductsFeed();
break;
case 'blog':
default:
generateBlogFeed();
break;
}
function generateBlogFeed(): void
{
$feed = FeedFactory::create();
$feed->setTitle('My Website - Blog Posts');
$feed->setDescription('Latest blog posts and articles');
$feed->setLink('https://example.com/blog');
$feed->setLanguage('en');
// Sample blog posts data
$posts = [
[
'title' => 'Getting Started with PHP',
'author' => 'John Doe',
'link' => 'https://example.com/blog/getting-started-php',
'pubdate' => '2025-01-15T10:00:00Z',
'description' => 'A beginner-friendly guide to PHP programming.'
],
[
'title' => 'Advanced Laravel Techniques',
'author' => 'Jane Smith',
'link' => 'https://example.com/blog/advanced-laravel',
'pubdate' => '2025-01-14T14:30:00Z',
'description' => 'Explore advanced patterns and techniques in Laravel.'
]
];
foreach ($posts as $post) {
$feed->addItem($post);
}
outputFeed($feed);
}
function generateNewsFeed(): void
{
$feed = FeedFactory::create();
$feed->setTitle('My Website - News Updates');
$feed->setDescription('Latest company and industry news');
$feed->setLink('https://example.com/news');
$feed->setLanguage('en');
// Sample news data
$news = [
[
'title' => 'Company Launches New Product',
'author' => 'Press Team',
'link' => 'https://example.com/news/new-product-launch',
'pubdate' => '2025-01-16T09:00:00Z',
'description' => 'We are excited to announce our latest product innovation.'
],
[
'title' => 'Industry Conference Recap',
'author' => 'Event Team',
'link' => 'https://example.com/news/conference-recap',
'pubdate' => '2025-01-15T16:00:00Z',
'description' => 'Key insights from this years biggest tech conference.'
]
];
foreach ($news as $item) {
$feed->addItem($item);
}
outputFeed($feed);
}
function generateTutorialsFeed(): void
{
$feed = FeedFactory::create();
$feed->setTitle('My Website - Tutorials');
$feed->setDescription('Step-by-step programming tutorials');
$feed->setLink('https://example.com/tutorials');
$feed->setLanguage('en');
// Sample tutorial data
$tutorials = [
[
'title' => 'Building a REST API with PHP',
'author' => 'Tech Team',
'link' => 'https://example.com/tutorials/rest-api-php',
'pubdate' => '2025-01-13T12:00:00Z',
'description' => 'Learn how to build a robust REST API using modern PHP.',
'category' => ['PHP', 'API', 'Backend']
],
[
'title' => 'Database Design Best Practices',
'author' => 'Database Expert',
'link' => 'https://example.com/tutorials/database-design',
'pubdate' => '2025-01-12T10:00:00Z',
'description' => 'Essential principles for designing efficient databases.',
'category' => ['Database', 'MySQL', 'Design']
]
];
foreach ($tutorials as $tutorial) {
$feed->addItem($tutorial);
}
outputFeed($feed);
}
function generateProductsFeed(): void
{
$feed = FeedFactory::create();
$feed->setTitle('My Store - New Products');
$feed->setDescription('Latest products in our store');
$feed->setLink('https://example.com/products');
$feed->setLanguage('en');
// Sample product data
$products = [
[
'title' => 'Premium PHP Course Bundle',
'author' => 'Store Admin',
'link' => 'https://example.com/products/php-course-bundle',
'pubdate' => '2025-01-16T08:00:00Z',
'description' => 'Complete PHP learning package with 20+ hours of content.',
'category' => ['Courses', 'PHP', 'Programming']
],
[
'title' => 'Development Tools License',
'author' => 'Store Admin',
'link' => 'https://example.com/products/dev-tools-license',
'pubdate' => '2025-01-15T12:00:00Z',
'description' => 'Professional development tools for modern web developers.',
'category' => ['Tools', 'Software', 'Development']
]
];
foreach ($products as $product) {
$feed->addItem($product);
}
outputFeed($feed);
}
function outputFeed(object $feed): void
{
header('Content-Type: application/rss+xml; charset=utf-8');
echo $feed->render('rss');
}
Organize your feeds with clean URLs:
https://example.com/feed # Main blog feed
https://example.com/feed/blog # Blog posts
https://example.com/feed/news # News updates
https://example.com/feed/tutorials # Tutorials
https://example.com/feed/products # Products
https://example.com/feed/category/php # PHP category
More advanced example with database integration:
<?php
require 'vendor/autoload.php';
use Rumenx\Feed\FeedFactory;
use PDO;
class MultiFeedGenerator
{
private PDO $pdo;
private array $baseConfig;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
$this->baseConfig = [
'base_url' => 'https://example.com',
'language' => 'en'
];
}
public function generateFeed(string $type, ?string $category = null): string
{
switch ($type) {
case 'posts':
return $this->generatePostsFeed($category);
case 'news':
return $this->generateNewsFeed();
case 'tutorials':
return $this->generateTutorialsFeed($category);
case 'products':
return $this->generateProductsFeed($category);
default:
throw new InvalidArgumentException("Unknown feed type: {$type}");
}
}
private function generatePostsFeed(?string $category = null): string
{
$feed = FeedFactory::create();
$feed->setTitle('My Blog' . ($category ? " - {$category}" : ''));
$feed->setDescription('Latest blog posts' . ($category ? " in {$category}" : ''));
$feed->setLink($this->baseConfig['base_url'] . '/blog');
$feed->setLanguage($this->baseConfig['language']);
$posts = $this->fetchPosts($category);
foreach ($posts as $post) {
$feed->addItem([
'title' => $post['title'],
'author' => $post['author_name'],
'link' => $this->baseConfig['base_url'] . '/blog/' . $post['slug'],
'pubdate' => $post['created_at'],
'description' => $post['excerpt'],
'category' => explode(',', $post['categories'] ?? '')
]);
}
return $feed->render('rss');
}
private function generateNewsFeed(): string
{
$feed = FeedFactory::create();
$feed->setTitle('My Website - News');
$feed->setDescription('Latest news and announcements');
$feed->setLink($this->baseConfig['base_url'] . '/news');
$feed->setLanguage($this->baseConfig['language']);
$news = $this->fetchNews();
foreach ($news as $item) {
$feed->addItem([
'title' => $item['title'],
'author' => $item['author_name'],
'link' => $this->baseConfig['base_url'] . '/news/' . $item['slug'],
'pubdate' => $item['published_at'],
'description' => $item['summary']
]);
}
return $feed->render('rss');
}
private function generateTutorialsFeed(?string $category = null): string
{
$feed = FeedFactory::create();
$feed->setTitle('My Website - Tutorials' . ($category ? " - {$category}" : ''));
$feed->setDescription('Programming tutorials and guides');
$feed->setLink($this->baseConfig['base_url'] . '/tutorials');
$feed->setLanguage($this->baseConfig['language']);
$tutorials = $this->fetchTutorials($category);
foreach ($tutorials as $tutorial) {
$feed->addItem([
'title' => $tutorial['title'],
'author' => $tutorial['author_name'],
'link' => $this->baseConfig['base_url'] . '/tutorials/' . $tutorial['slug'],
'pubdate' => $tutorial['created_at'],
'description' => $tutorial['description'],
'category' => explode(',', $tutorial['tags'] ?? '')
]);
}
return $feed->render('rss');
}
private function generateProductsFeed(?string $category = null): string
{
$feed = FeedFactory::create();
$feed->setTitle('My Store - Products' . ($category ? " - {$category}" : ''));
$feed->setDescription('Latest products and updates');
$feed->setLink($this->baseConfig['base_url'] . '/products');
$feed->setLanguage($this->baseConfig['language']);
$products = $this->fetchProducts($category);
foreach ($products as $product) {
$feed->addItem([
'title' => $product['name'],
'author' => 'Store Team',
'link' => $this->baseConfig['base_url'] . '/products/' . $product['slug'],
'pubdate' => $product['created_at'],
'description' => $product['description'],
'category' => [$product['category_name']]
]);
}
return $feed->render('rss');
}
private function fetchPosts(?string $category = null): array
{
$sql = "
SELECT p.title, p.slug, p.excerpt, p.created_at, u.name as author_name,
GROUP_CONCAT(c.name) as categories
FROM posts p
JOIN users u ON p.author_id = u.id
LEFT JOIN post_categories pc ON p.id = pc.post_id
LEFT JOIN categories c ON pc.category_id = c.id
WHERE p.published = 1
";
$params = [];
if ($category) {
$sql .= " AND c.slug = ?";
$params[] = $category;
}
$sql .= " GROUP BY p.id ORDER BY p.created_at DESC LIMIT 20";
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
private function fetchNews(): array
{
$stmt = $this->pdo->prepare("
SELECT n.title, n.slug, n.summary, n.published_at, u.name as author_name
FROM news n
JOIN users u ON n.author_id = u.id
WHERE n.published = 1
ORDER BY n.published_at DESC
LIMIT 15
");
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
private function fetchTutorials(?string $category = null): array
{
$sql = "
SELECT t.title, t.slug, t.description, t.created_at, u.name as author_name,
GROUP_CONCAT(tag.name) as tags
FROM tutorials t
JOIN users u ON t.author_id = u.id
LEFT JOIN tutorial_tags tt ON t.id = tt.tutorial_id
LEFT JOIN tags tag ON tt.tag_id = tag.id
WHERE t.published = 1
";
$params = [];
if ($category) {
$sql .= " AND tag.slug = ?";
$params[] = $category;
}
$sql .= " GROUP BY t.id ORDER BY t.created_at DESC LIMIT 10";
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
private function fetchProducts(?string $category = null): array
{
$sql = "
SELECT p.name, p.slug, p.description, p.created_at, c.name as category_name
FROM products p
JOIN categories c ON p.category_id = c.id
WHERE p.active = 1
";
$params = [];
if ($category) {
$sql .= " AND c.slug = ?";
$params[] = $category;
}
$sql .= " ORDER BY p.created_at DESC LIMIT 20";
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
// Usage
$pdo = new PDO('mysql:host=localhost;dbname=website', $username, $password);
$generator = new MultiFeedGenerator($pdo);
$type = $_GET['type'] ?? 'posts';
$category = $_GET['category'] ?? null;
header('Content-Type: application/rss+xml; charset=utf-8');
echo $generator->generateFeed($type, $category);
Add discovery links for all your feeds:
<?php
use Rumenx\Feed\Feed;
function generateFeedDiscoveryLinks(): string
{
$links = [
Feed::link('https://example.com/feed', 'rss', 'Main Feed'),
Feed::link('https://example.com/feed/blog', 'rss', 'Blog Posts'),
Feed::link('https://example.com/feed/news', 'rss', 'News Updates'),
Feed::link('https://example.com/feed/tutorials', 'rss', 'Tutorials'),
Feed::link('https://example.com/feed/products', 'atom', 'Products')
];
return implode("\n", $links);
}
// In your HTML <head>
echo generateFeedDiscoveryLinks();
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Controller;
use Illuminate\Http\Response;
use Rumenx\Feed\FeedFactory;
use App\Models\Post;
use App\Models\News;
use App\Models\Tutorial;
use App\Models\Product;
class MultiFeedController extends Controller
{
public function index(string $type = 'blog', ?string $category = null): Response
{
$feedData = $this->getFeedData($type, $category);
$feed = FeedFactory::create();
$feed->setTitle($feedData['title']);
$feed->setDescription($feedData['description']);
$feed->setLink($feedData['link']);
$feed->setLanguage(app()->getLocale());
foreach ($feedData['items'] as $item) {
$feed->addItem($item);
}
return response($feed->render('rss'), 200, [
'Content-Type' => 'application/rss+xml; charset=utf-8'
]);
}
private function getFeedData(string $type, ?string $category = null): array
{
switch ($type) {
case 'news':
return $this->getNewsData();
case 'tutorials':
return $this->getTutorialsData($category);
case 'products':
return $this->getProductsData($category);
case 'blog':
default:
return $this->getBlogData($category);
}
}
private function getBlogData(?string $category = null): array
{
$query = Post::published()->latest()->limit(20);
if ($category) {
$query->whereHas('categories', fn($q) => $q->where('slug', $category));
}
$posts = $query->get();
return [
'title' => config('app.name') . ' - Blog' . ($category ? " - {$category}" : ''),
'description' => 'Latest blog posts',
'link' => route('blog.index'),
'items' => $posts->map(fn($post) => [
'title' => $post->title,
'author' => $post->author->name,
'link' => route('blog.show', $post->slug),
'pubdate' => $post->created_at,
'description' => $post->excerpt,
'category' => $post->categories->pluck('name')->toArray()
])->toArray()
];
}
private function getNewsData(): array
{
$news = News::published()->latest()->limit(15)->get();
return [
'title' => config('app.name') . ' - News',
'description' => 'Latest news and updates',
'link' => route('news.index'),
'items' => $news->map(fn($item) => [
'title' => $item->title,
'author' => $item->author->name,
'link' => route('news.show', $item->slug),
'pubdate' => $item->published_at,
'description' => $item->summary
])->toArray()
];
}
private function getTutorialsData(?string $category = null): array
{
$query = Tutorial::published()->latest()->limit(10);
if ($category) {
$query->whereHas('tags', fn($q) => $q->where('slug', $category));
}
$tutorials = $query->get();
return [
'title' => config('app.name') . ' - Tutorials' . ($category ? " - {$category}" : ''),
'description' => 'Programming tutorials and guides',
'link' => route('tutorials.index'),
'items' => $tutorials->map(fn($tutorial) => [
'title' => $tutorial->title,
'author' => $tutorial->author->name,
'link' => route('tutorials.show', $tutorial->slug),
'pubdate' => $tutorial->created_at,
'description' => $tutorial->description,
'category' => $tutorial->tags->pluck('name')->toArray()
])->toArray()
];
}
private function getProductsData(?string $category = null): array
{
$query = Product::active()->latest()->limit(20);
if ($category) {
$query->whereHas('category', fn($q) => $q->where('slug', $category));
}
$products = $query->get();
return [
'title' => config('app.name') . ' - Products' . ($category ? " - {$category}" : ''),
'description' => 'Latest products and updates',
'link' => route('products.index'),
'items' => $products->map(fn($product) => [
'title' => $product->name,
'author' => 'Store Team',
'link' => route('products.show', $product->slug),
'pubdate' => $product->created_at,
'description' => $product->description,
'category' => [$product->category->name]
])->toArray()
];
}
}
// routes/web.php
Route::get('/feed/{type?}/{category?}', [MultiFeedController::class, 'index'])
->where('type', 'blog|news|tutorials|products')
->where('category', '[a-zA-Z0-9-]+')
->name('feeds.show');
// Alternative explicit routes
Route::get('/feed', [MultiFeedController::class, 'index'])->name('feeds.main');
Route::get('/feed/blog', [MultiFeedController::class, 'index'])->defaults('type', 'blog');
Route::get('/feed/news', [MultiFeedController::class, 'index'])->defaults('type', 'news');
Route::get('/feed/tutorials', [MultiFeedController::class, 'index'])->defaults('type', 'tutorials');
Route::get('/feed/products', [MultiFeedController::class, 'index'])->defaults('type', 'products');
// Category-specific feeds
Route::get('/feed/blog/{category}', [MultiFeedController::class, 'index'])
->defaults('type', 'blog')->name('feeds.blog.category');
Route::get('/feed/tutorials/{category}', [MultiFeedController::class, 'index'])
->defaults('type', 'tutorials')->name('feeds.tutorials.category');
- Learn about Caching for better performance with multiple feeds
- See Custom Views for different templates per feed type
- Check out Advanced Features for categories and enclosures