Select Page

1. Vorarbeiten und Ordnerstruktur erstellen

Grundlegende Ordnerstruktur

  • Ordner Source im Ordner Private erstellen → Hier kommt die HTML-Vorlage hin
  • Ordner Templates im Ordner Private erstellen mit den Unterordnern:
    • Layouts → Definiert den Rahmen einer Website (Struktur)
    • Pages → Fügen Inhalt in ein Layout ein, mehrere Templates für verschiedene Darstellungen nutzbar (Inhalte)
    • Partials → Kleinere, wiederverwendbare Abschnitte (Wiederverwendbarkeit)

Hinweis: Der Ordner Pages entspricht in der TYPO3-Ordnerstruktur dem, was hier als Templates beschrieben wurde.

Layout-Datei erstellen

Im Ordner Layout die Datei Default.html erstellen:

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
    <f:spaceless>
        <!-- Hier kommt das HTML aus der Source rein -->
        <!-- Gleichbleibende Inhalte, wie Header oder Footer, gehören hier her -->
    </f:spaceless>    
</html>

Page-Template erstellen

Im Ordner Pages die Datei Default.html erstellen (wie oben, nur kommen hier später Inhalte rein). Für verschiedene Pages sind verschiedene Page-Templates möglich.

2. TypoScript-Konfiguration einrichten

Grunddateien erstellen

  • setup.typoscript in Sets im Sitepackage-Ordner neben config.yaml erstellen
  • Ordner TypoScript erstellen
  • Ordner TsConfig erstellen mit Unterordnern Page und User

Basis-TypoScript konfigurieren

Im Ordner TypoScript die Datei page.typoscript erstellen:

page = PAGE
page.10 = TEXT
page.10.value = Text aus dem Sitesetup

In der setup.typoscript importieren:

@import "EXT:klht3sitepackage/Configuration/Sets/klht3sitepackage/TypoScript/*.typoscript"

Durch den Stern werden alle Skripte aus dem Ordner importiert, so kann man den Code modularer gestalten.

3. Layout und Template einbinden und verknüpfen

Page.typoscript anpassen

page = PAGE
page {
    10 = PAGEVIEW
    10 {
        paths {
            100 = EXT:vtklhsitepackage/Resources/Private/Templates/
        }
    }
}

Default.html im Pages-Ordner anpassen

Per ViewHelper das Layout einbinden:

<f:layout name="Default"/>

Layout definieren

In der Default.html im Layout-Ordner muss definiert werden, wo Inhalt hinkommen soll:

<f:render section="Main"/>

Complete Page-Template

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
    <f:layout name="Default" />
    <f:spaceless>
        <f:section name="Main">
            ### Hauptinhalt PAGES ###
        </f:section>
    </f:spaceless>
</html>

4. Metatags und Favicon einrichten

Metaangaben definieren

Metaangaben können als Eigenschaften des page-Objects im page.typoscript definiert werden:

page = PAGE
page {
    meta {
        viewport = width=device-width, initial-scale=1.0
    }
    headerData {
        10 = TEXT
        10.value (
            <link href="{path:EXT:vtklhsitepackage/Resources/Public/img/favicon.png}" rel="icon">
            <link href="{path:EXT:vtklhsitepackage/Resources/Public/img/apple-touch-icon.png}" rel="apple-touch-icon">
        )
        10.insertData = 1
    }
    10 = PAGEVIEW
    10 {
        paths {
            100 = EXT:vtklhsitepackage/Resources/Private/Templates/
        }
    }
}

Titel übernimmt TYPO3, description und keywords laufen über die SEO-Extension, sofern sie genutzt wird.

5. Fonts lokal einbinden

Fonts im Public-Ordner unter fonts speichern und CSS vom Google Font Helper in main.css zu Beginn einfügen.

6. CSS und JavaScript einbinden

Im page-Object im page.typoscript mit includeCSS das CSS einbinden, JavaScript mit includeJSFooter. Minifizierte Dateien mit .disableCompression = 1 ausschließen:

