Markus Michalski FAQ

Sylius SEO Suite Pro: hreflang

hreflang in Sylius SEO Suite Pro: Welche Seiten zusammengehören, Channel-Gruppen, Regeln für gelistete Sprachen, x-default, Einstellungen im Admin und Ausgabe in Storefront und Shop API.

English Version

Zurück zur Übersicht

Sylius SEO Suite Pro: hreflang

Das Plugin gibt <link rel="alternate" hreflang="..." href="..."> im <head> von Produktseiten, Kategorie-Listings und der Startseite aus. Dieselbe Liste steht in der Shop API im Feld alternates. Eine Seite mit weniger als zwei Alternativen bekommt nichts. Ein Shop mit einer Sprache pro Channel liefert daher genau das aus, was er vorher ausgeliefert hat.

<link rel="alternate" hreflang="de-DE" href="https://shop.example.de/de_DE/products/blaues-sofa">
<link rel="alternate" hreflang="en-US" href="https://shop.example.com/en_US/products/blue-sofa">
<link rel="alternate" hreflang="x-default" href="https://shop.example.de/de_DE/products/blaues-sofa">

Welche Seiten zusammengehören

Channels sind oft eigenständige Shops mit eigenem Sortiment und keine Übersetzungen voneinander. Das Plugin rät deshalb nie über Channels hinweg:

Gruppiert wird nach dem Code des Produkts oder der Kategorie. Für die Startseite zählt die Startseite jedes Gruppen-Channels.

Das Set wird immer aus der Gruppe gebaut, nie aus der Seite, die gerade gerendert wird. Jede Seite eines Sets gibt dieselbe vollständige Liste aus, sich selbst eingeschlossen.

Beispiel: zwei Channels in einer Gruppe

Der Channel shop_de (Hostname shop.example.de, Sprache de_DE) und der Channel shop_en (Hostname shop.example.com, Sprache en_US) haben denselben group_code:

Channel Aktiv hreflang group x-default language
shop_de ja main leer
shop_en ja main leer

Das Produkt wird in beiden Channels verkauft und hat die Slugs blaues-sofa (de_DE) und blue-sofa (en_US). Auf beiden Produktseiten steht dann derselbe Block:

<link rel="alternate" hreflang="de-DE" href="https://shop.example.de/de_DE/products/blaues-sofa">
<link rel="alternate" hreflang="en-US" href="https://shop.example.com/en_US/products/blue-sofa">
<link rel="alternate" hreflang="x-default" href="https://shop.example.de/de_DE/products/blaues-sofa">

Der x-default zeigt auf die Standardsprache des ersten Channels der Gruppe (niedrigste Zeilen-ID), hier shop_de.

Entscheidungsablauf

graph TD
    A["Seite wird gerendert"] --> B{"Channel-Einstellung aktiv?"}
    B -->|"Nein"| Z["Keine hreflang-Links"]
    B -->|"Ja"| C{"Seite ist kanonisch: kein noindex, keine Facette, nicht Seite 2 oder höher, kein abweichender Canonical?"}
    C -->|"Nein"| Z
    C -->|"Ja"| D["Set aufbauen: Sprachen des Channels oder aller aktiven Gruppen-Channels"]
    D --> E["Pro hreflang-Wert eine Seite: Duplikate fallen weg"]
    E --> F{"Ist die Seite selbst im Set?"}
    F -->|"Nein"| Z
    F -->|"Ja"| G{"Genug Alternativen und genug verschiedene URLs?"}
    G -->|"Nein"| Z
    G -->|"Ja"| H["x-default bestimmen und anhängen"]
    H --> I["Alternates im head und in der Shop API ausgeben"]

Regeln: wann eine Sprache gelistet wird

Eine Seite muss Teil ihres eigenen Sets sein (Selbstreferenz). Fehlt ihr eigener Eintrag, etwa weil sie noindex ist oder ihr Wert vergeben war, werden gar keine Alternativen ausgegeben, auch nicht für die übrigen Sprachen.

x-default

Es gibt genau einen x-default pro Set. Er wird so bestimmt:

  1. Der Reihe nach wird jeder Channel der Gruppe gefragt, beginnend mit der niedrigsten Zeilen-ID.
  2. Hat der Channel eine x-default-Sprache eingestellt, zählt die Seite in dieser Sprache. Sie darf auch zu einem anderen Channel der Gruppe gehören (das Formular akzeptiert jede), die Seite des eigenen Channels hat Vorrang.
  3. Ist keine Sprache eingestellt, zählt die Standardsprache des Channels.
  4. Gibt es diese Seite nicht, wird der nächste Channel gefragt.
  5. Gibt es für keinen Channel eine passende Seite, wird die erste Alternative als x-default genommen.

Entscheidung bei Duplikat-Werten

