Want a clean, crawlable Shopware 6 store in under an hour? Here’s a fast, do-this-now checklist with copy-paste templates and exact admin paths.
Prereqs (2–3 min)
- Shopware 6 admin access
- At least one Sales Channel with domains set
- If you’re multilingual: languages already created + per-language domains or paths
0–10 min — Baseline checks
- Find the SEO URL templates
Admin → Settings → Shop → SEO. You can scope templates globally or per sales channel and use Twig variables. After edits, you’ll rebuild the SEO index. - Turn on safe redirects (optional but recommended)
Same screen → Forwarding behavior → enable 301 redirect when URLs change.
10–30 min — URL templates that don’t bite
Product detail URLs
Start simple (short, stable) and optionally add structure later.
Option A — Just the name (shortest):
{{ product.translated.name|lower }}
Option B — Category trail + name (great for context):
{% for part in product.categories.sortByPosition().first.breadcrumb|slice(1) %}{{ part|lower }}/{% endfor %}{{ product.translated.name|lower }}
Option C — Name + SKU (helps uniqueness at scale):
{{ product.translated.name|lower }}-{{ product.productNumber|lower }}
Notes
- Variables must be complete (e.g.,
product.translated.name, not justproduct.translated). - Use filters like
|lowerto normalize case. - If you rely on category paths, set a Main/SEO category per product to prevent duplicate paths.
Category URLs
Keep the breadcrumb for nested structure:
{% for part in category.seoBreadcrumb %}{{ part|lower }}/{% endfor %}
You can also use just {{ category.translated.name|lower }} for flat sites.
Landing pages (if you use them)
Default is the landing page’s own URL; you can also reference its fields:
{{ landingPage.url }}
(See available variables in the SEO settings doc.)
Apply & rebuild
After saving templates, rebuild the SEO index so friendly URLs generate:
UI: Settings → System → Caches & Indexes
CLI:
php bin/console dal:refresh:index
30–45 min — Canonical tags that de-duplicate correctly
Product variants → one canonical
For variant families, enable Use single canonical URL for all variants on the product, then pick the variant that should own the URL. This avoids multiple near-identical pages competing. Admin → Products → (open product) → SEO.
Per-sales-channel canonical path & main category
Still on the product’s SEO tab, you can set a canonical path per sales channel and choose its Main category so your product URL always builds off the same category trail.
Global redirects on URL change
If you changed templates, that earlier Forwarding behavior ensures 301s from old to new URLs (no link equity loss).
Advanced: If you need all variants to canonicalize to the parent (even when each has its own detail page), you can implement a “parent canonical” concept or use a plugin built for variant canonicalization.
45–58 min — Hreflang that Google actually understands
Turn on hreflang (core)
Per Sales Channel: Admin → Settings → Sales channel → Hreflang
- Activate Hreflang.
- Select the default domain used as fallback (
x-defaultbehavior). - Make sure each language/country variant has a unique domain or path (e.g.,
example.com/en-us,example.de/de-de).
Follow Google’s hreflang rules
- Every localized version must reference all siblings (including itself).
- Use language-region codes (
en-US,de-DE) when regional content differs. - Provide an
x-defaultfor the global/chooser page.
Quick QA
- View-source on a product page and confirm a set of
<link rel="alternate" hreflang="…">entries for every language, plusx-default. - Run Chrome Lighthouse → SEO audit; it flags missing/invalid hreflang.
58–60 min — Final QA checklist
- Change a product name; confirm a 301 from old → new URL.
- For a variant family, confirm only the chosen variant is canonical.
- On a localized product, confirm the full set of
hreflangalternates exists and match real pages. - Rebuilt SEO index & cleared caches after template changes.
Copy-paste recipe box
Suggested starting templates
Product (flat):
{{ product.translated.name|lower }}
Product (category trail + name):
{% for part in product.categories.sortByPosition().first.breadcrumb|slice(1) %}{{ part|lower }}/{% endfor %}{{ product.translated.name|lower }}
Product (name + SKU):
{{ product.translated.name|lower }}-{{ product.productNumber|lower }}
Category:
{% for part in category.seoBreadcrumb %}{{ part|lower }}/{% endfor %}
Tip: Use Main/SEO category on each product to stabilize URLs if products live in multiple categories.
Common pitfalls (and quick fixes)
- Endless URL churn (dates, prices, stock in URLs). Avoid dynamic fields in templates; these cause ranking instability.
- Duplicate product URLs via multiple categories. Set a Main/SEO category per sales channel.
- Variant duplicates. Use the single canonical for all variants toggle.
- Partial hreflang sets. Each locale must declare all alternates + itself (and
x-defaultif used).
If you want, I can tailor the templates to your exact category tree and languages, or rewrite this into a ready-to-publish post for your agency blog.