page = PAGE
page {
    meta {
        viewport = width=device-width, initial-scale=1.0
    }
    headerData {
        10 = TEXT
        10.value (
            <link href="{path:EXT:vtklhsitepackage/Resources/Public/img/favicon.png}" rel="icon">
            <link href="{path:EXT:vtklhsitepackage/Resources/Public/img/apple-touch-icon.png}" rel="apple-touch-icon">
        )
        10.insertData = 1
    }
    includeCSS {
        bootstrap = EXT:vtklhsitepackage/Resources/Public/vendor/bootstrap/css/bootstrap.min.css
        bootstrap.disableCompression = 1
        bootstrap-icons = EXT:vtklhsitepackage/Resources/Public/vendor/bootstrap-icons/bootstrap-icons.css
        aos = EXT:vtklhsitepackage/Resources/Public/vendor/aos/aos.css
        swiper = EXT:vtklhsitepackage/Resources/Public/vendor/swiper/swiper-bundle.min.css
        swiper.disableCompression = 1
        glightbox = EXT:vtklhsitepackage/Resources/Public/vendor/glightbox/css/glightbox.min.css
        glightbox.disableCompression = 1
        main = EXT:vtklhsitepackage/Resources/Public/css/main.css
    }
    includeJSFooter {
        bootstrap = EXT:vtklhsitepackage/Resources/Public/vendor/bootstrap/js/bootstrap.bundle.min.js
        bootstrap.disableCompression = 1
        aos = EXT:vtklhsitepackage/Resources/Public/vendor/aos/aos.js
        purecounter = EXT:vtklhsitepackage/Resources/Public/vendor/purecounter/purecounter_vanilla.js
        waypoints = EXT:vtklhsitepackage/Resources/Public/vendor/waypoints/noframework.waypoints.js
        swiper = EXT:vtklhsitepackage/Resources/Public/vendor/swiper/swiper-bundle.min.js
        swiper.disableCompression = 1
        glightbox = EXT:vtklhsitepackage/Resources/Public/vendor/glightbox/js/glightbox.min.js
        glightbox.disableCompression = 1
        imagesloaded = EXT:vtklhsitepackage/Resources/Public/vendor/imagesloaded/imagesloaded.pkgd.min.js
        imagesloaded.disableCompression = 1
        isotope = EXT:vtklhsitepackage/Resources/Public/vendor/isotope-layout/isotope.pkgd.min.js
        isotope.disableCompression = 1
        main = EXT:vtklhsitepackage/Resources/Public/js/main.js
    }
    10 = PAGEVIEW
    10 {
        paths {
            100 = EXT:akoesitepackage/Resources/Private/Templates/
        }
    }
}

7. Inhalte im Template ausgeben

Variables im PAGEVIEW-Object definieren

