RSS'den 66 sosyal ağa: Facebook, Instagram, X, LinkedIn, Telegram ve daha fazlası Blog Satış Ortaklığı İletişim
Giriş yapın Ücretsiz başlayın
Updated: 2026-10-14
CodeIgniter 4 RSS Feed: Controller, Route and Auto-Posting

Short answer: A CodeIgniter 4 RSS feed needs three small pieces. Add a route such as $routes->get('rss.xml', 'Feed::index'), create a controller that loads the newest published posts from your model, and build RSS 2.0 with XMLWriter, which escapes text for you. Return it with the content type application/rss+xml, absolute links from site_url() and a stable GUID based on the post ID. Then connect the feed address to an auto-poster, and every new post is shared on social media automatically.

CodeIgniter 4 is a lightweight PHP framework known for its small footprint, clear structure and easy hosting on ordinary shared servers. Many company sites, directories and small blogs run on it. The framework has no feed component, and you do not need an extra package: PHP already contains the XML tools, and CodeIgniter provides routing, models and a response object. This guide walks through the route, the controller, the model query, images, dates, caching and testing, and explains the mistakes that most often break a feed.

Plan the feed before writing code

A feed is a list of the newest public items with five facts for each: a title, a link, a unique ID, a date and a short description. A picture is a welcome sixth. Check that your database table has these pieces. A typical posts table has id, title, slug, summary, image, status ve published_at. If you only have a full body column, add a short summary column; auto-posters and readers display the description, and a whole article makes a poor social post. The reasoning is in how to control the excerpt in your RSS feed.

Also confirm that baseURL in app/Config/App.php, or app.baseURL in your .env file, is your full public address with https. Every link in the feed is built from it, and a wrong value produces links to localhost or to the wrong host.

The route

Open app/Config/Routes.php and add:

$routes->get('rss.xml', 'Feed::index');

A route with a file-like name works as expected, and the feed is then available at https://www.example.com/rss.xml. If you prefer a path without an extension, such as /feed, use that name in the route instead. Pick one address and keep it, because auto-posters store it.

The controller

Create app/Controllers/Feed.php. The code below uses the built-in XMLWriter, which escapes ampersands and angle brackets in text automatically, so a title such as “Q&A” cannot break the document:

<?php

namespace App\Controllers;

use App\Models\PostModel;
use XMLWriter;

class Feed extends BaseController
{
    public function index()
    {
        $posts = (new PostModel())
            ->where('status', 'published')
            ->orderBy('published_at', 'DESC')
            ->findAll(20);

        $xml = new XMLWriter();
        $xml->openMemory();
        $xml->startDocument('1.0', 'UTF-8');
        $xml->startElement('rss');
        $xml->writeAttribute('version', '2.0');
        $xml->startElement('channel');
        $xml->writeElement('title', 'Example Blog');
        $xml->writeElement('link', site_url('blog'));
        $xml->writeElement('description', 'News and articles from Example');

        foreach ($posts as $post) {
            $xml->startElement('item');
            $xml->writeElement('title', $post['title']);
            $xml->writeElement('link', site_url('blog/' . $post['slug']));
            $xml->startElement('guid');
            $xml->writeAttribute('isPermaLink', 'false');
            $xml->text('post-' . $post['id']);
            $xml->endElement();
            $xml->writeElement('pubDate', gmdate(DATE_RSS, strtotime($post['published_at'])));
            $xml->writeElement('description', $post['summary']);
            if (! empty($post['image'])) {
                $xml->startElement('enclosure');
                $xml->writeAttribute('url', base_url($post['image']));
                $xml->writeAttribute('type', 'image/jpeg');
                $xml->writeAttribute('length', '0');
                $xml->endElement();
            }
            $xml->endElement();
        }

        $xml->endElement();
        $xml->endElement();
        $xml->endDocument();

        return $this->response
            ->setHeader('Cache-Control', 'public, max-age=300')
            ->setContentType('application/rss+xml', 'utf-8')
            ->setBody($xml->outputMemory());
    }
}

The model is the usual CodeIgniter model: a class PostModel in app/Models that extends CodeIgniter\Model, with $table = 'posts', a primary key and the allowed fields. Nothing in it is specific to feeds.

Why each part matters

The query. It filters on the status and sorts by the publication date, newest first, with a limit of 20. A feed does not need the whole archive, and a short one is faster to download and to check. Sorting by an update date would push an edited old post to the top, and an auto-poster might treat it as new.

The GUID. The ID in post-12 never changes, even if the slug is edited. If the GUID were the slug or the address, a small correction could make the item look new, and it could be shared twice; see why your RSS feed auto-posts the same article twice.

The date. gmdate(DATE_RSS, ...) formats the time in the pattern that RSS expects. If the database stores local time, convert it to UTC first; mistakes in this step shift every post by hours. The common problems are listed in RSS date formats and pubDate errors.

The links. site_url() ve base_url() produce absolute addresses from your configured base URL. Relative paths work in a browser on your site but break in readers and on social networks, as explained in relative URLs in RSS feeds.

Images

Social networks build their preview cards from the picture of an item, so the image address matters. Store a path such as uploads/posts/cover.jpg and turn it into a complete address with base_url(). Use images of about 1200 pixels wide and make sure the folder is publicly readable. The type attribute should match the real file type; if your uploads can be JPEG, PNG or WebP, derive the type from the file extension instead of writing JPEG every time. Recommended dimensions for each network are listed in social media image sizes.

