Aus SEO Sicht sollte für gewöhnlich vermieden werden, bestimmten Content unter verschiedenen Adressen (URLs) gleichzeitig zur Verfügung zu stellen (Thematik "Duplicate Content"). Nicht immer ist das allerdings möglich und manchmal muss der gleiche Inhalt dennoch unter verschiedenen Adressen abrufbar sein. Mit zusätzlichen Maßnahmen wie dem Canonical-Tag ist das in Bezug auf Suchmaschinen auch überhaupt kein Problem.

Zur Veranschaulichung verwenden wir das Beispiel einer Rezept-Website mit Kategorien: Hier kann ein Rezept "Pizza" verschiedenen Kategorien wie "herzhaft" und "vegetarisch" zugeordnet sein. Nun die Frage nach der URL-Struktur: Soll die Detailansicht eines Rezeptes unabhängig vom Kategoriepfad erfolgen (nicht schön!) oder unterhalb des Kategoriepfades (schöner!). Die zweite Variante resultiert in schönen URL-Strukturen aber ebenso auch in mehrfachen Detail-Views. Bei der ersten Variante "verliert" man die ausgewählte Kategorie, sofern man diese nicht anderweitig, z.B. via Session merkt. Aber das ist in diesem Beispiel nicht gewünscht.

Wir entscheiden uns also für Variante 2: Jedes Rezept ist unterhalb der ausgewählten Kategorie verfügbar. Um doppelten Content zu vermeiden, wird ein Canonical-Tag generiert, der auf die primäre Detailansicht des Rezepte verweist, losgelöst von der Kategorie. So wird ein angenehmes Navigationsverhalten mit einer logischen URL-Struktur erreicht, zusätzlich werden den Suchmaschinen kurze URLs zu den Detailansichten der Rezepte zur Verfügung gestellt.

TypoScript

page {
    headerData {
        # Canonical tag (multiple recipe detail views)
        9876 = TEXT
        9876 {
            typolink {
                returnLast = url
                forceAbsoluteUrl = 1
                parameter {
                    data = TSFE:id
                    # Different pid for detail view and list view
                    stdWrap {
                        override < plugin.tx_myext.settings.pageUidShow
                        override {
                            if {
                                isTrue.data = GP:tx_myext_pi1|recipe
                            }
                        }
                        stdWrap {
                            override < plugin.tx_myext.settings.pageUidList
                            override {
                            if {
                              isTrue.data = GP:tx_myext_pi1|category
                              isFalse.data = GP:tx_myext_pi1|recipe
                            }
                        }
                    }
                }
                additionalParams {
                    cObject = COA
                    cObject {
                        # Recipe detail
                        10 = TEXT
                        10 {
                            dataWrap = &tx_myext_pi1[recipe]={GP:tx_myext_pi1|recipe}
                            if {
                                isTrue.data = GP:tx_myext_pi1|recipe
                            }
                        }
                        # Category list
                        20 = TEXT
                        20 {
                            dataWrap = &tx_myext_pi1[category]={GP:tx_myext_pi1|category}
                            if {
                                isTrue.data = GP:tx_myext_pi1|category
                                isFalse.data = GP:tx_myext_pi1|recipe
                            }
                        }
                        # Paginator
                        30 = TEXT
                        30 {
                            dataWrap = &tx_myext_pi1[@widget_0][currentPage]={GP:tx_myext_pi1|@widget_0|currentPage}
                            if {
                                isTrue.data = GP:tx_myext_pi1|@widget_0|currentPage 
                            }
                        } 
                    }        
                }
            }
            wrap = <link rel="canonical" href="|" />
        }
    } 
}