Seitentemplate mit Typo3 10.4

Aus Debacher-Wiki
Zur Navigation springenZur Suche springen

Im Web findet man an vielen Stellen vorgefertigte Templates aus HTML und CSS, die man für eigene Projekte nutzen kann. Eine Recherche mit den Stichworten free css template führt schnell zu einer Reihe von Ergebnissen. Unter https://cms-1.org/dokumentation/cmsms-templates/freie-templates.html findet sich eine Übersicht über mehrere derartige Angebote.

Eine schöne Quelle für ein funktionsfähiges System ist unter https://www.bootstrap-package.com/de/ zu finden.

Nach meinen Erfahrungen mit Typo3 ist es aber sinnvoll auf Extensions möglichst zu verzichten, die nicht zu Typo3 gehören. Zu oft habe ich schon erlebt, dass eine für meine Konfiguration wichtige Erweiterung nicht mehr weiter gepflegt wird. Ganz ohne fremde Extension komme ich aber auch nicht aus, momentan sind die gridelements die Extension von der meine Layouts abhängen.

Der folgende Text beschreibt den Aufbau meiner Seiten, wobei ich dafür noch auf Bootstrap3 setze, aus Kompatibilitätsgründen mit den vorhandenen Installationen.

Die Vorlage

Die folgende Beschreibung geht von einem selbst erstellten Template auf Basis von Twitter Bootstrap aus, die folgendes Aussehen hat.

Bildschirmfoto von 2020-11-10 13-10-49.png

Die Farben folgen keinen künstlerischen Ansprüchen, sondern sollen nur das Auffinden der einzelnen Elemente in der CSS-Datei erleichtern und damit auch die individuelle Anpassung.

Alle individuellen Dateien befinden sich im Verzeichnis nettemplate unterhalb von fileadmin. Das hat den Hintergrund, dass ich das Layout auch als Distribution anbieten möchte und dabei gibt es die Möglichkeit bei der Installation Dateien in einen Unterordner von fileadmin kopieren zu lassen, der den gleichen Namen hat wie die Distribution. In diesem Bereich hat man auch vom Backend aus einfachen Zugriff auf die Dateien, ohne unnötig die Zugriffspfade erweitern zu müssen.

Das Paket ist im TER unter https://typo3.org/extensions/repository/view/nettemplate herunter ladbar.

Ich habe möglichst viele Dateien in das Verzeichnis fileadmin/nettemplate gelegt, damit sie bequem über die Funktion Dateiliste editierbar werden. Dazu muss man die Dateien in der Distribution nur im Verzeichnis Initialisation/Files ablegen. Beim Aktivieren der Extension wird dieser Ordner dann unter dem Namen der Extension nach fileadmin kopiert. Manche Typoscript-Dateien habe ich unter EXT:nettemplate/Configuration belassen, sie binden dann von dort aus die entsprechenden Dateien im fileadmin Bereich ein.

fileadmin/nettemplate
 |-- Resources
    |-- indexed_search
    |-- news
    |-- gridelements
    |-- Private
      |-- Layouts
      |-- Partials
      |-- Templates
    |-- Public
      |-- Bilder
      |-- Css
      |-- Fonts
      |-- JavaScript
 |-- Configuration
    |-- TypoScript

Das Archiv beinhaltet einige Unterordner, die sich im Prinzip an die Konventionen halten. Das eigene Layout befindet sich im Verzeichnis Resources und den Unterordnern. Die Ordner indexed_search, news und gridelements enthalten die Dateien zur Anpassung der Gestaltung der entsprechenden Extensionen.

Das Verzeichnis Initialisation/Files aus der Erweiterung wird bei der Installation in den Ordner fileadmin/ kopiert, als Unterordner nettemplate.

Bildschirmfoto von 2020-11-10 13-25-22.png

Was bisher nicht klappt, ist das Kopieren der Site-Einstellungen, das muss man also per Hand nachholen:

cd typo3conf
cp -a ext/nettemplate/Initialisation/sites/  .


Layouts mit Fluid

Ein Fluid-Layout findet sich üblicherweise in einem Verzeichnis Resources. Dieses Verzeichnis besitzt dann die beiden Unterordner Private und Public. Im Ordner Public befinden sich alle Dateien, die unverändert an den Browser ausgeliefert werden, also Bilder, Css, Fonts und Javascript. Der Übersichtlichkeit halber befinden sich diese Elemente jeweils wieder in eigenen Unterverzeichnissen.

Der Aufbau des Layouts wird über die Elemente im Ordner Private definiert. Direkt referenziert werden die Templates aus dem gleichnamigen Ordner. Jedes dieser Templates ist dann Teil eines Layouts, hier werden die Dinge festgelegt, die bei allen Templates gleich sind. Im Ordner Partials finden sich dann Teile des Layouts, die in mehreren Templates identisch benötigt werden, also z.B. die Beschreibung für den Footer.

