What it does
scriptor-markdown-feed serves a syndication feed straight from a
directory of dated markdown files. Point it at a news/, blog/, or
releases/ track and it answers /news/feed.xml by scanning those
files, parsing their frontmatter, and emitting Atom 1.0 (or RSS 2.0)
on every request. No build step, no cache, no database table: add an
entry, push, and the next poll sees it.
It is the companion to
scriptor-markdown-pages: the same .md
files that render as pages also back the feed, and the entry links the
feed generates match how markdown-pages resolves those files. This
site uses it for /news/feed.xml.
A feed is not page-shaped, so the plugin does not hook the page resolver. Instead it activates from one guard line in the theme, the same model as scriptor-simple-router.
Install
Host install. Not on Packagist, so register the VCS repo, then require:
composer config repositories.scriptor-markdown-feed \
vcs https://github.com/bigin/scriptor-markdown-feed
composer require bigins/scriptor-markdown-feed:^0.1
Docker. Bake it in with the two build args (typically alongside markdown-pages, since it reuses that plugin's content root):
services:
scriptor:
build:
args:
SCRIPTOR_PLUGIN_REPOS: "https://github.com/bigin/scriptor-markdown-pages https://github.com/bigin/scriptor-markdown-feed"
SCRIPTOR_PLUGINS: "bigins/scriptor-markdown-pages:^0.1 bigins/scriptor-markdown-feed:^0.1"
Then activate it from one guard line at the top of your theme's
_ext.php, before the theme is built:
if (\Bigins\ScriptorMarkdownFeed\Feed::handle($config)) {
return;
}
Feed::handle($config) returns true only when the request path
matches a configured feed (it has emitted the XML and the caller
returns); every other request returns false and the page flow runs
untouched.
Configure
Under plugins.markdown_feed in
data/settings/custom.scriptor-config.php:
return [
'plugins' => [
'markdown_feed' => [
// Optional. Falls back to plugins.markdown_pages.content_root.
'content_root' => '/var/www/scriptor/themes/info/content',
'feeds' => [
[
'track' => 'news', // subdirectory of content_root
'path' => '/news/feed.xml', // URL the feed answers on
'title' => 'Scriptor News', // channel title
'max' => 20, // newest N (default 20)
'format' => 'atom', // 'atom' (default) or 'rss'
],
],
],
],
];
| Key | Default | Effect |
|---|---|---|
content_root |
plugins.markdown_pages.content_root |
Where the tracks live. |
feeds[].track |
required | Subdirectory of content_root to scan. |
feeds[].path |
required | Exact request path the feed answers on. |
feeds[].title |
the track name | Channel <title>. |
feeds[].max |
20 |
Cap on entries, newest first. |
feeds[].format |
atom |
atom (Atom 1.0) or rss (RSS 2.0). |
Multiple feeds are allowed side by side. A feed entry missing track
or path is dropped rather than fatalling the request.
Use
Each .md in the track becomes one entry. _index.md is skipped (it
is the landing page, not an entry). The entry slug is the filename
without .md, and the link is <siteUrl>/<track>/<slug>/, matching
markdown-pages. Sort is by date: frontmatter, newest first, ties on
title; a file without a parseable date falls back to its mtime.
---
title: "Developer Guide is content-complete"
date: 2026-05-25
summary: "All four layers of the Developer Guide are now live."
---
# Developer Guide is content-complete
Body markdown…
Keep filenames within [a-z0-9_-]. When the feed is paired with
markdown-pages, that plugin sanitises every URL segment to
[a-z0-9_-], so a dot in the filename produces a feed link that
resolves to a 404. Use 2026-05-22-release-v0-1-7.md, not
…v0.1.7.md.
Links
- Source: https://github.com/bigin/scriptor-markdown-feed
- Version: v0.1.2 (not on Packagist; install via VCS repo)
- License: MIT
- Requires: Scriptor 2.1+; pairs with scriptor-markdown-pages
- Recipe: the RSS / Atom feed from a page tree cookbook recipe is the DB-backed variant of the same pattern.