This is a complex of services for build Sitemaps.xml and index of Sitemap.xml files.
See protocol for more details.
Pretty simple with Composer, run:
composer require gpslab/sitemap
Create a service that will return a links to pages of your site.
use GpsLab\Component\Sitemap\Builder\Url\UrlBuilder;
use GpsLab\Component\Sitemap\Url\Url;
class MySiteUrlBuilder implements UrlBuilder
{
private $urls;
public function __construct()
{
// add URLs on your site
$this->urls = new \ArrayIterator([
new Url(
'https://example.com/', // loc
new \DateTimeImmutable('-10 minutes'), // lastmod
Url::CHANGE_FREQ_ALWAYS, // changefreq
'1.0' // priority
),
new Url(
'https://example.com/contacts.html',
new \DateTimeImmutable('-1 month'),
Url::CHANGE_FREQ_MONTHLY,
'0.7'
),
new Url(
'https://example.com/about.html',
new \DateTimeImmutable('-2 month'),
Url::CHANGE_FREQ_MONTHLY,
'0.7'
),
]);
}
public function getName()
{
return 'My Site';
}
public function count()
{
return count($this->urls);
}
public function getIterator()
{
return $this->urls;
}
}
It was a simple builder. We add a builder more complicated.
use GpsLab\Component\Sitemap\Builder\Url\UrlBuilder;
use GpsLab\Component\Sitemap\Url\Url;
class ArticlesUrlBuilder implements UrlBuilder
{
private $pdo;
public function __construct(\PDO $pdo)
{
$this->pdo = $pdo;
}
public function getName()
{
return 'Articles on my site';
}
public function count()
{
$total = $this->pdo->query('SELECT COUNT(*) FROM article')->fetchColumn();
$total++; // +1 for section
return $total;
}
public function getIterator()
{
$section_update_at = null;
$sth = $this->pdo->query('SELECT id, update_at FROM article');
$sth->execute();
$i = 0;
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
$update_at = new \DateTimeImmutable($row['update_at']);
$section_update_at = max($section_update_at, $update_at);
// not forget free memory
if (++$i % 100 === 0) {
gc_collect_cycles();
}
// SmartUrl automatically fills fields that it can
yield new SmartUrl(
sprintf('https://example.com/article/%d', $row['id']),
$update_at
);
}
// link to section
yield new Url(
'https://example.com/article/',
$section_update_at ?: new \DateTimeImmutable('-1 day'),
Url::CHANGE_FREQ_DAILY,
'0.9'
);
}
}
We take one of the exists builders and configure it.
// collect a collection of builders
$collection = new UrlBuilderCollection([
new MySiteUrlBuilder(),
new ArticlesUrlBuilder(/* $pdo */),
]);
// the file into which we will write our sitemap
$filename = __DIR__.'/sitemap.xml';
// configure streamer
$render = new PlainTextSitemapRender();
$stream = new RenderFileStream($render, $filename);
// configure sitemap builder
$builder = new SilentSitemapBuilder($collection, $stream);
// build sitemap.xml
$total_urls = $builder->build();
You can create Sitemap index to group multiple sitemap files.
// collect a collection of builders
$collection = new UrlBuilderCollection([
new MySiteUrlBuilder(),
new ArticlesUrlBuilder(/* $pdo */),
]);
// the file into which we will write our sitemap
$filename_index = __DIR__.'/sitemap.xml';
// the file into which we will write sitemap part
// you must use the temporary directory if you don't want to overwrite the existing index file!!!
// the sitemap part file will be automatically moved to the directive with the sitemap index on close stream
$filename_part = sys_get_temp_dir().'/sitemap.xml';
// configure streamer
$render = new PlainTextSitemapRender();
$stream = new RenderFileStream($render, $filename_part)
// configure index streamer
$index_render = new PlainTextSitemapIndexRender();
$index_stream = new RenderFileStream($index_render, $stream, 'https://example.com/', $filename_index);
// configure sitemap builder
$builder = new SilentSitemapBuilder($collection, $index_stream);
// build sitemap.xml index file and sitemap1.xml, sitemap2.xml, sitemapN.xml with URLs
$total_urls = $builder->build();
If you use Symfony, you can use SymfonySitemapBuilder
in console.
class BuildSitemapCommand extends Command
{
private $builder;
public function __construct(SymfonySitemapBuilder $builder)
{
$this->builder = $builder;
}
protected function configure()
{
// ...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
// build sitemap.xml
$total_urls = $this->builder->build($io);
$io->success(sprintf('Build "%d" urls.', $total_urls));
}
}
LoggerStream
- use PSR-3 for log added URLsMultiStream
- allows to use multiple streams as oneOutputStream
- sends a Sitemap to the output buffer. You can use it in controllers.RenderFileStream
- writes a Sitemap to fileRenderIndexFileStream
- writes a Sitemap index to fileRenderGzipFileStream
- writes a Sitemap to Gzip fileRenderBzip2FileStream
- writes a Sitemap to Bzip2 fileCompressFileStream
- usegpslab/compressor
for compresssitemap.xml
You can use a composition from streams.
$stream = new MultiStream(
new LoggerStream(/* $logger */),
new RenderIndexFileStream(
new PlainTextSitemapIndexRender(),
new RenderGzipFileStream(
new PlainTextSitemapRender(),
__DIR__.'/sitemap.xml.gz'
),
'https://example.com/',
__DIR__.'/sitemap.xml',
)
);
Streaming to file and compress result without index
$stream = new MultiStream(
new LoggerStream(/* $logger */),
new CompressFileStream(
new RenderFileStream(
new PlainTextSitemapRender(),
__DIR__.'/sitemap.xml'
),
new GzipCompressor(),
__DIR__.'/sitemap.xml.gz'
)
);
Streaming to file and output buffer
$stream = new MultiStream(
new LoggerStream(/* $logger */),
new RenderFileStream(
new PlainTextSitemapRender(),
__DIR__.'/sitemap.xml'
),
new OutputStream(
new PlainTextSitemapRender()
)
);
This bundle is under the MIT license. See the complete license in the file: LICENSE