What is a Dynamic XML Sitemap?

             

A dynamic XML sitemap is an automatically generated XML file (typically accessed at /sitemap.xml) that updates in real-time whenever your site content changes—new posts are published, existing pages are edited, or URLs are added/removed. Unlike static sitemaps that require manual updates and file regeneration, a dynamic version in CodeIgniter 4 queries your database on each request, ensuring search engine crawlers always see the most current structure. It includes critical metadata such as lastmod (last modification date), changefreq, and priority, helping Google prioritize crawling and improve indexing speed and accuracy.



Create a Dynamic XML Sitemap in CodeIgniter 4 – Complete Tutorial

Table Of Content

1 Prerequisites

  • PHP ≥ 8.1 (CodeIgniter 4 requirement)
  • Composer
  • MySQL database

2 Introduction

In today's competitive digital landscape, ensuring search engines like Google can efficiently discover and index your website's content is essential for strong SEO performance. A dynamic XML sitemap in CodeIgniter 4 solves this by automatically generating an up-to-date list of your URLs, including posts, pages, categories, or products pulled directly from your database.

3 Install CodeIgniter 4 Project

3.1 Install Codeigniter 4 Project

First, make sure your computer has a composer.
Use the following command to install new Codeigniter Project.

composer create-project codeigniter4/appstarter ci4-sitemap

Then, navigate to your project directory:

cd ci4-sitemap

3.2 Configure Environment and MySql Database

Rename the env file to .env and set the development mode in the .env file also configure mysql:

# CI_ENVIRONMENT = production
CI_ENVIRONMENT = development


database.default.hostname = localhost
database.default.database = ci4_sitemap
database.default.username = root
database.default.password = 
database.default.DBDriver = MySQLi

Create the database ci4_sitemap.

4 Create Migration and Model

Create a migration for the posts table and a model to manage data:

php spark make:model Post --suffix

Edit app/Models/PostModel.php to configure the model:

<?php
namespace App\Models;

use CodeIgniter\Model;

class PostModel extends Model
{
    protected $table            = 'posts';
    protected $primaryKey       = 'id';
    protected $allowedFields    = ['title', 'slug', 'content', 'created_at', 'updated_at'];
    protected $useTimestamps    = true;
}

Create a migration file for the posts table:

php spark make:migration CreatePostsTable

Edit the migration file to define the table structure:

<?php
forge->addField([
            'id'         => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
            'title'      => ['type' => 'VARCHAR', 'constraint' => 255],
            'slug'       => ['type' => 'VARCHAR', 'constraint' => 255, 'unique' => true],
            'content'    => ['type' => 'TEXT'],
            'created_at' => ['type' => 'DATETIME', 'null' => true],
            'updated_at' => ['type' => 'DATETIME', 'null' => true],
        ]);
        $this->forge->addPrimaryKey('id');
        $this->forge->createTable('posts');
    }

    public function down()
    {
        $this->forge->dropTable('posts');
    }
}

Run the migration:

php spark migrate

5 Create Database Seeder

For seeding test data in the posts table, use the Seeder class:

php spark make:seeder PostSeeder

Inside the PostSeeder.php file, use the Faker library to generate fake data:

<?php
sentence(6);
            $model->insert([
                'title'      => $title,
                'slug'       => url_title($title, '-', true),
                'content'    => $faker->paragraphs(3, true),
                'created_at' => $faker->dateTimeThisYear(),
                'updated_at' => $faker->dateTimeThisMonth(),
            ]);
        }
    }
}

Run this below command to insert the data.

php spark db:seed PostSeeder

6 Create Sitemap Controller

Create a controller to handle sitemap requests:

php spark make:controller Sitemap 

In app/Controllers/Sitemap.php, define the index function:

<?php
namespace App\Controllers;

use App\Models\PostModel;
use CodeIgniter\HTTP\ResponseInterface;

class Sitemap extends Controller
{
    public function index(): ResponseInterface
    {
        $this->response->setContentType('application/xml');

        $postModel = new PostModel();
        $posts = $postModel->findAll();

        return view('sitemap', ['posts' => $posts]);
    }
}
?>

7 Create a View

Create the index.php view file in app/Views/ to generate the dynamic XML sitemap:

   <?php 
header('Content-Type: application/xml; charset=utf-8');
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc><?= esc(base_url()) ?></loc>
        <lastmod><?= date('c') ?></lastmod>
        <changefreq>daily</changefreq>
        <priority>1.0</priority>
    </url>

    <?php foreach ($posts as $post): ?>
    <url>
        <loc><?= esc(base_url('post/' . $post['slug'])) ?></loc>
        <lastmod><?= date('c', strtotime($post['updated_at'])) ?></lastmod>
        <changefreq>weekly</changefreq>
        <priority>0.7</priority>
    </url>
    <?php endforeach; ?>
</urlset>

8 Define a Route

In app/Config/Routes.php, define routes for the sitemap controller:

use CodeIgniter\Router\RouteCollection;

/**
 * @var RouteCollection $routes
 */
$routes->get('/', 'Home::index');
$routes->get('sitemap.xml', 'Sitemap::index');

9 Folder Structure

10 Run Web Server to Test the App

Use the following command to Test the App.

php spark serve

Visit: http://localhost:8080/sitemap.xml
You should see valid XML. Submit to Google Search Console.

Best Practices & Tips

  • Use real updated_at for accurate lastmod.
  • For large sites (>50k URLs), implement sitemap index files or caching (e.g., via CI Cache library).
  • Add static pages manually in the view.
  • Validate with tools like XML-Sitemaps.com validator.
  • Ping search engines after major updates.

11 Conclusion

Implementing a dynamic XML sitemap in CodeIgniter 4 is straightforward and boosts your site's SEO. With this setup, new content appears automatically — no manual updates needed.
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

A dynamic XML sitemap helps search engines like Google, Bing, and Yahoo discover and crawl your website pages more efficiently, improving SEO and indexing of dynamic content.

Create a migration for a 'posts' table with fields like id, name, slug, description, created_at, and updated_at. Run the migration and use a seeder with Faker to insert test data.

In the Sitemap controller, use a PostModel to fetch all records with findAll(). Pass the data to a view that loops through posts and generates entries with base_url('post/' . $item['name']).

In app/Config/Routes.php, add $routes->get('sitemap.xml', 'Sitemap::index');. This serves the XML output when accessing /sitemap.xml.

The view (e.g., app/Views/index.php) outputs XML with '; ?>, namespace, static homepage , and a foreach loop for dynamic post URLs with , , , and .

In the view, use or post['updated_at'], daily, and 0.5 (adjust values based on page importance).

Yes, manually add blocks in the view for static pages like the homepage: with custom priority and changefreq.

Common issues: Incorrect route, view not returning XML headers, or database connection problems. Ensure the controller calls view('index', $data) directly (no layout) and test with php spark serve.

Store updated_at in the database and use in the view loop instead of current timestamp.

For production with many URLs, add caching in the controller (e.g., CodeIgniter's Cache library) to avoid database queries on every request.