Der Navigation-Manager des Management Servers hat derzeit eine Einschränkung, welche es einem unmöglich macht Navigations-Einträge oder Teilstrukturen mehrfach im Navigationsbaum zu verwenden. Jetzt könnte man sich fragen, warum sollte man dies auch tun wollen. Gerade Themen wie SEO mit den s.g. Duplicate Content und weitere ähnliche Themen könnten ja ein Problem werden. Doch es geht nicht um die Verdopplung der Seiten, sondern nur die mehrfache Verlinkung der selben Seite im Navigationsbaum, an unterschiedlichen sinnvollen Stellen. Doch wie sollte das nun möglich sein, wenn der Navigations-Manager des Management Servers damit nicht klar kommt? Es gibt eine Lösung, welche zwar ein s.g. Workaround ist, jedoch einem genau dieses zuvor beschriebene Verhalten ermöglicht.
Als erstes möchte ich jedoch kurz an einem Bild die Aufgabenstellung erläutern und dannach eine Schritt für Schritt Anleitung aufzeigen.
Die Anforderung lautet, dass folgende Navigationspunkte an anderen Stellen in der Navigationsstruktur nochmals verwendet werden sollen:
Da man die Seiten derzeit nicht mehrfach innerhalb der Navigation verlinken kann, muss man zu einem Workaround greifen.
Die Masterpage (in diesem Fall alle, welche innerhalb der Navigation verwendet werden) müssen um ein Anchor-Element erweitert werden:
welches folgende Einstellungen bekommt:
Es ist jedoch nicht notwendig dieses neue Strukturelement innerhalb der Templates einzusetzen. Denn es wird nur über den Navigations-Manager ausgelesen.
Quelltext der Masterpage (Beispiel):
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Management Server</title> <style> * { font-family: Arial, Helvetica, sans-serif; font-size: 12px; } </style> </head> <body> <ul><%!! Navigation:OutputArea(String:NavigationStructure) !!%></ul> </body> </html><!IoRangeNoRedDotMode><!IoRangeRedDotMode><!-- <%listNavigation%> --><!/IoRangeRedDotMode><!/IoRangeNoRedDotMode>
Als nächstes sind zwei weitere Content-Klasse für den Navigations-Manager nötig. Die Syntax für dieses Beispiel sieht wie folgt aus:
Content-Klasse: Navigation - JumpLevel
<navigation:nextlevel>
Content-Klasse: Navigation - Level 1-10
<%!! Store:Set(linkedContents,Context:CurrentIndex.Page.Elements.GetElement(Str:anchorNavigationCollector).GetLinkedContents()) !!%> <%!! Store:Set(navigationAreaName,String:NavigationCollectorDepth) !!%> <%!! Store:Set(navigationAreaNameLevel,Store:Get(navigationAreaName).Insert(Int:24,Context:CurrentDepth.ToString())) !!%> <reddot:cms> <if> <query valuea="Store:Get(linkedContents).Count" operator="!=" valueb="Int:0"> <foreach itemname="linkedPage" object="Store:Get(linkedContents)"></foreach> <!-- Workaround for "Get the GUID from linked page at anchor" --> <htmltext> <li><b><%!! Context:CurrentIndex.Page.Headline !!%></b><br> <sup>(<%!! Store:Get(linkedPage).Id !!%> / <%!! Store:Get(linkedContents).Count !!%>)</sup> <ul> <%!! Navigation:OutputArea(Store:Get(navigationAreaNameLevel), Bool:False, Store:Get(linkedPage).Id) !!%> </ul> </li></htmltext> </query> <query type="else"> <htmltext> <li><b><%!! Context:CurrentIndex.Page.Headline !!%></b><br> <sup>(<%!! Context:CurrentIndex.Page.Id!!%> / <%!! Store:Get(linkedContents).Count !!%>)</sup> </htmltext> <if> <query valuea="Context:CurrentIndex.HasChildren()" operator="==" valueb="Bool:True"> <htmltext><ul><navigation:nextlevel></ul></htmltext> </query> </if> <htmltext></li></htmltext> </query> </if> </reddot:cms>
Nachdem man die Content-Klassen für den Navigations-Manager angelegt hat, müssen nun mehrere neue Navigationsbereiche eingerichtet werden. Die Anzahl der Navigationsbereiche richtet sich nach der Navigations-Tiefe, welche für den Navigation-Collector genutzt werden sollen:
In diesem Beispiel werden die Navigationsebenen 1, 2 und 3 berücksichtigt. Die erste Ebene (0) wird übersprungen.
Nun sucht man sich die entsprechenden Seiten raus und legt sich diese in Ablage. In unserem Beispiel die Seiten aus der o.g. Liste. Danach wird jede Seite entsprechend verwiesen oder verknpüft. Mit diesem Workaround ist beides möglich:
Wenn man nun eine Seitenvorschau ausführt oder im SmartEdit sich die z.B. die Homepage anschaut, bekommt man dieses Ergebnis:
Es wird wie gewünscht die verwiesenen oder verknüpften Teilbäume des Navigationbaums, in anderen Bereichen der Navigationstruktur angezeigt. Ohne negative Einflüsse auf den Navigations-Manager, werden die Teilbäume dargestellt. Mit diesem Workaround kann man sich die Headline, Id und die URL zu den mehrfach verwendeten Seiten abholen. Mit weiteren Aufwand lässt sich auch weitere Inhalte abholen, jedoch damit wird auch das Rendering der Navigation aufwändiger und dauert länger.
Man muss jedoch beachten, dass der Navigation-Collecotor (in dieser Lösung) die nachfolgende reguläre Navigation ignoriert. Und diese durch die verwiesene bzw. verknüpfte Navigation über den Anchor darstellt. Man kann sich auch einen Mischbetrieb vorstellen, jedoch macht dies dann die Pflege im Projekt noch komplexer. Es ist aber meiner Meinung technisch möglich und durch einen geschickten Projektbau inkl. SmartEdit UX auch bedienbar.
Als letzten Schritt kann man sich nun Gedanken machen, da ja sowohl verknüpfen und verweisen möglich ist, wie man diese Lösung im SmartEdit entsprechend anbietet.
Was passiert nun genau bei diesem Workaround. Dies ist recht schnell erklärt, wenn man sich die Syntax dieser Navigation-Manager Content-Klassen ansieht:
<%!! Store:Set(linkedContents,Context:CurrentIndex.Page.Elements.GetElement(Str:anchorNavigationCollector).GetLinkedContents()) !!%> <%!! Store:Set(navigationAreaName,String:NavigationCollectorDepth) !!%> <%!! Store:Set(navigationAreaNameLevel,Store:Get(navigationAreaName).Insert(Int:24,Context:CurrentDepth.ToString())) !!%> <reddot:cms> <if> <query valuea="Store:Get(linkedContents).Count" operator="!=" valueb="Int:0"> <foreach itemname="linkedPage" object="Store:Get(linkedContents)"></foreach> <!-- Workaround for "Get the GUID from linked page at anchor" --> <htmltext> <li><b><%!! Context:CurrentIndex.Page.Headline !!%></b><br> <sup>(<%!! Store:Get(linkedPage).Id !!%> / <%!! Store:Get(linkedContents).Count !!%>)</sup> <ul> <%!! Navigation:OutputArea(Store:Get(navigationAreaNameLevel), Bool:False, Store:Get(linkedPage).Id) !!%> </ul> </li></htmltext> </query> <query type="else"> <htmltext> <li><b><%!! Context:CurrentIndex.Page.Headline !!%></b><br> <sup>(<%!! Context:CurrentIndex.Page.Id!!%> / <%!! Store:Get(linkedContents).Count !!%>)</sup> </htmltext> <if> <query valuea="Context:CurrentIndex.HasChildren()" operator="==" valueb="Bool:True"> <htmltext><ul><navigation:nextlevel></ul></htmltext> </query> </if> <htmltext></li></htmltext> </query> </if> </reddot:cms>
Damit man jetzt nicht alles nachgebaut werden muss, habe ich das o.g. Beispiel als kleines Demo-Projekt gebaut und exportiert. Einfach diesen Projektexport (16.0.3.339) runterladen und importieren. Dann kann man sich diesen Workaround ansehen und damit rumspielen ;)
... ist Senior Site Reliability Engineer bei der Vodafone GmbH in Düsseldorf. Seit dem Jahr 2007 betreut er zusammen mit seinen Kollegen die OpenText- (vormals RedDot-) Plattform Web Site Management für die deutsche Konzernzentrale.
Er entwickelt Erweiterungen in Form von Plug-Ins und PowerShell Skripten. Seit den Anfängen in 2001 (RedDot CMS 4.0) kennt er sich speziell mit der Arbeitweise und den Funktionen des Management Server aus.