RSS в 66 социальных сетей: Facebook, Instagram, X, LinkedIn, Telegram и другие Блог Партнерская программа Контакты
Войти Начать бесплатно
Updated: 2026-10-17
Slim 4 RSS Feed: Add a Route in PHP and Auto-Post Items

Short answer: In Slim 4, add a GET route that queries the newest published rows, builds RSS 2.0 XML with escaped text, absolute links and RFC 822 dates, writes it to the PSR-7 response body and sets the content type to application/rss+xml with a short cache lifetime. Add an ETag so repeat visitors get a 304, test the route with curl and a validator, and then give the public address to an auto-poster so every new item is shared on social media automatically.

Slim is a favourite for small APIs, internal tools and compact websites in PHP. It gives you routing, middleware and a clean PSR-7 request and response, and very little else. That minimalism is exactly why it has no feed support: there is no blog engine to provide one. The solution is a single route. This guide builds it with PDO for the data, explains the parts that go wrong in practice, such as sub-directory installs, escaping and caching, and finishes with the steps that turn the feed into automatic social media posts.

When a Slim project needs a feed

A Slim application often serves content that people want to follow, even though nobody calls it a blog:

  • a news or announcements page for a club, school or company;
  • release notes for a product that runs on the same server;
  • a catalogue, a directory or a job board where new entries appear daily;
  • an events list that visitors check every week.

A feed removes the need to copy every announcement to social networks by hand. It also lets feed readers, aggregators and auto-posters follow your content in a format that every one of them understands. If you want to understand the structure first, writing an RSS feed by hand explains each element in plain language.

Set up the project

Start from a standard Slim 4 skeleton. If you are creating a new project, install the framework and a PSR-7 implementation with Composer: composer require slim/slim slim/psr7. The example below assumes a MySQL or SQLite table named posts with the columns id, title, slug, summary, status и published_at. Store the date in UTC. If your application stores local time, convert it before building the feed, because the feed must carry an unambiguous moment.

The route

Put the route in your front controller or in a routes file. The code below uses a PDO connection that the application already has:

<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

$siteUrl = 'https://www.example.com';

$app->get('/feed.xml', function (Request $request, Response $response) use ($pdo, $siteUrl) {
    $statement = $pdo->prepare(
        "SELECT id, title, slug, summary, published_at FROM posts "
        . "WHERE status = 'published' AND published_at <= :now "
        . "ORDER BY published_at DESC LIMIT 20"
    );
    $statement->execute(['now' => gmdate('Y-m-d H:i:s')]);
    $rows = $statement->fetchAll(PDO::FETCH_ASSOC);

    $e = fn (string $text): string => htmlspecialchars($text, ENT_XML1 | ENT_QUOTES, 'UTF-8');

    $items = '';
    foreach ($rows as $row) {
        $link = $siteUrl . '/blog/' . $row['slug'];
        $date = gmdate(DATE_RSS, strtotime($row['published_at'] . ' UTC'));
        $items .= '<item>'
            . '<title>' . $e($row['title']) . '</title>'
            . '<link>' . $e($link) . '</link>'
            . '<guid isPermaLink="false">post-' . (int) $row['id'] . '</guid>'
            . '<pubDate>' . $date . '</pubDate>'
            . '<description>' . $e((string) $row['summary']) . '</description>'
            . '</item>';
    }

    $xml = '<?xml version="1.0" encoding="UTF-8"?>'
        . '<rss version="2.0"><channel>'
        . '<title>Example Blog</title>'
        . '<link>' . $siteUrl . '/blog</link>'
        . '<description>News and articles from Example</description>'
        . $items
        . '</channel></rss>';

    $etag = '"' . md5($xml) . '"';
    if ($request->getHeaderLine('If-None-Match') === $etag) {
        return $response->withStatus(304)->withHeader('ETag', $etag);
    }

    $response->getBody()->write($xml);
    return $response
        ->withHeader('Content-Type', 'application/rss+xml; charset=utf-8')
        ->withHeader('Cache-Control', 'public, max-age=300')
        ->withHeader('ETag', $etag);
});

The route is short, but each line has a reason. The query filters on both the status and the date, so drafts and scheduled posts stay hidden. The escaping helper uses the XML flag, which converts the five special characters and keeps the result valid. The date uses the RSS constant of PHP with gmdate, which writes the time in UTC. The identifier in the GUID comes from the database and is cast to an integer, so it can never contain markup.

