Open-source project
samdark/sitemap avatar
samdark/sitemap

samdark/sitemap splits files by itself when the URL or byte limit is hit

Sitemap and sitemap index builder

544 stars93 forksPHPBSD-3-Clause

At a glance

What is it?
samdark/sitemap is a PHP library that writes XML sitemaps and sitemap indexes, and it rolls over to a new file on its own when either the 50000 URL or the 10MiB size limit is reached. It suits a PHP site that needs plain sitemap XML without a framework, and it leaves indexing policy and content selection to you.
Who is it for?
samdark/sitemap is a good fit for a PHP application that already has a query or route list and needs valid sitemap XML, including the file rollover that the 50000 URL and 10MiB limits force you to handle, because the library does that bookkeeping and returns the written file URLs for an index.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 95 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The class writes XML directly to a path you name

The library has a small surface and a clear job. You construct a `Sitemap` with the path of the file you want written, add items to it, and call `write()`. The constructor takes a path, and the first example in the documentation is a sitemap at `__DIR__ . '/sitemap.xml'`. The second constructor argument is the switch for multi-language output, since the documentation says to be sure to pass `true` as the second parameter to specify the XHTML namespace, so `new Sitemap(__DIR__ . '/sitemap_multi_language.xml', true)` produces a document with the XHTML namespace declared. There is no configuration file, no service container and no base class to extend, which is the point. A `Sitemap` object is a file writer with a schema on top. What it does not contain is any notion of where your URLs come from, which URLs deserve to be in a sitemap, or how often the file should be rebuilt. Those decisions stay in your application, and the library's job is to turn a list of items into spec-shaped XML.

Installing is one Composer command, and the checks are four more

The library is distributed on Packagist and the installation is described as very simple:

sh
composer require samdark/sitemap

After that, one step remains on the application side. The documentation says to make sure your application autoloads Composer classes by including `vendor/autoload.php`. There is no configuration file, no key and no service registration, because the library has no runtime settings that need to be persisted; every option is a method call on the object you construct. The development commands follow the same shape. The test suite runs with:

sh
composer test

Static analysis with PHPStan, the rewrite checks with Rector and the benchmarks with PHPBench are each a single composer script as well, which is what makes this repository pleasant to contribute to: `composer phpstan`, `composer rector` to check and `composer rector:fix` to apply, and `composer bench` for the benchmark suite. The repository is small and the root tells you the whole story: a `src/` directory, `tests/`, `benchmarks/`, a `composer.json`, `phpunit.xml.dist`, `phpstan.neon.dist`, `rector.php`, `phpbench.json` and the example stylesheet. Four composer scripts cover the development loop. `composer test` runs the test suite, `composer phpstan` checks the code with PHPStan, `composer rector` checks code with Rector and `composer rector:fix` applies Rector's changes, which makes Rector a rewrite-in-progress tool here rather than a one-off. The benchmark suite is the fourth, `composer bench`, and it uses PHPBench to measure the workflows from the examples above for small, medium and large websites: content sitemap generation, static sitemap generation, multi-language sitemap generation and sitemap index generation. That last detail tells you the library's author treats it as a performance-sensitive component, and the benchmark design gives you the four shapes worth measuring against your own site before you adopt it. The documentation also carries a Packagist PHP version support badge and a GitHub workflow badge for the test suite.

addItem takes modification time, change frequency, priority and images

The item signature is the API's most informative surface, because the optional arguments map directly onto the sitemap protocol. The first argument is the URL, the second is a modification timestamp, the third is a change frequency constant, the fourth is a priority, and the fifth is a list of image URLs. The examples use `time()` for the timestamp, and the change frequency comes from class constants on `Sitemap`, with `Sitemap::HOURLY`, `Sitemap::DAILY` and `Sitemap::WEEKLY` appearing in the samples. The priority is a float, with a value of 0.3 shown in one example and 1 in another. The image argument is what makes the fifth parameter useful: the documentation explains that image URLs are passed as the fifth argument of `addItem()`, that each one is encoded and validated before it is written, and that a URL can carry up to 1000 images. The five-argument form, with a page URL, a timestamp, a weekly frequency, a priority of 1 and two image URLs, is the shape you would copy for a product or article page.

Rolling over at 50000 URLs or 10MiB is automatic, and getSitemapUrls tells you what happened

The detail that makes this library more than a writer is the rollover behaviour, listed in the features as automatically creating a new file if either the URL limit or the file size limit is reached. Both limits are configurable. `setMaxUrls($number)` sets the maximum number of URLs in a single file, with a default of 50000, which the documentation notes is the limit according to the specification and most of the existing implementations. `setMaxBytes($number)` sets the maximum size of a single file, defaulting to 10MiB, which the documentation says should be compatible with most current search engines. Because a single file can therefore be several files, the object has to tell you what it wrote, and `getSitemapUrls('http://example.com/')` does that, returning the URLs of the sitemaps that were written, with the base URL you pass in. That return value is the bridge to the index, and the worked example threads it straight through: the URLs of the main sitemap and the URLs of the static sitemap are both added to an `Index` object, which is then written to `sitemap_index.xml`.

The buffer size is the knob that decides how often the file is touched