Situation Format Ergebnis
Zwei Channels einer Gruppe haben de_DE beliebig Der Channel mit der niedrigeren Zeilen-ID behält de-DE, der andere fällt heraus. Speichern im Admin wird verweigert.
Ein Channel hat de_DE, ein anderer de_AT language-region Zwei Werte de-DE und de-AT, alles in Ordnung
Ein Channel hat de_DE, ein anderer de_AT language Beide ergeben de: Konflikt wie oben

Einstellungen

Zwei Schlüssel unter mmd_sylius_seo_suite_pro.hreflang:

Einstellung Standard Beschreibung
hreflang.format language-region Schreibweise des Werts: language-region macht aus de_DE den Wert de-DE, language behält nur die Sprache (de)
hreflang.min_alternates 2 Eine Seite bekommt hreflang-Links nur, wenn ihr Set mindestens so viele Alternativen hat (x-default nicht mitgezählt). Mindestens 1.
# config/packages/mmd_sylius_seo_suite_pro.yaml
mmd_sylius_seo_suite_pro:
    hreflang:
        format: language-region
        min_alternates: 2

Mehr dazu unter Konfiguration.

Einstellungen im Admin

Öffne SEO Suite Pro > Schaltfläche hreflang. Dort gibt es eine optionale Zeile pro Channel, ein Channel ohne Zeile verwendet die Standardwerte (hreflang an, keine Gruppe, Standardsprache des Channels als x-default). Es gibt keinen eigenen Seitenleisten-Eintrag, über Zurück zu SEO Suite Pro kommst Du zurück.

Feld Standard Beschreibung
Channel Eine Zeile pro Channel, jeder Channel nur einmal
Output hreflang links an Aus: Der Channel gibt keine Links aus und wird auch von den anderen Channels seiner Gruppe nicht verlinkt
hreflang group leer Optionaler Code aus Kleinbuchstaben, Ziffern, - und _, beginnend mit Buchstabe oder Ziffer, höchstens 64 Zeichen. Gleicher Code bedeutet, dass die Channels Alternativen voneinander sind.
x-default language leer Sprache für Besucher ohne passende Sprache. Muss zum Channel (oder in einer Gruppe zu einem Channel der Gruppe) gehören. Leer bedeutet die Standardsprache des Channels. In einer Gruppe zählt die Einstellung des ersten Channels (niedrigste Zeile).

Beim Speichern prüft ValidHreflangSettings:

Die Priorität in einer Gruppe ist die ID der Zeile. Die niedrigste ID gewinnt bei Duplikaten und bestimmt den x-default. Eine neu angelegte Zeile hat immer die höchste ID und steht damit am Ende.

Eigene Seitentypen

Wer eigene Seitentypen (zum Beispiel Landingpages) mit hreflang versehen will, implementiert Mmd\SyliusSeoSuiteProPlugin\Hreflang\HreflangAlternatesProviderInterface. Der Provider sagt nur, in welchen Sprachen eines Channels eine Seite existiert. Gruppierung, Duplikate, x-default und Host übernimmt das Plugin. Die Details stehen unter Erweitern. Eingebaut sind Produkt, Kategorie und Startseite.

Storefront und Shop API

Im Storefront rendert das Template die Links für jeden Eintrag von seo.alternates. Das gilt für Produktseiten, Kategorie-Listings und die Startseite.

Die Shop API liefert dieselbe Liste im Feld alternates der Seo-Ressource, gebaut vom selben Service:

Beide Pfade liegen unter dem API-Präfix Deines Shops (bei Sylius standardmäßig /api/v2). Das Feld ist eine Liste aus {hreflang, href}, leer, wenn die Seite keine Alternativen bekommt:

{
  "alternates": [
    { "hreflang": "de-DE", "href": "https://shop.example.de/de_DE/products/blaues-sofa" },
    { "hreflang": "en-US", "href": "https://shop.example.com/en_US/products/blue-sofa" },
    { "hreflang": "x-default", "href": "https://shop.example.de/de_DE/products/blaues-sofa" }
  ]
}

Die URLs verwenden die Hostnamen der Channels und das Schema der API-Anfrage. Ein Headless-Frontend auf einem anderen Host ordnet sie selbst zu. Für die Startseite gibt es keinen API-Endpunkt, ihre Alternativen rendert nur Twig. Mehr zur API steht unter Shop API.

Kosten

Die Einstellungen aller Channels werden mit einer Abfrage pro Request gelesen, ein weiteres Query holt die Übersetzungen der Seite, und alle Channels mit Locales und Menü-Kategorie kommen in einer einzigen Abfrage. Weder die Zahl der Sprachen noch die Zahl der Channels einer Gruppe erzeugt zusätzliche Abfragen. Fehlt die Tabelle (Migration noch nicht gelaufen), gelten die Standardwerte, und es wird einmalig eine Warnung geloggt. Schlägt der Aufbau der Alternativen fehl, wird die Seite ohne Alternativen gerendert, nie mit einem Fehler.

Weitere Hilfe: Fehlerbehebung.