
Short answer: ProcessWire ships with a core module called MarkupRSS that turns a set of pages into an RSS feed. Install it, create a template named rss with a small template file, add a page such as /rss/ that uses it, and inside the file find your latest published posts with a selector and pass them to the module. Map the title, date and summary fields, set $config->httpHosts so absolute links use your real domain, and then connect the feed to an auto-poster so every new page is shared on social media automatically.
ProcessWire is a PHP CMS and framework that developers like for its clean API, flexible fields and selector engine. It does not create a feed on its own, because it makes no assumptions about which templates are articles or what your fields are called. The pieces are all there, though, and building a feed takes a few minutes. This guide covers the MarkupRSS module, the template and page setup, field mapping, a hand-written feed for images, topic feeds with URL segments, caching and multi-language sites, and the checks to run before automation reads the feed.
Not by default. A fresh installation has no feed URL, and that is consistent with how ProcessWire works: the site structure, templates and fields are entirely yours. What the core does include is MarkupRSS, a module that takes a list of pages and outputs an RSS 2.0 document. It is not installed automatically. Go to Modules in the admin, find Markup RSS Feed in the core modules list and click Install.
You then decide three things: where the feed lives, which pages it contains and which fields provide the title, date and description of each item. The rest of this guide shows a sensible default for each.
The cleanest setup is a dedicated template and page:
site/templates/rss.php. It can be empty for now.rss. It needs no fields beyond the title._init.php un _main.php. Otherwise your HTML layout wraps the XML and breaks the feed.rss template, named rss, and mark it hidden so it does not appear in your navigation.The feed now answers at https://example.com/rss/. Choose the address once and keep it: every reader and automation tool stores it, and changing it means updating all of them. More on that choice is in which RSS feed URL to use.
Put this in site/templates/rss.php, adjusting the template and field names to your site:
<?php namespace ProcessWire;
$items = $pages->find('template=blog-post, sort=-date, limit=20');
$rss = $modules->get('MarkupRSS');
$rss->title = 'Example Blog';
$rss->description = 'News and articles from Example';
$rss->url = $pages->get('/blog/')->httpUrl;
$rss->itemTitleField = 'title';
$rss->itemDateField = 'date';
$rss->itemDescriptionField = 'summary';
$rss->itemDescriptionLength = 400;
$rss->render($items);The module outputs the XML and sends the header, so nothing else is needed. Open /rss/ and you should see your 20 newest posts.
The selector deserves a closer look, because it decides what can end up on social media:
template=blog-post limits the feed to articles. Without it, a feed sorted by modification date can contain every page on the site.sort=-date sorts by your own date field, newest first. The minus sign means descending.limit=20 keeps the feed short and fast.find() runs for a guest, which is how feed readers and automation tools arrive. Do not add include=all vai include=hidden to a feed selector.MarkupRSS reads three fields from each page, and its defaults do not fit every site:
title by default, which is right for almost everyone.created by default, the moment the page was created in the admin. That is often days before publication. Point itemDateField to a datetime field that editors set, such as date. Avoid modified: it changes on every save and makes old posts look new.summary by default. If your summary field has a different name, set itemDescriptionField. itemDescriptionLength limits the length.A real summary of one or two sentences works far better than a truncated body, because social posts show only the first lines. The difference is explained in custom RSS feed excerpts. Wrong dates are one of the most common reasons automation tools skip or repeat items; see pubDate vs lastBuildDate.
Each item link is the page’s httpUrl, the full address including scheme and host name. ProcessWire builds it from the current request, checked against the list of allowed hosts in site/config.php:
$config->httpHosts = ['example.com', 'www.example.com'];Put your canonical host first. If the site runs behind a proxy or a CDN that terminates https, make sure ProcessWire knows the request is secure, for example through the template’s https setting or your proxy configuration, so links start with https and not plain http. A feed whose links point to an internal host name or the wrong scheme is unusable outside your network; the symptoms are described in relative URLs in RSS feeds.
MarkupRSS outputs titles, links, dates and descriptions, but no image element. Social posts with a good picture perform much better, so many sites write the feed directly in the template file instead. ProcessWire’s API makes that short:
<?php namespace ProcessWire;
$items = $pages->find('template=blog-post, sort=-date, limit=20');
$e = function ($s) use ($sanitizer) { return $sanitizer->entities($s); };
header('Content-Type: application/rss+xml; charset=utf-8');
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<rss version="2.0">
<channel>
<title>Example Blog</title>
<link><?= $pages->get('/blog/')->httpUrl ?></link>
<description>News and articles from Example</description>
<?php foreach ($items as $p): ?>
<item>
<title><?= $e($p->title) ?></title>
<link><?= $p->httpUrl ?></link>
<guid isPermaLink="false">page-<?= $p->id ?></guid>
<pubDate><?= date('r', $p->getUnformatted('date')) ?></pubDate>
<description><?= $e($p->summary) ?></description>
<?php if ($p->images->count()): $img = $p->images->first()->size(1200, 630); ?>
<enclosure url="<?= $img->httpUrl ?>" type="image/jpeg" length="<?= $img->filesize ?>"/>
<?php endif; ?>
</item>
<?php endforeach; ?>
</channel>
</rss>A few details make this robust. getUnformatted('date') returns the raw Unix timestamp, so date('r') can format it the way RSS expects, rather than the human-friendly format your field may be set to. size(1200, 630) creates a cropped variation at the size most networks use for previews, and its httpUrl is absolute. The GUID is based on the page ID, which never changes, even if an editor renames the page later; changing GUIDs are a common cause of duplicate posts, as explained in why a feed auto-posts the same article twice. Make sure nothing, not even a blank line, is output before the XML declaration.
The example assumes an images field called images that holds several images. If your field is set to a single image, use it directly instead of first(). Also output an og:image tag on the article page itself, because many networks build their link preview from the page.
| Need | MarkupRSS | Hand-written template |
|---|---|---|
| Quick setup | A few lines | About 30 lines |
| Field mapping | Title, date, description | Any field |
| Images | Not included | Enclosure with absolute URL |
| Custom GUID | Module default | Page ID or your own value |
| Escaping | Handled by the module | Use the sanitizer |
One template can serve a feed per category. In the rss template’s URLs tab, allow URL segments. Then read the first segment and filter by it:
$selector = 'template=blog-post, sort=-date, limit=20';
if ($input->urlSegment1) {
$cat = $pages->get('template=category, name=' . $sanitizer->pageName($input->urlSegment1));
if (!$cat->id) throw new Wire404Exception();
$selector .= ', categories=' . $cat->id;
}
$items = $pages->find($selector);/rss/ is now the full feed and /rss/tutorials/ only the tutorials. Sanitizing the segment and returning a 404 for unknown categories keeps the URL space clean. Topic feeds let you send each kind of content to the right audience, as explained in category filtering for auto-posting.
ProcessWire’s template cache, set in the template’s Cache tab, can serve the feed from a file for a set time. Keep that time short, a few minutes at most, and use the option to clear the cache when pages are saved if your version offers it, so a new article appears quickly. The same applies to full-page cache modules and to any CDN in front of the site. A feed that is cached for a day delays every social post by up to a day.
On multi-language sites, the page’s language-specific URLs give you one feed per language, such as /rss/ un /de/rss/, as long as the rss page is active in each language. Each feed then uses titles and summaries in that language. Connect each one to the social accounts for that audience.
Finally, add an autodiscovery link to the head of your main layout file, so browsers and tools find the feed from any page:
<link rel="alternate" type="application/rss+xml"
title="Example Blog" href="<?= $pages->get('/rss/')->httpUrl ?>">/rss/. Unpublished and restricted pages must be missing.Selectors, templates, URL segments and the API variables used above are documented on the ProcessWire documentation site.
PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your ProcessWire feed, or several topic feeds, connect your accounts and choose how each post is built from the title, the description or the page title. PostRSS checks the feed as often as every minute and shares each new page, with its image and link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, from Facebook Pages, LinkedIn and Pinterest to Telegram, Mastodon and Bluesky. Keyword filters, UTM parameters, hashtags from categories and posting windows let you adjust each channel. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.
A ProcessWire RSS feed is a template, a page and either the MarkupRSS module or about 30 lines of your own XML. Select published posts of one template, sort by an editor-controlled date, map the summary field, configure httpHosts so links are absolute and add images with an enclosure if you write the feed by hand. Keep the cache short, add an autodiscovery link, validate once, and every new page can be shared on social media automatically.
Yes. MarkupRSS is a core module, but it is not installed by default. Install it under Modules, then call it from a template file with the pages you want in the feed.
The rss template is still using the automatic prepend and append files. Disable them in the template Files tab so only the XML is output.
It uses the created date by default. Set itemDateField to your own datetime field so items carry the real publication date instead of the moment the page was created.
MarkupRSS does not output images, so write the feed in the template file and add an enclosure with the httpUrl of a resized image from the page.
ProcessWire builds absolute URLs from the request host checked against httpHosts. List your public domain first in site config and make sure https is detected behind a proxy.
What changed in the networks, what broke, and how to fix it before it costs you reach.
Izstrādājusi Internet Solutions — PostRSS komanda. Katrs produkts ietaupa laiku savā veidā.