Summary
Expose an RSS feed for each page category so readers can subscribe to updates, and surface the feed URL in the two natural discovery points: the homepage "latest pages" block and the header of the category list / single-page views.
This is greenfield — the project currently ships an iCal feed for events (EventAgendaController::feed()) but no RSS/Atom for CMS pages.
Proposed approach
1. New route + controller action
In src/Controller/PageController.php, add a feed() action mirroring the structure of category():
- Route name:
app_page_category_feed
- URL:
/{_locale}/pages/category/{id}/feed.xml
- Returns RSS 2.0 XML with
Content-Type: application/rss+xml; charset=UTF-8
- Items: published pages in that category, newest first, capped (e.g. 20 items) — reuse the published-pages repository query used by
category()
- Each
<item> carries <title>, <link> (absolute URL to app_page_show), <guid isPermaLink="true">, <pubDate> (RFC 822 from publishedAt / lastUpdatedAt), <description> (page excerpt or first paragraph)
- Channel-level metadata: category name (translated), site URL, language matching
{_locale}, <lastBuildDate>
Follow the iCal precedent: short HTTP cache (public, max-age=300) since pages publish infrequently.
2. Rendering
Use a dedicated Twig template templates/page/feed.xml.twig rather than building XML strings in PHP. Mirror the iCal pattern — keeps escaping in Twig (|escape('html') or a CDATA wrap) and the action thin.
3. Discovery links
Per the request, expose the feed URL in three template locations:
templates/home/blocks/_latest_pages.html.twig — small RSS icon/link next to the block heading, pointing to the configured category's feed (the block already surfaces a category from HomepageRenderer::resolveLatestPages()).
templates/page/category.html.twig (around the <h1> near line 14) — RSS link in the category header.
templates/page/show.html.twig (header region around lines 41–42) — RSS link to the page's own category feed (since pages belong to a category via Page::menuCategory).
Also add the standard <link rel="alternate" type="application/rss+xml" …> to the <head> of both the category list and the single-page view so browser readers can autodiscover.
4. Translations
New keys in translations/messages.{en,fr}.xlf:
app.page.feed.subscribe → "Subscribe via RSS" / "S'abonner au flux RSS"
app.page.feed.title_for_category → "%category% — latest pages" / "%category% — derniers articles" (channel title)
Acceptance criteria
Files likely touched
src/Controller/PageController.php — new feed() action + route
templates/page/feed.xml.twig — new feed template
templates/page/category.html.twig — header link + <link rel="alternate">
templates/page/show.html.twig — header link + <link rel="alternate">
templates/home/blocks/_latest_pages.html.twig — RSS link near block heading
translations/messages.{en,fr}.xlf — two new keys
docs/features.md — claim F21 (Content syndication) and F21.1 entry
tests/Functional/Controller/PageControllerTest.php (or equivalent) — feed coverage
Out of scope (possible follow-ups)
- A global "all pages" RSS feed (this issue is strictly per-category, as requested).
- Atom 1.0 alongside RSS 2.0 — only one format ships here.
- Per-author or per-tag feeds.
- WebSub / PubSubHubbub push notifications.
Notes
MenuCategory has no slug, only numeric id — URL pattern follows the existing app_page_category route shape.
- Feature ID: allocates F21 as a new top-level family ("Content syndication"). F19 is left as a deliberate gap; F20 is Theming. Update
docs/features.md in the same PR.
Summary
Expose an RSS feed for each page category so readers can subscribe to updates, and surface the feed URL in the two natural discovery points: the homepage "latest pages" block and the header of the category list / single-page views.
This is greenfield — the project currently ships an iCal feed for events (
EventAgendaController::feed()) but no RSS/Atom for CMS pages.Proposed approach
1. New route + controller action
In
src/Controller/PageController.php, add afeed()action mirroring the structure ofcategory():app_page_category_feed/{_locale}/pages/category/{id}/feed.xmlContent-Type: application/rss+xml; charset=UTF-8category()<item>carries<title>,<link>(absolute URL toapp_page_show),<guid isPermaLink="true">,<pubDate>(RFC 822 frompublishedAt/lastUpdatedAt),<description>(page excerpt or first paragraph){_locale},<lastBuildDate>Follow the iCal precedent: short HTTP cache (
public, max-age=300) since pages publish infrequently.2. Rendering
Use a dedicated Twig template
templates/page/feed.xml.twigrather than building XML strings in PHP. Mirror the iCal pattern — keeps escaping in Twig (|escape('html')or a CDATA wrap) and the action thin.3. Discovery links
Per the request, expose the feed URL in three template locations:
templates/home/blocks/_latest_pages.html.twig— small RSS icon/link next to the block heading, pointing to the configured category's feed (the block already surfaces acategoryfromHomepageRenderer::resolveLatestPages()).templates/page/category.html.twig(around the<h1>near line 14) — RSS link in the category header.templates/page/show.html.twig(header region around lines 41–42) — RSS link to the page's own category feed (since pages belong to a category viaPage::menuCategory).Also add the standard
<link rel="alternate" type="application/rss+xml" …>to the<head>of both the category list and the single-page view so browser readers can autodiscover.4. Translations
New keys in
translations/messages.{en,fr}.xlf:app.page.feed.subscribe→ "Subscribe via RSS" / "S'abonner au flux RSS"app.page.feed.title_for_category→ "%category% — latest pages" / "%category% — derniers articles" (channel title)Acceptance criteria
GET /en/pages/category/{id}/feed.xmlreturns valid RSS 2.0 (validates via W3C feed validator) withContent-Type: application/rss+xml./fr/…and the channel<language>reflects the locale.category.html.twig) shows a "Subscribe via RSS" link.show.html.twig) shows a "Subscribe via RSS" link pointing to that page's category feed.<link rel="alternate" type="application/rss+xml">autodiscovery tag in<head>.Files likely touched
src/Controller/PageController.php— newfeed()action + routetemplates/page/feed.xml.twig— new feed templatetemplates/page/category.html.twig— header link +<link rel="alternate">templates/page/show.html.twig— header link +<link rel="alternate">templates/home/blocks/_latest_pages.html.twig— RSS link near block headingtranslations/messages.{en,fr}.xlf— two new keysdocs/features.md— claim F21 (Content syndication) and F21.1 entrytests/Functional/Controller/PageControllerTest.php(or equivalent) — feed coverageOut of scope (possible follow-ups)
Notes
MenuCategoryhas no slug, only numericid— URL pattern follows the existingapp_page_categoryroute shape.docs/features.mdin the same PR.