TYPO3: Einfache und komplexe Menüs auf Basis von Fluid

In der Vergangenheit bauten wir Menüs jeglicher Komplexität mit TypoScript. Gott sei Dank sind diese Zeiten vorbei, denn mittlerweile nutzen wir dafür Fluid. Das ist in meinen Augen deutlich einfacher und vor allem übersichtlicher. Mit Hilfe der VHS ViewHelper sind auch komplexere Menüs ohne Probleme umsetzbar.

Einfaches Menü mit 2 Ebenen

Dieser Code erzeugt ein Menü mit zwei Ebenen. Zusätzlich sorgen wir mit expandAll dafür, dass die zweite Ebene immer ausgegeben wird. Das Markup dieses automatisch generierten Menüs kann mit Hilfe von zahlreichen Argumenten angepasst werden.

Mehr dazu kann man auf der Seite der Menu / ListViewHelper von VHS nachlesen.

<v:menu levels="2" expandAll="TRUE" />

Hauptmenü und Submenü separat

Um die erste und zweite Menüebene getrennt voneinander auszugeben, ist folgender Code notwendig.

<nav class="main-menu">
	<v:menu levels="1" />
</nav>

<nav class="sub-menu">
	<v:menu levels="2" entryLevel="1" />
</nav>

Deferred Rendering

Manchmal ist es notwendig das umgebende Markup eines Menüs auf Grundlage des Menüs selbst anzupassen. Um das zu erreichen, benutzen wir das Argument deferred. Damit haben wir vor dem eigentlichen Rendern Zugriff auf das Menü und können beispielsweise abfragen, ob Menüpunkte existieren.

<v:menu deferred="TRUE">
	<div class="widget{f:if(condition: '{menu}', then: ' has-menu')}">
		<f:if condition="{menu}">
			<nav>
				<v:menu.deferred />
			</nav>
		</f:if>
		<f:render partial="widget-content" />
	</div>
</v:menu>

Bild aus Seiteneigenschaften (Media Ressourcen) anzeigen

Hier möchte ich in der zweiten Ebene des Menüs das erste Bild aus den Seiteneigenschaften auslesen und anzeigen. Mit dem automatischen Rendering des Menüs ist dieses Unterfangen meines Wissens nicht umsetzbar. Daher verwende ich hier das tag-basierte Rendering und baue mir mein Markup selbst zusammen.

<!-- Erste Ebene -->
<v:menu>
	<ul>
		<f:for each="{menu}" as="item-lvl-1">
			<li {f:if(condition:'{item-lvl-1.hasSubPages}',then:' class="has-subpages"',else:'')}>
				<a href="{f:uri.page(pageUid:item-lvl-1.uid)}" class="{f:if(condition:'{item-lvl-1.active}',then:' is-current',else:'')}">
					{item-lvl-1.linktext}
				</a>
				
				<!-- Zweite Ebene -->
				<v:menu pageUid="{item-lvl-1.uid}">
					<ul>
						<f:for each="{menu}" as="item-lvl-2">
							<li{f:if(condition:'{item-lvl-2.hasSubPages}',then:' class="has-subpages"',else:'')}>
								<a href="{f:uri.page(pageUid:item-lvl-2.uid)}"{f:if(condition:'{item-lvl-2.active}',then:' class="is-current"',else:'')}>

									<!-- Zeige erstes Bild aus den "Media Ressourcen" -->
									<v:page.resources.fal table="pages" field="media" uid="{item-lvl-2.uid}" as="images">
										{images -> v:iterator.first() -> v:variable.set(name: 'image')}
										<f:if condition="{v:media.exists(then: '1', else: '', file: '{image.url}')}">
											<f:image src="{image.url}" alt="{image.alternative}" width="250c" height="105c" />
										</f:if>
									</v:page.resources.fal>

									<span>{item-lvl-2.linktext}</span>
								</a>
							</li>
						</f:for>
					</ul>
				</v:menu>
			</li>
		</f:for>
	</ul>
</v:menu>

Sebastian Schrama

Sebastian fühlt sich als Frontend-Entwickler in großen Systemen Zuhause. Wohldosiert packt er zur rechten Zeit den Perfektionismus-Hammer aus.