Why an ETag helps

The ETag is a fingerprint of the feed. When a client repeats the request with the fingerprint it received last time, the route can answer with a short 304 response and no body. Feed readers and auto-posters send these conditional requests routinely, so a quiet feed costs almost nothing to serve. The mechanism is explained in ETags and conditional GET. If your server also compresses responses, make sure the ETag still changes when the content does.

Sub-directory installs and the base path

The most common Slim surprise is the base path. If the application lives in a sub-directory, for example https://www.example.com/app/, the route /feed.xml will answer a 404 until you tell Slim where it lives. Call $app->setBasePath('/app') before you define routes, or configure the web server so that the application sits at the root. Also check that the rewrite rule sends requests for feed.xml to index.php. Some servers have a rule that treats any path with a file extension as a static file, so the request never reaches Slim. A quick test with curl shows which case you are in: a 404 from the web server looks different from a 404 produced by Slim.

Where each field comes from

RSS elementSource in the appRule
titlepost titleEscape it; keep it short and descriptive
linksite address plus slugAlways absolute and public
guiddatabase identifierNever changes, even if the slug does
pubDatepublication dateUTC, RFC 822 format, never in the future
descriptionsummaryPlain text or escaped HTML; the first sentence matters most

Two of these rules cause most of the support questions. Use the identifier, not the slug, for the GUID; otherwise renaming a post makes it look new, and an auto-poster may share it twice, as described in why your RSS feed auto-posts the same article twice. And keep dates in the format explained in RSS date formats and pubDate errors. If summaries contain HTML, escape them or use CDATA; see CDATA and HTML in RSS descriptions.

Move the code out of the route

A closure is fine for a first version, but a real project is easier to maintain when the feed has its own class. Create a small class named FeedController with an __invoke method, receive the database connection and the site address through the constructor, and register the route with the class name. If you use a container such as PHP-DI, it builds the controller and supplies the dependencies. The query and the XML building can then live in separate methods, which makes them easy to test: a unit test can pass a list of fake rows to the builder and compare the output with an expected string. Tests catch the mistakes that hurt feeds most, namely unescaped characters, wrong date formats and items that should have been hidden.

Separate feeds for categories

Once the route works, you can add a second route for a category, such as /feed/news.xml или /feed/{category}.xml, and pass the category name to the same query as an extra condition. Separate feeds let you send different kinds of content to different channels, for example announcements to a company page and tutorials to a developer community. Validate the category against a list of known values before using it, and answer with a 404 for anything else. The routing idea behind this is explained in category filtering for auto-posting.

Middleware, errors and caching

Slim lets you add middleware around routes, and two kinds are useful for a feed. Error middleware should catch database failures and return a plain 503 status instead of a stack trace or, worse, an empty feed. An empty file can look like a deletion to some tools, while an error status simply makes them try again later. A caching layer in front of the application, such as a reverse proxy or a content delivery network, uses the cache header to keep one copy for a few minutes. That is plenty, and it protects the database from bursts of requests. Avoid very long lifetimes; they delay every share, as explained in RSS feed caching explained. The right content type is covered in the Content-Type guide.

Test the feed before connecting it

  1. Request the feed with curl -i https://www.example.com/feed.xml and check for a 200 status, the XML content type, the cache header and the ETag. The method is described in debugging an RSS feed with curl.
  2. Repeat the request with the header If-None-Match set to the ETag and confirm that you receive a 304.
  3. Validate the file with the W3C Feed Validation Service.
  4. Publish a test post and confirm that it appears first after the cache expires.
  5. Create a post with a future date and confirm that it stays hidden.

Common mistakes to avoid

  • Forgetting the base path. A sub-directory install returns 404 for the route until the path is set.
  • Printing PHP warnings into the output. A single notice before the XML declaration breaks the feed. Turn off error display in production and log errors instead.
  • Whitespace before the opening tag. A blank line at the start of an included file corrupts the XML.
  • Using local time for dates. Convert to UTC and use the RSS format.
  • Returning an empty feed on errors. Return an error status and keep serving the cached copy.
  • Linking to internal addresses. Build links from a configured public site address.