10 = PAGEVIEW
10 {
    paths {
        100 = EXT:akoesitepackage/Resources/Private/Templates/
    }
    variables {
        content0 = CONTENT
        content0 {
            table = tt_content
            select {
                where = {#colPos} = 0
                orderBy = sorting
            }
        }
    }
}

ViewHelper im Fluid-Template integrieren

<f:section name="Main">
    <f:format.raw>{content0}</f:format.raw>
</f:section>

Es gibt unterschiedliche Notationen, gegebenenfalls in der Dokumentation nachschauen.

8. Rendering der Content-Elemente anpassen

Layout anpassen

  1. Default.html aus vendor/typo3/cms-fluid-styled-content/Resources/Private/Layouts kopieren
  2. Im Sitepackage unter Resources/Private/Extensions/fluid_styled_content/Layouts ablegen
  3. lib.contentElement.typoscript erstellen:
lib.contentElement {
    layoutRootPaths {
        100 = EXT:akoesitepackage/Resources/Private/Extensions/fluid_styled_content/Layouts/
    }
}

9. Backend-Layouts erstellen

Backend-Layout definieren

In TsConfig/Page eine Datei backend_layouts.tsconfig erstellen:

mod.web_layout.BackendLayouts {
    sidebar {
        title = Sidebar right
        config {
            backend_layout {
                colCount = 3
                rowCount = 1
                rows {
                    1 {
                        columns {
                            1 {
                                name = Normal
                                colspan = 2
                                colPos = 0
                            }
                            2 {
                                name = Sidebar
                                colPos = 1
                            }
                        }
                    }
                }
            }
        }
    }
}

Page.tsconfig einbinden

page.tsconfig auf Ebene von setup.typoscript erstellen:

@import "EXT:akoesitepackage/Configuration/Sets/akoesitepackage/TsConfig/Page/*.tsconfig"

Sidebar-Template erstellen

Sidebar.html unter Templates/Pages erstellen:

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
    <f:layout name="Default" />
    <f:spaceless>
        <f:section name="Main">
            <div class="container">
                <div class="row">
                    <div class="col-lg-8">
                        <f:format.raw>{content0}</f:format.raw>
                    </div>
                    <div class="col-lg-4">
                        <f:format.raw>{content1}</f:format.raw>
                    </div>
                </div>
            </div>
        </f:section>
    </f:spaceless>
</html>

Page.typoscript für Sidebar anpassen

variables {
    content0 = CONTENT
    content0 {
        table = tt_content
        select {
            where = {#colPos} = 0
            orderBy = sorting
        }
    }
    content1 < .content0
    content1.select.where = {#colPos} = 1
}

10. Logo mit Link im Header-Bereich

Logo einbinden

Slash im href-Attribut führt immer zur Startseite. Image per ViewHelper einbinden:

<f:image src="EXT:akoesitepackage/Resources/Public/img/logo.svg"/>

Wenn height- oder width-Attribute unerwünscht sind:

<img src="{f:uri.resource(path: 'EXT:akoesitepackage/Resources/Public/img/logo.svg')}" 
     alt="Logo Beschreibung" />

11. Hauptmenü mit dataProcessor

DataProcessing konfigurieren

dataProcessing.typoscript im TypoScript-Ordner erstellen:

page.10.dataProcessing {
    10 = menu
    10 {
        as = mainMenu
        expandAll = 1
        levels = 3
    }
}

Mit <f:debug>{mainMenu}</f:debug> kann im Frontend geprüft werden, ob die Daten übermittelt werden.

MainMenu-Partial erstellen

MainMenu.html im Partials-Ordner erstellen und im Layout mit <f:render partial="MainMenu" arguments="{_all}"/> einfügen:

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
    <f:spaceless>
        <nav id="navmenu" class="navmenu">
            <ul>
                <f:for each="{mainMenu}" as="item">
                    <f:render section="MenuItem" arguments="{_all}"/>
                </f:for>
            </ul>
            <i class="mobile-nav-toggle d-xl-none bi bi-list"></i>
        </nav>

        <a class="btn-getstarted" href="about.html">Get Started</a>
      
        <form id="search-form" name="searchForm" class="search-form ms-4">
            <input type="text" name="searchQuery" placeholder="Search..." class="form-control"/>
            <button type="submit" class="btn"><i class="bi bi-search"></i></button>
        </form>

        <f:section name="MenuItem">
            <li class="{f:if(condition: item.children, then: 'dropdown')}">
                <f:link.typolink parameter="{item.data.uid}" class="{f:if(condition: item.current, then: 'active')}">
                    <f:if condition="{item.children}">
                        <span>
                    </f:if>
                    {item.title}
                    <f:if condition="{item.children}">
                        </span> <i class="bi bi-chevron-down toggle-dropdown"></i>
                    </f:if>
                </f:link.typolink>
                <f:if condition="{item.children}">
                    <ul>
                        <f:for each="{item.children}" as="item">
                            <f:render section="MenuItem" arguments="{_all}"/>
                        </f:for>
                    </ul>
                </f:if>
            </li>
        </f:section>
    </f:spaceless>
</html>

Durch den rekursiven Aufruf der Section können mehrere Ebenen abgebildet werden. Der dataProcessor berücksichtigt die rootPage nicht, daher einen Shortlink anlegen, der auf diese verweist.

12. Metamenü mit dataProcessor

Vorbereitung

  1. Seitentrenner im Seitenbaum als Einstieg erstellen (nicht in Menüs anzeigen, ID notieren)
  2. Darunter die Seiten einfügen

Metamenü konfigurieren

In dataProcessing.typoscript das Menü anlegen:

20 = menu
20 {
    as = metaMenu
    special = directory
    special.value = 17
    levels = 1
}

Mit <f:debug>{metaMenu}</f:debug> im Frontend prüfbar.

Partial und CSS

<ul class="metaMenu">
    <f:for each="{metaMenu}" as="item">
        <li>
            <f:link.typolink parameter="{item.data.uid}" class="{f:if(condition: item.current, then: 'active')}">{item.title}</f:link.typolink>
        </li>
    </f:for>
</ul>
/* MetaMenu */
ul.metaMenu {
    list-style-type: none;
    padding: 0;
}

ul.metaMenu li {
    display: inline-block;
    padding: 0 .1rem;
}

@media (min-width: 400px) {
    ul.metaMenu li {
        padding: 0 .5rem;
    }
}

13. Settings für das Site Set definieren

Settings.definitions.yaml erstellen

categories:
  akoesitepackage:
    label: 'Akoe Sitepackage'
  akoesitepackage.pageUids:
    label: 'Specific Page Uids'
    parent: akoesitepackage
  akoesitepackage.headerButton:
    label: 'Button in main navigation'
    parent: akoesitepackage

settings:
  akoesitepackage.metaMenuUid:
    category: akoesitepackage.pageUids
    label: 'UID of the meta navigation separator'
    type: int
    default: 17
  akoesitepackage.buttonText:
    category: akoesitepackage.headerButton
    label: 'Button text'
    type: string
    default: ''
  akoesitepackage.buttonLink:
    category: akoesitepackage.headerButton
    label: 'Link target'
    type: string
    default: ''

Variable im dataProcessor verwenden

20 = menu
20 {
    as = metaMenu
    special = directory
    special.value = {$akoesitepackage.metaMenuUid}
    levels = 1
}

Settings in Fluid auswerten

<f:if condition="{settings.akoesitepackage.buttonText} && {settings.akoesitepackage.buttonLink}">
    <f:link.typolink class="btn-getstarted" parameter="{settings.akoesitepackage.buttonLink}">
        {settings.akoesitepackage.buttonText}
    </f:link.typolink>
</f:if>

14. Rootline-Navigation (Breadcrumb)

DataProcessor konfigurieren

Im dataProcessing.typoscript ein neues Menü anlegen:

30 = menu
30 {
    as = rootlineMenu
    special = rootline
    special.range = 0|-1
}

Breadcrumb-Partial erstellen

Die Navigation am besten in ein Partial auslagern, auf der Startseite wird diese über den Vergleich von page.id und rootPageId ausgeblendet:

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
    <f:spaceless>
        <f:if condition="{page.id} != {site.rootPageId}">
            <div class="page-title light-background">
                <div class="container">
                    <nav class="breadcrumbs">
                        <ol>
                            <f:for each="{rootlineMenu}" as="item">
                                <li>
                                    <f:if condition="{f:if(condition: item.current, then: 'current')}">
                                        <f:then>{item.title}</f:then>
                                        <f:else>
                                            <f:link.typolink parameter="{item.data.uid}">{item.title}</f:link.typolink>
                                        </f:else>
                                    </f:if>
                                </li>
                            </f:for>
                        </ol>
                    </nav>
                </div>
            </div>
        </f:if>
    </f:spaceless>
</html>

15. Body-Tag erweitern

ID und Klasse hinzufügen

Im page.typoscript:

bodyTagCObject = TEXT
bodyTagCObject.dataWrap = <body id="uid{field:uid}" class="pid{field:pid}">

16. Bildkonfiguration

Ausgabegröße und Lightbox

settings.yaml im Sitepackage:

styles:
  content:
    textmedia:
      maxW: 1296
      maxWInText: 648
      linkWrap:
        lightboxEnabled: true
        lightboxCssClass: glightbox
        width: 1280m
        height: 1280m

Responsive Images

  1. Ordner Partials/Media/Rendering erstellen
  2. Image.html von fluid-styled-content hineinkopieren
  3. Klasse img-fluid ergänzen:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
    <f:media class="image-embed-item img-fluid" file="{file}" width="{dimensions.width}" height="{dimensions.height}" alt="{file.alternative}" title="{file.title}" loading="{settings.media.lazyLoading}" decoding="{settings.media.imageDecoding}" />
</html>
  1. partialRootPaths in lib.contentElement ergänzen:
lib.contentElement {
    layoutRootPaths {
        100 = EXT:akoesitepackage/Resources/Private/Extensions/fluid_styled_content/Layouts/
    }
    partialRootPaths {
        100 = EXT:akoesitepackage/Resources/Private/Extensions/fluid_styled_content/Partials/
    }
}

17. 404-Fehlerseite

  1. 404-Seite anlegen
  2. In den Site Settings das Error Handling einstellen

18. Code im Head-Bereich

HeaderData konfigurieren

page.headerData.typoscript erstellen (Timestamp als Identifier: date +%s in der Shell eingeben):

page.headerData {
    1746805775 = TEXT
    1746805775.value (
        <!-- Hier könnte dein Code stehen -->
    )
}

19. Header-Kommentar ergänzen

Config.typoscript erstellen

Text ganz nach links einrücken, sonst gibt es Darstellungsfehler:

config {
    headerComment (
Seite erstellt von Klaus Hesbacher
Web: https://www.klaus-hesbacher.de
Mail: klaus.heba@web.de
    )
}

20. Nützliches PageTsConfig

TCEFORM.tsconfig

TCEFORM {
    tt_content {
        header_layout {
            altLabels {
                1 = H1 Überschrift
                2 = H2 Überschrift
                3 = H3 Überschrift
                4 = H4 Überschrift
                5 = H5 Überschrift
                6 = H6 Überschrift
            }
        }
        /* Entfernt Elemente aus der Übersicht
        CType {
            removeItems = header
        }
        */
    }
}

TCAMAIN.tsconfig

TCEMAIN {
    table {
        tt_content {
            disableHideAtCopy = 1
            disablePrependAtCopy = 1
        }
        pages {
            disableHideAtCopy = 1
            disablePrependAtCopy = 1
        }
    }
}

TCAdefaults.tsconfig

TCAdefaults {
    pages {
        hidden = 0
    }
}

Achtung: Nur während der Entwicklung so verwenden, im Live-System ergibt es Sinn, dass Seiten erst einmal nicht sichtbar sind.

21. Nützliches UserTsConfig

user.tsconfig im Ordner Configuration

## https://docs.typo3.org/m/typo3/reference-typoscript/13.4/en-us/UserTsconfig/Index.html
options {
    clearCache.pages = 1
    pageTree {
        showPageIdWithTitle = 1
    }
}

22. CSS für Responsive Videos

Video-Embed CSS

/* Responsive Videos mit Fluid Styled Content */
.video-embed {
    position: relative;
    padding-bottom: 56.25%;
    height: 0;
    overflow: hidden;
    margin-bottom: 1.5rem;
}

.video-embed iframe,
.video-embed video {
    position: absolute;
    top: 0;
    left: 0;
    max-width: 100%;
    width: 100% !important;
    height: 100% !important;
}

.ce-center:has(.video-embed) .ce-inner {
    position: relative;
    float: none;
    right: -50%;
}

.ce-left:has(.video-embed) .ce-gallery,
.ce-column:has(.video-embed) {
    float: none;
}

.ce-center:has(.video-embed) .ce-outer {
    position: relative;
    float: none;
    right: 50%;
}

.ce-center:has(figure.video) figure.video {
    display: block;
}