Linkhandler ab TYPO3 8: einfach News, Jobs etc. verlinken
Der Linkhandler ermöglicht es ab der TYPO3 8.7 LTS verschiedenste Datensätze direkt im Text zu verlinken. Doch was hat es mit dem Linkhandler auf sich und wie lässt er sich einrichten?
TYPO3 ist ein sehr flexibles Content Management System. Kundenindividuell lassen sich Datensätze anfertigen und verwalten, wie beispielsweise News, Jobs, Ansprechpartner oder Termine. Diese können dann u.a. als sortierte Liste und sogar als Detailansicht als einzelne Seite angezeigt werden. Doch wie können Redakteure diese Seiten im Text, genauer gesagt im Rich Text Editor, verlinken?
Der Linkhandler für Redakteure
Nehmen wir als Beispiel die News. Sie erstellen im TYPO3 einen neuen Artikel. Die neuesten drei Artikel werden auf Ihrer Startseite dargestellt. Zusätzlich gibt es ein Archiv mit allen Artikeln aufgelistet. Für jede News gibt es eine sogenannte Detailansicht. Das heißt eine separate Seite im TYPO3, wo alle relevanten Informationen zu einem News-Artikel dargestellt werden.
Nun kann es sein, dass Sie einen Text schreiben oder Bild im TYPO3 einfügen, welches auf einen Artikel verlinken soll. Betätigt ein Nutzer diesen Link, gelangt er automatisch zur Detailansicht. Nun können Sie die URL direkt im RTE eintragen. Komfortabler und nachhaltiger ist es jedoch auf den Datensatz zu verlinken. Wie das geht, zeigt das folgende Video.
Dieses Video wird über eine externe Plattform (YouTube) gehostet. Das Laden bedarf der Zustimmung unserer Datenschutzbestimmungen.
Ändert sich bei der bisherigen Vorgehensweise die URL des Artikels beispielsweise dadurch, weil Ihnen noch ein Rechtschreibfehler im Titel aufgefallen ist, so ist der bisherige Link nicht mehr gültig. Nutzen Sie besser die Methode aus dem Video. Haben Sie so den Datensatz verlinkt, aktualisiert sich dieser Link automatisch und die Verknüpfung bleibt erhalten.
Im Folgenden zeigen wir den Integratoren, wie Sie diese Funktion den Redakteuren bereitstellen können. Dabei beziehen wir uns auf die Kernfunktionalität ab TYPO3 8.6. Vorher bis inklusive der TYPO3 7.6 LTS war der Linkhandler eine separate Erweiterung.
Backend: Linkhandler im TSconfig
Um einen Linkhandler den Redakteur im Backend zur Verfügung zu stellen, werden einige Zeilen pageTSconfig benötigt, genauer gesagt im TCEMAIN
. In dem Codebeispiel haben wir 3 neue Verlinkungsmöglichkeiten geschaffen.
TCEMAIN { linkHandler { tx_news { handler = TYPO3\CMS\Recordlist\LinkHandler\RecordLinkHandler label = LLL:EXT:cs_templates/Resources/Private/Language/locallang_db.xlf:TCEMAIN.linkHandler.tx_news configuration { table = tx_news_domain_model_news storagePid = 86 hidePageTree = 1 } scanAfter = page } tx_csevents { handler = TYPO3\CMS\Recordlist\LinkHandler\RecordLinkHandler label = LLL:EXT:cs_templates/Resources/Private/Language/locallang_db.xlf:TCEMAIN.linkHandler.tx_csevents configuration { table = tx_news_domain_model_news storagePid = 87 hidePageTree = 1 } scanAfter = page displayAfter = tx_news } tx_cshosts { handler = TYPO3\CMS\Recordlist\LinkHandler\RecordLinkHandler label = LLL:EXT:cs_templates/Resources/Private/Language/locallang_db.xlf:TCEMAIN.linkHandler.tx_cshosts configuration { table = tx_cshosts_domain_model_host hidePageTree = 0 } scanAfter = page displayAfter = tx_csevents } } }
Nachdem der Cache geleert wurde, sehen wir im CKEditor direkt die neuen Tabs.
Achtung: Wenn Sie das pageTSconfig mit registerPageTSConfigFile
und über die Auswahl in den Seiteneinstellungen hinzugefügt haben, werden die Links im Frontend nicht gerendert, sondern einfach nicht als Links ausgegeben. Das rührt daher, dass diese Dateien im Frontend noch nicht mit geladen werden. Daher müssen diese Einstellungen entweder direkt in die Seiteneigenschaften geschrieben oder die Datei an der selben Stellen inkludiert werden.
Frontend: Linkhandler im TypoScript
Nun muss TYPO3 noch gesagt werden, wie es mit diesen Verlinkungen umgehen soll. Anders ausgedrückt, wie soll der Link im Frontend gerendert werden. Die entsprechende Konfiguration findet unter config.recordLinks
im TypoScript statt.
config.recordLinks { tx_news { typolink { parameter = {$plugin.tx_news.settings.defaultDetailPid} additionalParams.data = field:uid additionalParams.wrap = &tx_news_pi1[controller]=News&tx_news_pi1[action]=detail&tx_news_pi1[news]=| useCacheHash = 1 ATagParams.data = parameters:allParams target.data = parameters:target title.data = parameters:title extTarget = _blank extTarget.override.data = parameters:target } forceLink = 1 } tx_csevents < .tx_news tx_csevents { typolink { parameter = {$plugin.tx_csevents.settings.detailPid} } forceLink = 1 } tx_cshosts < .tx_news tx_cshosts { typolink { parameter = {$plugin.tx_cshosts_pi1.settings.detailPid} additionalParams.wrap = &tx_cshosts_pi1[controller]=Host&tx_cshosts_pi1[action]=show&tx_cshosts_pi1[host]=| } } }
Wenn der Linkhandler einmal konfiguriert wurde, dann lassen sich die Einstellungen leicht für andere Erweiterungen übernehmen.
Achtung: Die Angaben wie title.data
und ATagParams.data
sind wichtig, ansonsten werden nicht alle Einstellungen aus dem RTE übernommen.
Detailseiten nach Kategorien
Ein Sonderfall ist, wenn es für unterschiedliche Kategorien auch unterschiedliche Detailseiten gibt. Sind die Detailseiten am Kategorie-Datensatz definiert, kann folgendes TypoScript genutzt werden, um je Kategorie, eine andere Verlinkung zu erzeugen.
config.recordLinks.tx_news.typolink.parameter.stdWrap.cObject = CONTENT config.recordLinks.tx_news.typolink.parameter.stdWrap.cObject { table = sys_category select { pidInList = {$plugin.tx_news.settings.startingpoint} selectFields = sys_category.single_pid AS detailPid join = sys_category_record_mm ON sys_category_record_mm.uid_local = sys_category.uid where = sys_category_record_mm.uid_foreign = {field:uid} where.insertData = 1 max = 1 } renderObj = TEXT renderObj.field = detailPid }
Das TypoScript wurde aus dem Kommentar von Micha zu diesem Blog-Beitrag übernommen (s. unten). Wir empfehlen generell nur eine Detailseite pro Domain zu verwenden, da es ansonsten auf jeder Detailseite möglich ist, jede News darzustellen, was zu doppelten Inhalten führen kann. Das hier abgebildete Beispiel geht auch nur, wenn die News-Artikel jeweils nur einer Kategorie zugewiesen wurden.
Vorsicht bei weiteren Attributen
Derzeit werden weitere Attribute wie Targets und Klassen beim Fluid-TypoLinkViewHelper und der Verlinkung von Datensätzen ignoriert. Tickets gibt es dazu schon einige auf Forge, u.a.: https://forge.typo3.org/issues/81620. Mit den obigen Einstellungen werden diese Attribute nur für Links aus dem RTE übernommen.
Ausblick
Der Linkhandler funktioniert so auch in der neuen TYPO3 9.0. Weitere Videos rund um das Thema TYPO3 und mehr finden Sie auch auf unserem YouTube-Kanal.
Falls Sie Fragen oder Anmerkungen zum Beitrag haben, schreiben Sie uns gerne einen Kommentar oder nehmen Sie mit uns Kontakt auf.
Kommentar von Matthias
Danke für das Tutorial. Eine Frage dazu: es gibt ja die Möglichkeit, die Detail Seite der News über die zugehörigen Kategorien anzugeben, also nicht eine einzige sondern mehrere Detailseiten zu haben. Kann der Linkhandler damit umgehen?
Kommentar von Marc
Hallo Matthias, gerne. Ja du kannst den typolink-Parameter über stdWrap soweit modifizieren wie du magst. Also bestenfalls sind die Detail-Seiten bei den Kategorien hinterlegt und je nachdem werden sie ausgegeben. Oder du gehst über das CASE-Objekt oder nimmst eine UserFunc. Also theoretischerweise ist alles möglich. Prinzipiell würde ich jedoch immer eine Detail-Seite für alle News bevorzugen, um doppelte Inhalte etc. zu vermeiden. Viele Grüße, Marc
Kommentar von Michael
Ich hab das mit den Newskategorien so gelöst:
parameter.stdWrap.cObject = CONTENT
parameter.stdWrap.cObject {
table = sys_category
select {
pidInList = 71
selectFields = sys_category.single_pid AS detailPid
join = sys_category_record_mm ON sys_category_record_mm.uid_local = sys_category.uid
where = sys_category_record_mm.uid_foreign = {field:uid}
where.insertData = 1
andWhere.stdWrap.intVal = 1
andWhere.stdWrap.stripHtml = 1
}
renderObj = TEXT
renderObj.field = detailPid
renderObj.wrap = |
}
Kommentar von Marc
Hallo Michael, danke für dein Kommentar. Das ist ein guter Lösungsansatz. Viele Grüße, Marc
Kommentar von Matthias
Hallo Marc,
wenn man die Detail Seite über die Kategorien vergibt, hat man ja kein Problem mit doppeltem Content (weil es auch dann pro News immer nur eine Detail Seite gibt). Die Lösung von Michael würde ich gerne ausprobieren – kann man die irgendwie formatiert bekommen?
Danke und Gruß,
Matthias
Kommentar von Marc
Hallo Matthias, ich habe das Codebeispiel von Micha in den Beitrag übernommen inkl. Anmerkungen. Viele Grüße, Marc
Kommentar von Matthias
Die Lösung von Michael funktioniert – allerdings nur, wenn pro news genau eine Kategorie vergeben wurde. Hat eine news mehrere Kategorien, klappt die Verlinkung nicht mehr.
Kommentar von Marc
Hallo Matthias, da kann ich dir nur zustimmen. Es ist bei einigen Projekten schwer zu realisieren, aber prinzipiell raten wir auch aufgrund dessen zu einer Detailseite für alle News. Viele Grüße, Marc
Kommentar von Matthias
Hallo Marc,
man kann bei dem select noch ein max = 1 hinzufügen, dann klappt es auch, wenn die news mehrere Kategorien hat.
Matthias
Kommentar von Marc
Hallo Matthias, der erste gewinnt also 🙂 Ich füge das mal noch hinzu. Viele Grüße, Marc
Kommentar von Martin
Danke für das Tutorial. Funktioniert super mit dem RTE. Leider funktioniert es nicht bei anderen Linkfeldern z.B. beim header_link oder bei der Verlinkung von Bildern.
Es wird zwar in der Datenbank der der richtige Link abgelegt: t3://record?identifier=…. Aber der Link um die Überschrift wird ignoriert. Die TCEMAIN-Anweisungen habe ich direkt in das Seiten-TSconfig geschrieben, daran kann es eigentlich nicht liegen.
Eine debug-Ausgabe im Fluid gibt mir auch den entsprechenden string aus (t3://record?identifier=..) aber er lässt sich nicht mit f:link.typolink parameter=“{link}“ rendern.
Gibt es dazu von euch Erfahrungswerte?
Danke und schöne Grüße
Martin
Kommentar von Marc
Hallo Martin, ich hoffe deine Frage richtig verstanden zu haben. Dein pageTSconfig scheint zu greifen, da du ja im Backend die Verlinkung vornehmen kannst. Wichtig ist wie beschrieben und im Screenshot gezeigt, dass das pageTSconfig direkt über über das Seiten-TSconfig-Feld eingbunden wird. Ich vermute mal, das sorgt auch bei dir für den Fehler. Ansonsten schau mal, dass das TypoScript richtig eingebunden wird, also config.recordLinks. In der TYPO3 8 kannst du zudem in der typo3/sysext/frontend/Classes/Typolink/DatabaseRecordLinkBuilder.php debuggen, ob dein TypoScript und dein pageTSconfig greift. Ich hoffe, dass ich dir weiterhelfen konnte. Viele Grüße, Marc
Kommentar von Martin
Hallo Marc, danke für die Rückmeldung. Das pageTSconfig war schon richtig eingebunden, das war nicht das Problem. Beide Scripte (TypoScript und pageTSconfig) waren korrekt eingebunden und haben gegriffen. Zwei Tage im ContentObjectRenderer und im DatabaseRecordLinkBuilder haben mir gezeigt, das die parameter in der Konfiguration falsch interpretiert werden. Es wird ein array statt einem String gebildet. Nachdem ich das gefunden hatte konnte ich das auch beheben. Das ganze war in der TYPO3 Version 8.7.11. In der neuen Version 8.7.12 ist der Bug behoben: https://review.typo3.org/#/c/56152/ Es funktioniert nun und euer Tutorial hat dabei geholfen. Danke. Das ganze nur zu deiner Information. Herzliche Grüße, Martin
Kommentar von Marc
Hallo Martin, vielen Dank nochmal für deine Rückmeldung. Viele Grüße, Marc
Kommentar von Josef Kochmann
Hallo, vielen Dank für den Beitrag.
Ich möchte Dich fragen, ob das auch für 7.6.25 LTS funktioniert?
Danke im Voraus!
Kommentar von Marc
Hallo Josef, wir haben für TYPO3 7 diese Erweiterung genutzt https://github.com/cobwebch/linkhandler. Im Core ist der Linkhandler ab TYPO3 8.6 verfügbar https://docs.typo3.org/typo3cms/extensions/core/8.7/Changelog/8.6/Feature-79626-IntegrateRecordLinkHandler.html. Viele Grüße, Marc
Kommentar von Karina Kern
Hallo!
Danke für die sehr hilfreiche Anleitung!!
Mir ist nur aufgefallen, dass sich beim Code für die Detailseiten nach Kategorien ein (Tipp?)Fehler eingeschlichen hat. Es steht zwei mal „paremeter“ statt „parameter“, deswegen hat es bei mir nicht gleich funktioniert 😉
Vielen Dank und liebe Grüße,
Karina
Kommentar von Marc
Hallo Karina, ich weiß gar nicht wovon du sprichst. Bei mir im Browser sieht alles gut aus *hust*. Vielen Dank für den Tipp. Liebe Grüße
Kommentar von Armin
Hallo, danke für das Tutorial. Geht das ganze nur mit der News Extension oder würde das auch mit einer Custom Extension so funktionieren? Vorausgesetzt man passt die Datenbank, Controller-Name, etc. an.
Danke vorab.
Armin
Kommentar von Marc
Hallo,
genau, die news-Erweiterung wurde hier nur als Beipsiel genommen.
Viele Grüße, Marc
Kommentar von Armin
Vielen Dank, habt ihr auch ein Beispiel wie das Link Parsing ohne Typoscript funktioniert? Also sprich einen eigenen RecordLinkHandler basteln oder diesen erweitern?
Kommentar von Marc
Hallo Armin, bitte schau dir mal unsere Beispiele genauer an. Wir nutzen hier nicht nur die news, sondern auch Eigenentwicklungen. Ich weiß nicht genau worauf deine Frage abzielt. Der RecordLinkHandler dient dazu verschiedenste Records/Datensätze im TYPO3 zu verlinken. Die Konfiguration für das Backend erfolgt im pageTSconfig, sodass der Redakteur die Datensätze z.B. im RTE verlinken kann. Hier kannst du auch einen eigenen Handler angeben. Die Konfiguration für das Frontend erfolgt im TypoScript. Das Rendern des Links erfolgt mit typolink. Die Funktion steht sowohl im TypoScript als auch im PHP zur Verfügung. Einen eigenen RecordLinkHandler zu schreiben war bisher nicht notwendig. Ich würde mich dann an der Klasse TYPO3\CMS\Recordlist\LinkHandler\RecordLinkHandler orientieren. Ich hoffe, dass ich dir weiterhelfen konnte. Viele Grüße, Marc
Kommentar von Bernd
Hallo Marc,
ich hab den LinkHandler für tx_news erweitert. Man kann jetzt Links auf News mit verschiedenen DetailPid setzten ohne das die Detailsseiten mit den Kategorien verknüpft sind. Vorausgesetzt die News Kategorien liegen in einem SysFolder und es gibt nur jede News hat nur eine Kategorie aus diesem SysFolder. Der Nachteil meiner Lösung ist, das man die DetailPid im Typoscript in der Case Anweisung angeben muss.
recordLinks {
tx_news {
typolink {
parameter {
stdWrap {
cObject = CONTENT
cObject {
table = sys_category
select {
pidInList = 4
max = 1
selectFields = sys_category.uid AS categoryUid
join = sys_category_record_mm ON sys_category_record_mm.uid_local = sys_category.uid
where = sys_category_record_mm.tablenames=’tx_news_domain_model_news‘ AND sys_category_record_mm.uid_foreign = { field: uid }
where.insertData = 1
where.stdWrap.intVal = 1
where.stdWrap.stripHtml = 1
}
renderObj = COA
renderObj {
10 = CASE
10 {
key.field = categoryUid
9 = TEXT
9.value = DetailPid_1
10 = TEXT
10.value = DetailPid_2
18 = TEXT
18.value = DetailPid_3
default = TEXT
default.value = DetailPid_default
}
10.wrap = |
}
}
}
}
additionalParams.data = field:uid
additionalParams.wrap = &tx_news_pi1[controller]=News&tx_news_pi1[action]=detail&tx_news_pi1[news]=|
useCacheHash = 1
ATagParams.data = parameters:allParams
target.data = parameters:target
title.data = parameters:title
extTarget = _blank
extTarget.override.data = parameters:target
forceLink = 0
}
}
}
}
Kommentar von Marc
Hallo Bernd, vielen Dank für deinen Kommentar.
Kommentar von Henri
Juhuu. Für pid = 0 bitte aufpassen. https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/Functions/Select.html?highlight=root#pidinlist
Kommentar von Marc
Danke Henri für den Hinweis.
Kommentar von Boris
News Detailseiten nach Kategorien in Übersetzungen
funktioniert leider nicht auf Anhieb in anderen Sprachen. Im Fall Typo3 9.5 und „fallbackType: strict“ müssen die Kategorien (mit den Detailseiten) übersetzt sein. Ein einfaches zuweisen „All Languages“ reicht hier nicht aus und die Links werden nicht gerendert in der Übersetzung.
Kommentar von Marc
Hallo Boris, vielen Dank für den Hinweis.
Kommentar von Markus
Hat jemand eine Idee wie man es löst wenn eine News mehrere Kategorien hat und der Link zur Detailseite der ersten Kategorie gehen soll?
Kommentar von Marc
Hallo Markus,
unser Beispiel im Beitrag funktioniert für dich nicht?
Kommentar von Markus Dübbert
Bei mir sind die Anführungszeichen falsch.
In dieser Zeile sind sie richtig:
where = sys_category_record_mm.tablenames=’tx_news_domain_model_news‘ AND sys_category_record_mm.uid_foreign = { field: uid }
Kommentar von Marc
Hallo Markus, danke für deinen Beitrag.
Kommentar von Markus Dübbert
Weiss jemand, warum der Linkhandler zwar funktioniert, aber nicht die unter Routing angegebenen Urls nutzt?
Also:
../detail?tx_news_pi1%5Bnews%5D=840&cHash=fa36228f62badad1a0026ee079cdba48
statt
../detail/News/my-news-title/
wie Links, die mit dem news plugin erstellt werden.
Kommentar von Marc
Hallo Markus,
wir haben das Problem nicht. Schau mal, ob du die TypoScript-Einstellung features.skipDefaultArguments nutzt https://docs.typo3.org/m/typo3/book-extbasefluid/master/en-us/b-ExtbaseReference/Index.html und überprüfe die site-Einstellungen für den Route-Enhancer.
Wenn du den Link bspw. mit Fluid setzt, funktioniert dann die Umwandlung in eine sprechende URL? Wir können uns auch gerne noch im Slack dazu austauschen.
Viele Grüße,
Marc
Kommentar von Udo Klingner
Weiss jemand, wie man auch das Feld ‚CSS-Klasse‘ mit aktiviert? Das fehlt irgendwie…
Kommentar von Marc
Hallo Udo,
schau mal hier https://usetypo3.com/ckeditor.html. Dort ist es unter „Adding custom Link Classes“ gut beschrieben.
Viele Grüße,
Marc
Kommentar von David
Was wirklich noch fehlt, ist die Möglichkeit, die Sprachen auf default einzuschränken. Wenn ich eine News, ein Produkt, irgendeinen mehrsprachigen Record verlinke, möchte / muss ich ihn in der Default-Sprache verlinken, um Duplicate Content zu vermeiden. Früher ging das mit
additionalSearchQueries.tx_news_domain_model_news = AND tx_news_domain_model_news.sys_language_uid=0
Ausführlicher beschrieben findet sich das Problem hier, auf einen alten Linkhandler bezogen, aber vergleichbares Szenario:
https://github.com/cobwebch/linkhandler/issues/40
Kommentar von Marc
Hallo David,
danke für deinen Hinweis. Eventuell würde es helfen dazu noch ein Ticket bei https://forge.typo3.org/ anzulegen.
Viele Grüße,
Marc
Kommentar von Andre W.
Funktioniert das auch mit dem UrlLinkHandler?
ich hab das Backend so konfiguriert:
TCEMAIN.linkHandler.youtube {
handler = TYPO3\CMS\Recordlist\LinkHandler\UrlLinkHandler
label = Youtube
configuration {
table = mytest_domain_model_item
}
}
und das Typoscript so:
config {
recordLinks.youtube {
typolink {
wrap=test1|test2
}
}
}
Die Ausgabe im Frontend ist aber immer nur der Standard a href…
Kommentar von Marc
Hallo Andre,
wird dein TypoScript auch an der Stelle geladen? Schau bitte im TypoScript Object Browser mal nach. Funktioniert denn ein anderes TypoScript an der Stelle bzw. ein Beispiel aus dem Blog-Beitrag? Nutze für solche Fragen auch gerne Stack Overflow.
Viele Grüße,
Marc
Kommentar von Alex
Ich hab mit dieser Funktion in TYPO3 10.4 interessante Probleme die ich mir nicht erklären kann.
Die Links werden manchmal im Frontend nicht gerendert. Dann hab ich rausgefunden:
Das Problem tritt auf wenn im Backend der Cache gelöscht wird oder ungültig wird, aber im Frontend vom TYPO3 Redakteur kein Seitenrefresh erfolgt. Der erste externe User der dann die Seite anfordert, der hat keine gerenderten LInks mehr.
Ich kann das Problem nur lösen, indem ich die TSCONFIG in der ext_localconf.php UND der ext_tables.php einfüge.
Das TYPOSCRIPT reicht in der ext_tables.php oder der Config/TCA/Overrides/[table].php.
Kommentar von Marc
Hallo Alex,
danke für deinen Beitrag. Den Fehler hatte ich so noch nicht. Du findest aber sicherlich Hilfe bei Stack Overflow oder im TYPO3 Slack Channel.
Viele Grüße,
Marc
PS: Schau nochmal, ob du das Page TsConfig so eingebunden hast, wie hier im Beitrag beschrieben.
Kommentar von Armin
Vielen Dank für die Erweiterung.
Kann man sich auch bei den externen Links das Feld „rel-Attribut“ anzeigen lassen? Das man dort ein Wert eintragen kann.
Kommentar von Marc
Hallo Armin, da kann ich dir auf die Schnelle nicht helfen. Evtentuell fragst du mal im TYPO3 Slack Channel oder bei Stackoverflow. Viele Grüße, Marc