Caching

Readers and auto-posters request the feed regularly, and the data changes rarely. The cache header in the example lets proxies keep the response for five minutes. For busy sites you can also store the finished XML with the framework’s cache service and delete it when a post is saved, so the database is not queried on every request. Keep the lifetime short; a feed cached for a day delays every share by a day. If your server sits behind a security service, make sure it does not block the feed address; the symptoms are described in fixing 403 errors on RSS feeds.

Help tools discover the feed

Add a link tag to the head of your layout so that browsers and readers can find the feed: <link rel="alternate" type="application/rss+xml" title="Example Blog" href="https://www.example.com/rss.xml">. In your real layout, build the address with site_url('rss.xml'). A visible link in the footer, labelled RSS, helps visitors too. Discovery does not replace pasting the address into an auto-poster, but it makes the feed easy to find.

HTML in descriptions and categories

If your description contains HTML, for example an intro paragraph with links, use $xml->startElement('description'), then $xml->writeCdata($html), then $xml->endElement(). A CDATA section keeps the markup intact without double escaping; the trade-offs are discussed in CDATA and HTML in RSS descriptions. For auto-posting, however, plain text is almost always better, because social networks show the text without formatting.

You can also add a category element for each post, using the name of the category or tag. Auto-posters can turn categories into hashtags or use them to route items, so a clean set of short, consistent category names pays off. Write $xml->writeElement('category', $post['category']) once per category, and keep the names stable: renaming a category later changes the hashtags of future posts.

One feed per section

A real site often has more than one kind of content: news, tutorials, product updates. Add a route that contains the (:segment) placeholder, for example rss/(:segment).xml, pointing to a second controller method, which receives the section name as an argument. The method that receives the section name and adds a where('section', $section) condition. Return a 404 response when the section does not exist, so crawlers do not index empty feeds. Move the XML building into a private method that accepts a list of posts and a channel title, so both methods share it. Separate feeds let you send tutorials to LinkedIn, product updates to a customer channel and news to Facebook. Never place the section name straight into a query string by hand; pass it through the query builder, which binds the value safely. The idea of splitting feeds is explained in category filtering for auto-posting.

Using a view instead of XMLWriter

Some developers prefer a view file for the XML, like the other pages of the application. It is possible, but it has traps: PHP short open tags and the XML declaration collide, whitespace before the declaration breaks the document, and every value must be escaped with a function such as htmlspecialchars with the XML flags. XMLWriter avoids all three problems, which is why it is used here. If you do use a view, return it with $this->response->setContentType('application/rss+xml')->setBody(view('feed', $data)) and test the output with a validator.

Common mistakes to avoid

  • Output before the XML declaration. A stray space or a byte order mark in a PHP file before the opening tag breaks the document; see fixing the XML declaration error.
  • Debug toolbar in the output. In the development environment the toolbar can add HTML to responses. Test the feed in production mode.
  • Wrong content type. If the response is sent as text/html, strict readers may refuse it. Set application/rss+xml explicitly.
  • Drafts in the feed. Filter on the status in the query, not in the loop.
  • Different GUIDs on every run. Never build the GUID from the current time or a random value.

Test the feed before connecting it

  1. Request the feed with curl -i and confirm that the status is 200 and the content type is application/rss+xml.
  2. Check that the newest published post comes first and that no draft appears.
  3. Open several item links and image addresses; they must start with your public https domain.
  4. Run the feed through the W3C Feed Validation Service and fix every error.
  5. Publish a new post and check how quickly it shows in the feed.

Routing, controllers and the response object are described in the CodeIgniter user guide. For more checks, see debugging an RSS feed with curl.

How PostRSS works with a CodeIgniter site

PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your rss.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 post, with its image and link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, including Facebook Pages, LinkedIn, X, Telegram and Bluesky. Keyword filters, UTM parameters, hashtags from categories and posting windows let you tune each channel, and the REST API and webhooks connect PostRSS to your own systems. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.

İlgili Okumalar

The bottom line

A CodeIgniter 4 RSS feed is one route, one controller and a short model query. Filter on the status, sort by the publication date, build the XML with XMLWriter so text is escaped, use the post ID for the GUID, make every link and image absolute with site_url and base_url, and send the content type application/rss+xml. Validate it once, and every post you publish can reach your social channels automatically.

FAQ

Does CodeIgniter 4 have a built-in RSS feed?

No. The framework has no feed component, but PHP includes XMLWriter and CodeIgniter provides routing and a response object, so a feed takes one controller and one route.

Which address should the feed have?

Any address works. The names rss.xml and feed are common. Choose one, keep it stable and link to it from your page head so tools can discover it.

Why do my feed links point to localhost?

The links are built from the base URL in the application configuration or the environment file. Set it to your full public address with https and clear the cache.

How do I stop drafts from appearing?

Filter on the status field in the model query, so only published rows are returned. Test once with a draft post and confirm that it is missing from the feed.

Can I use the feed with PostRSS?

Yes. Paste the public feed address as a source in PostRSS, connect your social accounts and each new post is shared automatically. Check that the address opens without a login first.

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.

Ekibimizden daha fazla araç

PostRSS'in arkasındaki ekip Internet Solutions tarafından geliştirildi. Her biri size farklı bir şekilde zaman kazandırır.