Add the SEO features that Sylius is missing — structured data, Open Graph metadata and a manageable
robots.txt — with sensible defaults and zero template changes.
Once installed, the plugin automatically enriches your storefront's <head> on every page, so search
engines and social networks understand your catalog out of the box.
-
🔎 Schema.org structured data (JSON-LD) — automatically generates and renders structured data for your storefront:
OnlineStoreandWebSiteon the homepage (theWebSitenode can expose a Sitelinks Search Box)Product/ProductGroupon product pages, including images and offers (price, availability, canonical variant URLs)
The data is rendered as a single JSON-LD graph in the shop
<head>. -
📣 Open Graph metadata — emits
<meta property="og:*">tags (title, description, site name, locale, images, …) for rich link previews on social platforms, populated from your channel and products. -
🤖 robots.txt management — edit a
robots.txtper channel straight from the admin panel and serve it at/robots.txt. The content is rendered as a Twig template, so it can be dynamic. -
🧩 Extensible by design — add or override any fact in the structured data with a tagged data mapper, or hook into the dedicated events. Nothing is hardcoded.
-
🌍 Translations — the admin UI ships with translations for 16 locales.
| Package | Version |
|---|---|
| PHP | >= 8.2 |
| Symfony | 6.4 or 7.4 |
| Sylius | ^2.0 |
Using Sylius 1.x? Use the
1.xbranch (^1.0) instead.
composer require setono/sylius-seo-plugin# config/bundles.php
return [
// ...
Setono\SyliusSEOPlugin\SetonoSyliusSEOPlugin::class => ['all' => true],
];# config/routes/setono_sylius_seo.yaml
setono_sylius_seo:
resource: "@SetonoSyliusSEOPlugin/config/routes.yaml"The plugin stores the robots.txt content on your channel. Implement the plugin's ChannelInterface
and use the ChannelTrait on your Channel entity:
<?php
declare(strict_types=1);
namespace App\Entity\Channel;
use Doctrine\ORM\Mapping as ORM;
use Setono\SyliusSEOPlugin\Model\ChannelInterface;
use Setono\SyliusSEOPlugin\Model\ChannelTrait;
use Sylius\Component\Core\Model\Channel as BaseChannel;
#[ORM\Entity]
#[ORM\Table(name: 'sylius_channel')]
class Channel extends BaseChannel implements ChannelInterface
{
use ChannelTrait;
}php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate -nThat's it — structured data and Open Graph tags are now rendered on your storefront automatically.
There is nothing to wire up in your templates. The plugin injects its output into the shop <head>
via Sylius Twig Hooks, so visiting the homepage or a product page already produces the JSON-LD graph
and the og:* meta tags. Use Google's
Rich Results Test to verify the structured data.
Go to Admin → Channels → (edit a channel) and fill in the Robots.txt field. The content is
served at /robots.txt for that channel's domain.
If a physical
public/robots.txtfile exists it is served by your web server and shadows this route. The admin form warns you when that is the case.
All structured data features are enabled by default. The full configuration with its defaults:
# config/packages/setono_sylius_seo.yaml
setono_sylius_seo:
# Service id of the canonical product variant URL generator. Override with your own implementation.
product_variant_url_generator: 'Setono\SyliusSEOPlugin\UrlGenerator\ProductVariantUrlGenerator'
structured_data:
product:
enabled: true
online_store:
enabled: true
website:
# Disabled by default. Enable it to add a WebSite node with a Sitelinks Search Box.
enabled: false
search_url_template:
route: app_shop_search # your own route handling search queries
query_parameter: q # the query parameter that route expectsTo turn a feature off, disable it:
setono_sylius_seo:
structured_data:
product:
enabled: falseEach Schema.org type is built by a set of data mappers. To add a new fact, create a class implementing the relevant interface — it is autoconfigured and picked up automatically:
| Schema.org type | Interface to implement |
|---|---|
| Product | Setono\SyliusSEOPlugin\DataMapper\Product\ProductDataMapperInterface |
| Product group | Setono\SyliusSEOPlugin\DataMapper\ProductGroup\ProductGroupDataMapperInterface |
| Online store | Setono\SyliusSEOPlugin\DataMapper\OnlineStore\OnlineStoreDataMapperInterface |
| Website | Setono\SyliusSEOPlugin\DataMapper\Website\WebsiteDataMapperInterface |
use Setono\SyliusSEOPlugin\DataMapper\Product\ProductDataMapperInterface;
use Spatie\SchemaOrg\Product;
use Sylius\Component\Core\Model\ProductVariantInterface;
final class MpnProductDataMapper implements ProductDataMapperInterface
{
public function map(ProductVariantInterface $productVariant, Product $product): void
{
// enrich the generated Schema.org Product with your own data
$product->mpn($productVariant->getCode());
}
}After each object is added to the graph the plugin dispatches an event you can subscribe to in order to extend or replace the generated data:
Setono\SyliusSEOPlugin\Event\OnlineStoreAddedToGraphSetono\SyliusSEOPlugin\Event\ProductAddedToGraphSetono\SyliusSEOPlugin\Event\ProductGroupAddedToGraphSetono\SyliusSEOPlugin\Event\WebsiteAddedToGraph
composer install
composer phpunit # run the unit tests
composer analyse # run static analysis
composer check-style # check the coding standardSee the test application in tests/Application for a runnable Sylius store with the plugin installed.
This plugin is released under the MIT License.