Die Dateinmane, z.B. der Partials, müssen auf .html enden. Aber beim Aufruf des Partials muss man jeweils die Endung weglassen.

Für diese Distribution habe ich möglichst alle Dateien entsprechend im Verzeichnis fileadmin/nettemplate angelegt.

Hinweis: Seit Typo3 8.7.x müssen die Dateinamen der Partials mit einem Großbuchstaben beginnen.

ext_localconf.php

In dieser Datei können Typoscript-Dateien aufgerufen werden.

<?php
 if (!defined('TYPO3_MODE')) { die('Access denied.'); }
 
 call_user_func(
    function ($extConfString) {

        // Add pageTS config
        \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig('<INCLUDE_TYPOSCRIPT: source="FILE:EXT:nettemplate/Configuration/TypoScript/tsconfig.ts">');

        // Setup (nicht notwendig, geht automatisch über Statische Templates einschließen ...)
          //  \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript('nettemplate','setup',' <INCLUDE_TYPOSCRIPT: source="FILE:EXT:nettemplate/Configuration/TypoScript/setup.txt">');
        //Konstanten (nicht notwendig, geht automatisch über Statische Templates einschließen ...)
          //  \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript('nettemplate','constants',' <INCLUDE_TYPOSCRIPT: source="FILE:EXT:nettemplate/Configuration/TypoScript/constants.txt">');

        // Get ext configuration
          // strlen($extConfString)?$extConf = unserialize($extConfString):$extConf = array();

    },$_EXTCONF
 );
?>

ext_tables.php

<?php
defined('TYPO3_MODE') || die();

call_user_func(function()
{
   /**
    * Extension key
    */
   $extensionKey = 'nettemplate';

   /**
    * Default TypoScript
    */
   \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile(
      $extensionKey,
      'Configuration/TypoScript',
      'Netthelp Template'
   );
});


Layout und Templates

Die Templates beziehen sich alle auf ein Layout. Dieses Layout befindet sich im Ordner

fileadmin/nettemplate/Resources/Private/Layouts/

Die Templates bfinden Sich dann im Ordner

fileadmin/nettemplate/Resources/Private/Templates

Layout: DefaultLayout.html

Das einzige Layout baut sich momentan nach folgendem Schema auf.

 <f:render section="inhalt" />

Hier könnte man natürlich deutlich mehr Zeilen unterbringen, z.B. für den Kopf der Seite.

Template: zweispaltig.html

 <f:layout name="DefaultLayout" />
 <f:section name="inhalt">
 
 <div id="zweispaltig">
 
  <div class="container">
 
    <div class="row" id="header">
      <div class="col-md-12"><f:cObject typoscriptObjectPath="lib.field_headerimage" /></div>
    </div>
    <f:render partial="navbar" />
    <f:render partial="service" />
    <f:render partial="rootline" />
 
    <div id="inhalt" class="row equalheight">
 
      <div class="col-md-3 equal" id="spalte-links">
        <div id="menu-links">
          <a id="subnav" name="subnav"></a><ul class="nav nav-pills  nav-stacked" role="tablist">
          <f:cObject typoscriptObjectPath="lib.field_submenu" />
        </ul>
        </div>
        <div id="inhalt-links">
          <!--TYPO3SEARCH_begin-->
          <f:format.raw>{inhaltLinks}</f:format.raw>
          <!--TYPO3SEARCH_end-->
        </div>
      </div>
 
      <div class="col-md-9 equal" id="hauptinhalt">
        <a id="content" name="content"></a>
          <!--TYPO3SEARCH_begin-->
          <f:if condition="{data.subtitle}">
              <f:then><h1 class="pagetitle">{data.subtitle}</h1><br></f:then>
              <f:else><h1 class="pagetitle">{data.title}</h1><br></f:else>
          </f:if>
          <f:format.raw>{hauptInhalt}</f:format.raw>
          <!--TYPO3SEARCH_end-->
        <p style="font-size:0px">&nbsp;<p>
      </div>
 
    </div>
    <f:render partial="footer" />
   </div>
  </div>
 </f:section>


In meinem Ordner Templates habe ich noch zwei weitere Vorlagendateien liegen.