How PostRSS works with a Slim feed

PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your feed.xml route, 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 item, with its link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, including LinkedIn, X, Bluesky, Mastodon and Telegram. Keyword filters, UTM parameters and posting windows let you tune each channel. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.

Связанное чтение

The bottom line

A Slim feed is one route. Query only published items, escape every value, use a stable identifier for the GUID, write dates in UTC in the RSS format, build absolute links from a configured address and return the XML with the correct content type, a short cache and an ETag. Remember the base path for sub-directory installs, keep warnings out of the output and return an error status instead of an empty file. Then test with curl and a validator, and connect the address to an auto-poster so each new item is shared without manual work.

FAQ

Does Slim have a built-in RSS feature?

No. Slim is a micro-framework for routing and middleware, so you build the XML yourself in a route, as shown above, or use a small feed library of your choice.

Why does my feed route return 404 in a sub-directory?

Slim does not know the application lives in a sub-directory. Set the base path before defining routes and make sure the web server rewrites requests to the front controller.

Why is my feed invalid after I added logging?

Output before the XML declaration, such as a PHP warning, a debug line or a blank line in an included file, breaks the document. Disable error display in production and send messages to a log file.

How many items should the feed contain?

Ten to twenty of the newest published items are enough. Auto-posters only need recent items, and a smaller file downloads and parses faster.

Can I use the Slim feed with PostRSS?

Yes. Add the public address of the feed as a source in PostRSS, connect your social accounts and each new item is posted automatically. Check that the address opens without a login.

{“@context”: “https://schema.org”, “@type”: “FAQPage”, “mainEntity”: [{“@type”: “Question”, “name”: “Does Slim have a built-in RSS feature?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “No. Slim is a micro-framework for routing and middleware, so you build the XML yourself in a route, as shown above, or use a small feed library of your choice.”}}, {“@type”: “Question”, “name”: “Why does my feed route return 404 in a sub-directory?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Slim does not know the application lives in a sub-directory. Set the base path before defining routes and make sure the web server rewrites requests to the front controller.”}}, {“@type”: “Question”, “name”: “Why is my feed invalid after I added logging?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Output before the XML declaration, such as a PHP warning, a debug line or a blank line in an included file, breaks the document. Disable error display in production and send messages to a log file.”}}, {“@type”: “Question”, “name”: “How many items should the feed contain?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Ten to twenty of the newest published items are enough. Auto-posters only need recent items, and a smaller file downloads and parses faster.”}}, {“@type”: “Question”, “name”: “Can I use the Slim feed with PostRSS?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Yes. Add the public address of the feed as a source in PostRSS, connect your social accounts and each new item is posted automatically. Check that the address opens without a login.”}}]}

New guides, once a month

What changed in the networks, what broke, and how to fix it before it costs you reach.

We send a confirmation e-mail first. Unsubscribe any time.

Другие инструменты нашей команды

Создано Internet Solutions — командой PostRSS. Каждый продукт экономит ваше время по-своему.

ИИ-чат для сайтов Talkmio Ваш сайт отвечает посетителям круглосуточно на основе вашего контента и на их языке. Бесплатный план · без карты ИИ-ассистент Ask Mio Чат, код, дизайн, тексты и исследования. Mio выбирает лучшую модель для каждой задачи. Бесплатный план ИИ-автопилот для блога и соцсетей AI Blog Autopilot ИИ пишет SEO-статьи на 2 000–3 000 слов и публикует каждую в 60 соцсетях. Первые 3 статьи бесплатно Проверка состояния сайта Аудит ИИ сайта SEO, скорость, SSL, безопасность и настройки почты в одном отчёте — в порядке важности исправлений. Первый аудит бесплатно Глубокий SEO-аудит Аудит SEO ИИ сайта Полный SEO-обход по 7 направлениям, включая видимость в ИИ-поиске, с исправлениями по степени влияния. Первый аудит бесплатно RSS и товарные фиды Создатель RSS‑ленты Создавайте RSS из любой веб-страницы, а также товарные фиды для Google и Meta, которые обновляются сами. Бесплатный план Разработка сайтов и SEO Internet Solutions Сайты, интернет-магазины и индивидуальные системы — проектируем, создаём и поддерживаем сами. С 2011 года