`setBufferSize($number)` sets the number of URLs kept in memory before writing to the file, and the documentation is candid that the default of 10 gives only marginal benefits from a larger value. The reason it cannot simply be large is stated in the next sentence: when the file size limit is hit, the complete buffer must be written to the next file. So a large buffer does not smooth over the byte limit, it just means that a rollover carries a large chunk of unwritten items with it. The other two options are about output shape rather than performance. `setUseIndent($bool)` sets whether the XML should be indented, and it defaults to true, which is what you want for a file a human may open while debugging and what you do not necessarily want for a large production file. `setUseGzip($bool)` sets whether the resulting sitemap files are gzipped, and it defaults to false, with the requirement that the `zlib` extension must be enabled to use the feature. The `Index` class has its own `setUseGzip` and its own `setStylesheet`, both with the same defaults, so an index can be compressed independently of the sitemaps it lists.

Stylesheets are attached by URL, and the example file is the documentation

The stylesheet feature is a single method, `setStylesheet($string)`, which sets the `xml-stylesheet` tag. By default the tag is not generated, and the documentation points at an example file in the repository, `example-sitemap-stylesheet.xsl`, rather than describing the format. That is a reasonable choice for a small library, and it is also a limitation worth naming, because attaching an XSL stylesheet to a sitemap is how a human-readable index is normally produced, and this library gives you the tag but not the stylesheet. You write that part yourself, and the repository carries an example to copy. Every example uses the same stylesheet URL, `http://example.com/css/sitemap.xsl`, for the content sitemap, the static sitemap and the index, so the three documents share one presentation. The `Index` object takes the same method, which means an index can carry its own stylesheet independent of the sitemaps beneath it.

Multi-language output needs the XHTML flag and a halved URL limit

The multi-language mode is the least obvious part of the API. You pass an array keyed by language code instead of a string URL, with a `ru` key and an `en` key in the examples pointing at the same page under different prefixes. The array form works with the same optional arguments, so the third example passes an array with a timestamp and `Sitemap::HOURLY`, and the fourth adds `Sitemap::DAILY` and a priority of 0.3. The catch is a capacity one. The documentation tells you to set the URL limit to fit inside the default limit of 50000, being the default limit divided by the number of languages, and the example calls `setMaxUrls(25000)` for two languages. The reason is arithmetic rather than a rule inside the library: each language variant counts against the same 50000 URL budget, so a bilingual site halves the number of pages it can hold in one file. The XHTML namespace in the constructor's second argument is what makes the alternates valid, and without it the language links would not be expressed the way the protocol expects.

Where this library stops, and what the alternative shape is

The boundary is the word builder. This library turns a list of URLs into files; it does not decide what belongs in a sitemap, it does not watch a database for new content, and it does not tell a crawler about anything you did not add. The worked example makes that division visible, with one sitemap for content pages and a separate one for static pages such as an about page, a terms page and a jobs page, both listed in the same index. That pattern is the library's intended usage, and it is also its limit: the selection logic, the scheduling and the incremental behaviour all live in your code. The alternative to weigh against is generating the sitemap from a framework's routing table or an ORM query at request time or on a schedule, where the URL set is derived rather than hand-assembled. The difference in approach is that this library hands you full control over exactly what is in the file, which matters when you want a hand-curated set of pages, and gives you nothing when you want coverage that keeps itself up to date. For a site whose URL set is dynamic and large, a route-driven generator is the better fit; for a site with a few hundred curated pages, this library is smaller, faster and easier to reason about. The BSD-3-Clause licence and the SemVer release history with 3.1.0 published on 2026-07-20 are the other two facts to weigh.

Editorial conclusion

samdark/sitemap is a good fit for a PHP application that already has a query or route list and needs valid sitemap XML, including the file rollover that the 50000 URL and 10MiB limits force you to handle, because the library does that bookkeeping and returns the written file URLs for an index. It is a poor fit for a large content site that needs incremental updates, since the documented workflow writes whole files and there is no mention of resuming a partial write, and a poor fit if you want a crawler to discover URLs on its own, since the sitemap only ever contains what you add to it. Before adopting it, decide where the URL list comes from and how often it is rebuilt, check that the `zlib` extension is present if you want gzipped output, and read the `example-sitemap-stylesheet.xsl` file if you plan to attach a stylesheet, since the documentation points at it rather than explaining it. The last push to the repository was on 2026-07-20, with release 3.1.0 published the same day.

Frequently asked questions

How do I install samdark/sitemap?

Install it with Composer by running composer require samdark/sitemap, then make sure your application autoloads Composer classes by including vendor/autoload.php. The package is published on Packagist under samdark/sitemap.

Does samdark/sitemap split a sitemap into multiple files automatically?

Yes. The library automatically creates a new file when either the URL limit or the file size limit is reached. setMaxUrls controls the URL count, defaulting to 50000, and setMaxBytes controls the file size, defaulting to 10MiB, and getSitemapUrls returns the URLs of the files that were written.

How do I create a multi-language sitemap with samdark/sitemap?

Pass true as the second constructor argument to set the XHTML namespace, then add items as arrays keyed by language code. Because each language variant counts against the same limit, the documentation says to set the URL limit to the default divided by the number of languages, for example setMaxUrls(25000) for two languages.

How do I run the tests and checks for samdark/sitemap?

Run composer test for the test suite, composer phpstan for static analysis, composer rector to check refactoring rules and composer rector:fix to apply them. The benchmark suite runs with composer bench and uses PHPBench to measure the content, static, multi-language and index generation workflows.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. README
  4. Releases
  5. samdark/sitemap on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/samdark-sitemap.svg)](https://hysenlabs.com/projects/samdark-sitemap)

Was this useful?