Template: einspaltig.html

 <f:layout name="DefaultLayout" />
 <f:section name="inhalt">
 
 <div id="einspaltig">
 
  <div class="container">
 
    <div class="row" id="header">
      <div class="col-md-12"><f:cObject typoscriptObjectPath="lib.field_headerimage" /></div>
    </div>
 
  <f:render partial="navbar" />
  <f:render partial="service" />
  <f:render partial="rootline" />
 
    <div id="inhalt" class="row equalheight">
 
      <div class="col-md-12 equal" id="hauptinhalt">
      <a id="content" name="content"></a>
          <!--TYPO3SEARCH_begin-->
          <f:if condition="{data.subtitle}">
              <f:then><h1 class="pagetitle">{data.subtitle}</h1><br></f:then>
              <f:else><h1 class="pagetitle">{data.title}</h1><br></f:else>
          </f:if>
          <f:format.raw>{hauptInhalt}</f:format.raw>
          <!--TYPO3SEARCH_end-->
      <p style="font-size:0px">&nbsp;<p>
      </div>
 
    </div>
    <f:render partial="footer" />
  </div>
 </div>
 </f:section>

Template: dreispaltig.html

 <f:layout name="DefaultLayout" />
 <f:section name="inhalt">
 
 <div id="dreispaltig">
 
  <div class="container">
 
    <div class="row" id="header">
      <div class="col-md-12"><f:cObject typoscriptObjectPath="lib.field_headerimage" /></div>
    </div>
    <f:render partial="navbar" />
    <f:render partial="service" />
    <f:render partial="rootline" />
 
    <div id="inhalt" class="row equalheight">
 
      <div class="col-md-3 equal" id="spalte-links">
        <div id="menu-links">
          <a id="subnav" name="subnav"></a>
          <ul class="nav nav-pills  nav-stacked" role="tablist">
            <f:cObject typoscriptObjectPath="lib.field_submenu" />
          </ul>
        </div>
        <div id="inhalt-links">
         <!--TYPO3SEARCH_begin-->
         <f:format.raw>{inhaltLinks}</f:format.raw>
         <!--TYPO3SEARCH_end-->
        </div>
      </div>
 
      <div class="col-md-6 equal" id="hauptinhalt">
 
          <a id="content" name="content"></a>
          <f:if condition="{data.subtitle}">
              <f:then><h1 class="pagetitle">{data.subtitle}</h1><br></f:then>
              <f:else><h1 class="pagetitle">{data.title}</h1><br></f:else>
            </f:if>
         <!--TYPO3SEARCH_begin-->
         <f:format.raw>{hauptInhalt}</f:format.raw>
         <!--TYPO3SEARCH_end-->
         <p style="font-size:0px">&nbsp;<p>
 
      </div>
 
      <div class="col-md-3 equal" id="spalte-rechts">
         <!--TYPO3SEARCH_begin-->
         <f:format.raw>{inhaltRechts}</f:format.raw>
         <!--TYPO3SEARCH_end-->
      </div>
 
    </div>
 
    <f:render partial="footer" />
  </div>
 </div>
 
 </f:section>


Auswahl und Zuordnung der Templates

Da anscheinend keine direkte Auswahl des Templates im Backend vorgesehen ist, geht man hier einen kleinen Umweg. Für die Auswahl zwischen mehrspaltigen Templates ist es generell sehr praktisch, wenn auch im Backend nur die benötigte Anzahl an Spalten vorhanden ist. Die Gestaltung solcher Backend-Layouts ist vorgesehen. Für die Auswahl des Backend-Layouts gibt es auch ein Feld in den Seiteneigenschaften. Im Typoscript zur Gestaltung kann man dann auf diese Einstellung Bezug nehmen.

Erstellung von Backend-Layouts - tsconfig.ts

