in-square/pimcore-sitemap-bundle

Static XML sitemap generator for Pimcore (Documents + DataObjects).

Maintainers

Package info

github.com/in-square/pimcore-simple-sitemap-bundle

Homepage

Type:pimcore-bundle

pkg:composer/in-square/pimcore-sitemap-bundle

Transparency log

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.0 2026-07-28 11:04 UTC

This package is not auto-updated.

Last update: 2026-07-28 11:06:35 UTC


README

Static XML sitemap generator for Pimcore (Documents + DataObjects) with multi-site and multi-locale support.

Requirements

  • PHP 8.1+
  • Pimcore 11 / Symfony 6.4
  • Symfony Messenger (for queue processing)
  • Elements Process Manager (commands integrate with Process Manager)

Installation

composer require in-square/pimcore-sitemap-bundle

Enable the bundle in config/bundles.php:

return [
    InSquare\PimcoreSitemapBundle\InSquarePimcoreSitemapBundle::class => ['all' => true],
];

Configuration

Create config/packages/in_square_pimcore_sitemap.yaml:

in_square_pimcore_sitemap:
  sites:
    - id: 0
      host: 'example.com'
      languages: ['pl']
      objects:
        - 'Pimcore\Model\DataObject\Post'
        - 'Pimcore\Model\DataObject\PostCategory'

    - id: 1
      host: 'example.org'
      languages: ['pl', 'en']
      objects:
        - 'Pimcore\Model\DataObject\Product'

  object_generators:
    post: 'App\\Sitemap\\PostGenerator'
    postCategory: 'App\\Sitemap\\PostCategoryGenerator'
    product: 'App\\Sitemap\\ProductGenerator'

  output:
    dir: '%kernel.project_dir%/public/sitemap'
    max_urls_per_file: 50000

  hreflang:
    enabled: true
    x_default_language: 'en'
    x_default_fallback_language: 'pl'

Notes:

  • sites[*].objects defines DataObject classes to collect for each site.
  • object_generators keys must match the generator's getId(); keys are used in sitemap filenames.
  • hreflang.enabled controls generation of <xhtml:link rel="alternate" ... /> entries.
  • hreflang.x_default_language selects the preferred locale for x-default.
  • hreflang.x_default_fallback_language is used only when the preferred locale is missing.

Commands

  • bin/console insquare:sitemap:install – create sitemap_item table.
  • bin/console insquare:sitemap:collect – dispatch sitemap messages to Messenger.
  • bin/console insquare:sitemap:dump – generate XML files from database.
  • bin/console insquare:sitemap:delete – delete XML files and truncate the table.

For an existing installation, run Doctrine migrations after updating the bundle:

bin/console doctrine:migrations:migrate

Run collect, wait until Messenger finishes processing the dispatched messages, and then run dump. Collection uses a run token, so the dump can remove rows which were not seen during the latest completed collection without truncating the table while workers are active.

Add routing for Messenger in config/packages/framework.yaml:

framework:
  messenger:
    routing:
      'InSquare\PimcoreSitemapBundle\Message\SitemapItemCreateMessage': async

Run Messenger worker for the queue:

bin/console messenger:consume async

Controller

The bundle exposes /sitemap.xml. The controller selects the correct site and serves the pre-generated file from public/sitemap/sitemap.{siteId}.xml. The site index links directly to the locale/type URL sets, for example sitemap.0.pl.documents.xml.

Object generators

Implement InSquare\PimcoreSitemapBundle\Generator\ObjectGeneratorWithContextInterface in your app to receive the normalized sitemap host:

<?php

declare(strict_types=1);

namespace App\Sitemap;

use InSquare\PimcoreSitemapBundle\Generator\ObjectGeneratorWithContextInterface;
use InSquare\PimcoreSitemapBundle\Generator\SitemapGeneratorContext;
use InSquare\PimcoreSitemapBundle\Generator\SitemapItemData;
use Pimcore\Model\DataObject\Post;

final class PostGenerator implements ObjectGeneratorWithContextInterface
{
    public function getId(): string
    {
        return 'post';
    }

    public function getObjectClass(): string
    {
        return Post::class;
    }

    public function buildItem(object $object, SitemapGeneratorContext $context): ?SitemapItemData
    {
        if (!$object instanceof Post) {
            return null;
        }

        if (!$object->isPublished()) {
            return null;
        }

        $linkGenerator = $object->getClass()?->getLinkGenerator();
        if ($linkGenerator === null) {
            return null;
        }

        $path = $linkGenerator->generate($object, [
            'locale' => $context->getLocale(),
            'siteId' => $context->getSiteId(),
        ]);
        $url = $context->getHost() . '/' . ltrim((string) $path, '/');

        $lastmod = (new \DateTimeImmutable())->setTimestamp($object->getModificationDate());

        return new SitemapItemData(
            $object->getId(),
            $object::class,
            $url,
            $lastmod
        );
    }
}

The generator returns a SitemapItemData DTO used to persist rows in sitemap_item. SitemapGeneratorContext::getHost() is normalized to an absolute host such as https://example.com. The legacy ObjectGeneratorInterface remains available for backward compatibility but is deprecated.