This PHP script scans a directory for XML sitemap files and automatically builds a valid sitemap index that points search engines to each sitemap.
It supports regular .xml sitemap files and compressed .xml.gz files, sorts them alphabetically, and uses the real file modification time for each <lastmod> value.
This is useful when a site has grown beyond a single sitemap and you want to separate URLs into files such as pages, posts, images, products, categories, or other sections.
Instead of manually maintaining one large sitemap index, the script reads the sitemap files already in the directory and builds the index automatically.
/sitemaps/
sitemap-pages.xml
sitemap-posts.xml
sitemap-images.xml
index.php
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://example.com/sitemaps/sitemap-images.xml</loc>
<lastmod>2026-09-17T13:20:00+00:00</lastmod>
</sitemap>
<sitemap>
<loc>https://example.com/sitemaps/sitemap-pages.xml</loc>
<lastmod>2026-09-17T12:05:00+00:00</lastmod>
</sitemap>
<sitemap>
<loc>https://example.com/sitemaps/sitemap-posts.xml</loc>
<lastmod>2026-09-16T19:30:00+00:00</lastmod>
</sitemap>
</sitemapindex>
Save this as index.php inside the directory that contains your sitemap files.
Before using it, change $baseUrl near the top of the script so it matches the public URL of your sitemap directory.
<?php
declare(strict_types=1);
/*
* PHP Sitemap Index Generator
* PHP 8+
*
* Put this file inside the directory containing
* your individual sitemap files.
*
* Example:
*
* /sitemaps/
* sitemap-pages.xml
* sitemap-posts.xml
* sitemap-images.xml
* index.php
*/
header('Content-Type: application/xml; charset=UTF-8');
/*
* CHANGE THIS to the public URL of the directory
* containing your sitemap files.
*/
$baseUrl = 'https://example.com/sitemaps/';
$sitemapDir = __DIR__;
/*
* Sitemap files that should not be included.
*/
$skipFiles = [
'sitemap.xml',
'sitemap-index.xml',
'sitemap_index.xml',
];
/*
* Escape text safely for XML.
*/
function xmlEscape(string $value): string
{
return htmlspecialchars(
$value,
ENT_XML1 | ENT_QUOTES,
'UTF-8'
);
}
$files = @scandir($sitemapDir);
$sitemaps = [];
if ($files !== false) {
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}
if (in_array($file, $skipFiles, true)) {
continue;
}
$fullPath = $sitemapDir . DIRECTORY_SEPARATOR . $file;
if (!is_file($fullPath)) {
continue;
}
/*
* Include regular XML sitemap files
* and compressed .xml.gz sitemap files.
*/
if (!preg_match('/\.xml(?:\.gz)?$/i', $file)) {
continue;
}
$modified = @filemtime($fullPath);
$sitemaps[] = [
'file' => $file,
'lastmod' => $modified
? date(DATE_W3C, $modified)
: null,
];
}
}
/*
* Sort sitemap files alphabetically.
*/
usort(
$sitemaps,
static fn(array $a, array $b): int =>
strcasecmp($a['file'], $b['file'])
);
/*
* A sitemap index can contain up to
* 50,000 sitemap entries.
*/
if (count($sitemaps) > 50000) {
http_response_code(500);
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
echo '<error>Too many sitemap files.</error>';
exit;
}
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
echo '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
foreach ($sitemaps as $sitemap) {
$url =
rtrim($baseUrl, '/') .
'/' .
rawurlencode($sitemap['file']);
echo " <sitemap>\n";
echo ' <loc>' .
xmlEscape($url) .
"</loc>\n";
if ($sitemap['lastmod'] !== null) {
echo ' <lastmod>' .
xmlEscape($sitemap['lastmod']) .
"</lastmod>\n";
}
echo " </sitemap>\n";
}
echo "</sitemapindex>\n";
The main setting you need to change is:
$baseUrl = 'https://example.com/sitemaps/';
For example, if your sitemap files are publicly available under /sitemaps/, use the complete URL to that directory.
The script does not invent modification dates. It reads the actual file modification time of each sitemap and converts it to the date format used by sitemap indexes.
When a sitemap file changes, its <lastmod> value changes with it.
The script automatically includes files ending in:
.xml
.xml.gz
Other files in the same directory are ignored.
Need to create the individual XML sitemap files first?
Simple XML Sitemap Generator PHP Script
Use the XML sitemap generator for individual sitemap files, then use this sitemap index generator when you have multiple sitemaps to group together.
This script does not crawl your website for URLs. It expects individual sitemap files to already exist in the directory.
It also does not automatically submit the sitemap index to Google or other search engines.
Keep the sitemap directory limited to sitemap files you actually want included. Files listed in $skipFiles are ignored so the index does not accidentally include itself.
For a normal site, you can submit the public URL of this generated sitemap index in your search engine webmaster tools or reference it from your robots.txt.