Für die Distribution habe ich drei Layouts in die Datei EXT:nettemplate/Configuration/Typoscript/tsconfig.ts ausgelagert:

 mod.web_layout.BackendLayouts {
  Einspaltig {
    title = Einspaltig
    icon = fileadmin/nettemplate/Resources/Public/Bilder/lspalten1.png
    config {
      backend_layout {
        colCount = 1
        rowCount = 1
        rows {
          1 {
            columns {
              1 {
                name = Hauptinhalt
                colPos = 0
                allowed = header,text,textpic,image,textmedia,bullets,table,uploads,menu_abstract,menu_categorized_content,menu_categorized_pages,menu_pages,menu_subpages,menu_recently_updated,menu_related_pages,menu_section,menu_section_pages,menu_sitemap,menu_sitemap_pages,shortcut,list,div,html,login,form_formframework,gridelements_pi1
              }
            }
          }
        }
      }
    }
  }
  
  Zweispaltig {
    title = Zweispaltig
    icon = fileadmin/nettemplate/Resources/Public/Bilder/lspalten2.png
    config {
      backend_layout {
        colCount = 3
        rowCount = 1
        rows {
          1 {
            columns {
              1 {
                name = Inhalt unter linkem Menü
                colPos = 1
                allowed = header,text,textpic,image,textmedia,bullets,table,uploads,menu_abstract,menu_categorized_content,menu_categorized_pages,menu_pages,menu_subpages,menu_recently_updated,menu_related_pages,menu_section,menu_section_pages,menu_sitemap,menu_sitemap_pages,shortcut,list,div,html,login,form_formframework,gridelements_pi1
              }
              2 {
                name = Hauptinhalt
                colspan = 2
                colPos = 0
                allowed = header,text,textpic,image,textmedia,bullets,table,uploads,menu_abstract,menu_categorized_content,menu_categorized_pages,menu_pages,menu_subpages,menu_recently_updated,menu_related_pages,menu_section,menu_section_pages,menu_sitemap,menu_sitemap_pages,shortcut,list,div,html,login,form_formframework,gridelements_pi1
              }
            }
          }
        }
      }
    }
  }
  
  Dreispaltig {
    title = Dreispaltig
    icon = fileadmin/nettemplate/Resources/Public/Bilder/lspalten3.png
    config {
      backend_layout {
        colCount = 4
        rowCount = 1
        rows {
          1 {
            columns {
              1 {
                name = Inhalt unter linkem Menü
                colPos = 1
 ###                allowed = undefined das muss weg
              }
              2 {
                name = Hauptinhalt
                colspan = 2
                colPos = 0
 ###                allowed = undefined das muss weg
              }
              3 {
                name = Rechte Spalte
                colPos = 2
              }
            }
          }
        }
      }
    }
  }
 }

Mir ist nicht ganz klar, ob man bei allowed alle Typen angeben muss, oder undefined stehen lässt oder ganz auf die Zeile verzichtet. Damit werde ich mich aber erst später auseinander setzen.

Das Typoscript dazu

Das Typoscript-Template auf der Root-Seite muss nun erweitert werden:

    file.stdWrap.cObject = CASE
    file.stdWrap.cObject {
   
      key.data = levelfield:-1, backend_layout_next_level, slide
      key.override.field = backend_layout
      #  key.data = pagelayout
      default = TEXT
      default.value =  {$resDir}/Private/Templates/einspaltig.html
      pagets__Einspaltig < .default
      pagets__Zweispaltig < .default
      pagets__Zweispaltig.value =  {$resDir}/Private/Templates/zweispaltig.html
      pagets__Dreispaltig < .default
      pagets__Dreispaltig.value =  {$resDir}/Private/Templates/dreispaltig.html
    }

Siehe oben in der Datei fileadmin/nettemplate/Configuration/TypoScript/setup.txt

Jetzt kann man z.B. in den Seiteneigenschaften der Ausgangsseite die Spaltenzahl einstellen, die man als Vorgabe für alle späteren Seiten machen möchte.

Bildschirmfoto von 2020-11-10 14-08-36.png

Die Vorgabe lässt sich natürlich auf jeder Seite individuell überschreiben, sofern die Rechte dazu nicht eingeschränkt wurden.

Partials

Die Partials befinden sich alle im Verzeichnis

fileadmin/nettemplate/Resources/Private/Partials/

Partial: Footer.html

 <div class="row" id="footer">
    <div class="col-md-12"><f:cObject typoscriptObjectPath="lib.field_footer" /></div>
 </div>

Dieses Partial legt den Aufbau des Footers fest. Dabei greift es auf den Viewhelper f:cObject zurück, über den ein Typoscript-Objekt aufgerufen wird, welches sich in diesem Beispiel im Backend auf der Seite mit den Templates befindet.

Partial: Navbar.html

<div id="navbar">
  <nav class="navbar navbar-default" role="navigation">
    <a id="navigation" name="navigation"></a>
    <!-- Titel und Schalter werden für eine bessere mobile Ansicht zusammengefasst -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
        <span class="sr-only">Navigation ein-/ausblenden</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Hauptmenü</a>
    </div>
 
    <!-- Alle Navigationslinks, Formulare und anderer Inhalt werden hier zusammengefasst und können dann ein- und ausgeblendet werden -->
    <div class="collapse navbar-collapse" id="navbar-collapse-1">
      <ul class="nav navbar-nav">
        <f:cObject typoscriptObjectPath="lib.mainnav" />
     </ul>
    </div> <!-- /.navbar-collapse -->
  </nav>
</div>

Partial: Rootline.html

<div class="row" id="rootline"><f:cObject typoscriptObjectPath="lib.field_rootline" /></div>

Partial: Service.html

<div class="row" id="service"><f:cObject typoscriptObjectPath="lib.field_service" /></div>

Ein Teil der Partials ruft Typoscript-Code auf.