TYPO3: Mehrsprachige 404 Fehlerseite bei realurl

Geändert: Dienstag, 31. Mai 2016 | Erstellt: Montag, 23. Dezember 2013

Dies ist out-of-the-box nicht möglich, da TYPO3 zu einer ungültigen URL nicht die Sprach-ID (den Sprachparameter L) geliefert bekommt und die URL auch nicht über realurl aufgelöst werden kann, da keine entsprechende Seite im System existiert.
Ein Beispiel: Es wird die URL domain.com/de/veraltete-url/ aufgerufen. Da realurl zu dieser URL keine Seite findet, steigt realurl aus und obwohl die URL den Sprachkey „de“ enthält, wird die 404 Fehlerseite anschließend in der Default-Sprache angezeigt.

Mit Ext. realurl_force404lang

Edit Nov. 2015: Leider gab es für diese Erweiterung schon lange kein Update mehr, daher funktioniert sie in neueren TYPO3- und realurl-Versionen nicht mehr.

Die Erweiterung realurl_force404lang korrigiert diesen Umstand: Sie erkennt die Sprach-ID anhand der realurl-Konfiguration aus der sprechenden URL und schreibt diesen in die GET-Superglobale. Damit wird aber noch nicht automatisch die definierte Fehlerseite (z.B. $TYPO3_CONF_VARS[‚FE‘][‚pageNotFound_handling‘] = ‚/index.php?id=71‘) in der richtigen Sprache aufgerufen, daher muss man für das 404-Handling eine User-Funktion schreiben:

LocalConfiguration.php

$TYPO3_CONF_VARS['FE']['pageNotFound_handling'] = 'USER_FUNCTION:fileadmin/php/pageNotFoundHandling.php:user_pageNotFound->pageNotFound';
$TYPO3_CONF_VARS['FE']['pageNotFound_handling_redirectPageID'] = 71; // Attention: this parameter is not provided by TYPO3, but needed for page-not-found-userfunction

pageNotFoundHandling.php

class user_pageNotFound {
  /**
   * Redirect to 404 error page with language-ID provided by ext. "realurl_force404lang"
   *
   * @param array $params: "currentUrl", "reasonText" and "pageAccessFailureReasons"
   * @param object $tsfeObj: object type "tslib_fe"
   */
  function pageNotFound(&$params, &$tsfeObj) {
    // handle default language
    $tsfeObj->pageErrorHandler('/index.php?id=' . $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_redirectPageID'] . (array_key_exists('L', $_GET) ? '&L=' . $_GET['L'] : ''));
  }
}

Ohne Erweiterung

Ohne die Erweiterung realurl_force404lang geht es auch, so könnte die Funktion aussehen:

class user_pageNotFound {
  /**
   * Detect language and redirect to 404 error page
   *
   * @param array $params: "currentUrl", "reasonText" and "pageAccessFailureReasons"
   * @param object $tsfeObj: object type "tslib_fe"
   */
  function pageNotFound($params, $tsfeObj) {
    // get first realurl configuration array (important for multidomain)
    $realurlConf = array_shift($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']);
    // look for language configuration
    foreach($realurlConf['preVars'] as $conf) {
      if($conf['GETvar'] == 'L') {
        foreach($conf['valueMap'] as $k => $v) {
          // we expect a part like "/de/" in requested url
          if(strpos($params['currentUrl'], '/' . $k . '/') !== false) {
            $tsfeObj->pageErrorHandler('/index.php?id=' . $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_redirectPageID'] . '&L=' . $v);
          }
        }
      }
    }
    // handle default language
    $tsfeObj->pageErrorHandler('/index.php?id=' . $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_redirectPageID']);
  }
}

Edit Mai 2016: An der obigen Lösung gefällt mir nicht, dass TYPO3 auf die 404 Fehlerseite redirected, anstatt unter der aufgerufenen URL die Inhalte der 404 Fehlerseite mit Statuscode „404 Not Found“ anzuzeigen. Daher habe ich den PHP Code überarbeitet:

use TYPO3\CMS\Core\Utility\GeneralUtility;
 
class user_pageNotFound {
 
    /**
     * Redirect to 404 error page with language-ID
     *
     * @param array $params: "currentUrl", "reasonText" and "pageAccessFailureReasons"
     * @param object $tsfeObj: object type "tslib_fe"
     */
    function pageNotFound(&$params, &$tsfeObj) {
        // Get first realurl configuration array (important for multidomain)
        $realurlConf = array_shift($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']);
        // Look for language configuration
        $language = false;
        foreach($realurlConf['preVars'] as $conf) {
            if($conf['GETvar'] == 'L') {
                if(is_array($conf['valueMap'])) {
                    foreach($conf['valueMap'] as $k => $v) {
                        // We expect a part like "/de/" in requested url
                        if(strpos($params['currentUrl'], '/' . $k . '/') !== false) {
                            $language = $v;
                            break;
                        }
                    }
                }
            }
        }
        // Get contents of 404 page
        $contentUrl = GeneralUtility::locationHeaderUrl(sprintf(
            '/index.php?id=%u%s',
            $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_redirectPageID'],
            $language ? sprintf('&L=%u', $language) : ''
        ));
        $content = GeneralUtility::getUrl($contentUrl);
        // Output 404 page
        if($content) {
            echo $content;
        // No 404 page found: Display TYPO3 error page
        } else {
            $params['reasonText'] .= sprintf(
                ' Additionally, %s was not found while trying to retrieve the error document.',
                $contentUrl
            );
            if(strpos($contentUrl, 'https://') === 0) {
                $params['reasonText'] .= ' It seems, your SSL certificate seems not to be accepted.';
            }
            $tsfeObj->pageErrorHandler('', '', $params['reasonText']);
        }
    }
}

Thema: TYPO3 Extensions | Kommentare (5)

TYPO3: Accordion mit gridelements

Geändert: Sonntag, 2. März 2014 | Erstellt: Montag, 9. Dezember 2013

In Ergänzung zum Artikel Slider mit gridelements hier nun die Konfiguration zum Accordion mit der Ext. gridelements:

Die FlexForm-Konfiguration für die Accordion-Optionen. Ich setze das Accordion von jqueryui ein, daher stehen hier die Optionen für dieses jQuery Plugin:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3DataStructure>
    <meta>
        <langDisable>1</langDisable>
    </meta>
    <sheets>
        <sDEF>
            <ROOT>
                <TCEforms>
                    <sheetTitle>Allgemein</sheetTitle>
                </TCEforms>
                <type>array</type>
                <el type="array">
                    <active type="array">
                        <TCEforms type="array">
                            <label>Geöffnetes Element (0 = erstes, 1 = zweites, ..., -1 = letztes)</label>
                            <config type="array">
                                <type>input</type>
                                <size>1</size>
                                <max>3</max>
                            </config>
                        </TCEforms>
                    </active>
                </el>
            </ROOT>
        </sDEF>
        <advanced>
            <ROOT>
                <TCEforms>
                    <sheetTitle>Erweitert</sheetTitle>
                </TCEforms>
                <type>array</type>
                <el type="array">
                    <header type="array">
                        <TCEforms type="array">
                            <label>Überschrift Tag</label>
                            <config type="array">
                                <type>input</type>
                                <size>2</size>
                                <default>h3</default>
                            </config>
                        </TCEforms>
                    </header>
                    <collapsible type="array">
                        <TCEforms type="array">
                            <label>Alle Elemente sind einklappbar</label>
                            <config type="array">
                                <type>check</type>
                                <default>1</default>
                            </config>
                        </TCEforms>
                    </collapsible>
                    <animate type="array">
                        <TCEforms type="array">
                            <label>Animation (Name des Effektes oder Dauer in Millisekunden)</label>
                            <config type="array">
                                <type>input</type>
                                <size>40</size>
                            </config>
                        </TCEforms>
                    </animate>
                    <heightStyle type="array">
                        <TCEforms type="array">
                            <label>Verhalten Höhe</label>
                            <config type="array">
                                <type>select</type>
                                <items type="array">
                                <numIndex index="0" type="array">
                                    <numIndex index="0">Keine Anpassung</numIndex>
                                    <numIndex index="1">content</numIndex>
                                </numIndex>
                                <numIndex index="1" type="array">
                                    <numIndex index="0">Orientierung an höchsten Element</numIndex>
                                    <numIndex index="1">auto</numIndex>
                                </numIndex>
                                </items>
                            </config>
                        </TCEforms>
                    </heightStyle>
                    <event type="array">
                        <TCEforms type="array">
                            <label>Aufklappen bei</label>
                            <config type="array">
                                <type>select</type>
                                <items type="array">
                                <numIndex index="0" type="array">
                                    <numIndex index="0">Klick</numIndex>
                                    <numIndex index="1">click</numIndex>
                                </numIndex>
                                <numIndex index="1" type="array">
                                    <numIndex index="0">Mouseover</numIndex>
                                    <numIndex index="1">mouseover</numIndex>
                                </numIndex>
                                </items>
                            </config>
                        </TCEforms>
                    </event>
                </el>
            </ROOT>
        </advanced>
    </sheets>
</T3DataStructure>

HTML-Ausgabe dieses Raster-Elementes:

TS Setup

tt_content.gridelements_pi1 {
    20.10.setup {
        13 < lib.gridelements.defaultGridSetup
        13 {
            columns {
                default.renderObj.wrap = <li class="accordionItem">|</li>
            }
            wrap.stdWrap.cObject = COA
            wrap.stdWrap.cObject {
                wrap = <div class="accordion">|</div>
                10 = COA
                10 {
                    10 = COA
                    10 {
                        wrap = <div class="options">{|}</div>
                        110 = TEXT
                        110.value = "active":false,
                        110.override.wrap = "active":|,
                        110.override.field = flexform_active
                        110.override.if.value = -2
                        110.override.if.isGreaterThan.field = flexform_active
                        120 = TEXT
                        120.wrap = "header":"|",
                        120.field = flexform_header
                        130 = TEXT
                        130.value = "collapsible":true,
                        130.if.isTrue.field = flexform_collapsible
                        140 = TEXT
                        140.wrap = "animate":|,
                        140.field = flexform_animate
                        140.required = 1
                        140.override.wrap = "|"
                        140.override.field = flexform_animate
                        140.override.if.value = 1000000
                        140.override.if.isGreaterThan.field = flexform_animate
                        150 = TEXT
                        150.wrap = "heightStyle":"|",
                        150.field = flexform_heightStyle
                        160 = TEXT
                        160.wrap = "event":"|"
                        160.field = flexform_event
                    }
                    20 = TEXT
                    20.value = <ul class="accordionContents">|</ul>
                }
            }
        }
    }
}

Der JavaScript-Code, um die Optionen an den Slider weiterzugeben:

$('.accordion').each(function(){
    options = $(this).find('.options').text();
    if(options) {
        options = $.parseJSON(options);
    } else {
        options = [];
    }
    $(this).find('.accordionContents').accordion(options);
});

Thema: TYPO3 | Kommentare (9)

TYPO3: Zugriffsbeschränkte Seiten mit Login

Geändert: Mittwoch, 6. Dezember 2017 | Erstellt: Mittwoch, 30. Oktober 2013

In den Seiteneigenschaften einer Seite kann man in Reiter „Zugriff“ über Einstellung „Zugriffsrechte für Benutzergruppen“ festlegen, ob der Benutzer eingeloggt oder ob er einer bestimmten Benutzergruppen zugehörig sein muss, um die Seite sehen zu dürfen. Standardmäßig zeigt TYPO3 Links auf solche Seiten nicht an, wenn der Benutzer nicht eingeloggt ist. Hier wird die Einrichtung einer alternativen Handhabung erklärt, bei der die Links auf diese Seiten angezeigt werden, beim Aufruf der Seite wird aber ein Login-Formular eingeblendet. Nach der richtigen Eingabe von Benutzername und Passwort wird der nun authentifizierte Benutzer auf die zuvor zugriffsbeschränkte Seite weitergeleitet.

Vorteile dieser Lösung:

  1. Verzicht auf Parameter „addParams“
  2. Parameter „redirect_url“ ist nicht in der URL sichtbar
  3. Leitet weiter zu sprechender URL
  4. Nutzt TYPO3 Funktion „pageErrorHandler“
  5. Konfigurierbar über localconf.php (ähnlich der Konfiguration für die 404 Fehlerseite)

Einrichtung

TS Setup

config.typolinkLinkAccessRestrictedPages = NONE

TS Setup für Menü (TMENU)

showAccessRestrictedPages = NONE

Durch das „NONE“ erscheint der Link zur zugriffsbeschränkten Seite sowohl im Menü als auch bei Links im Seitencontent, der Link wird aber nicht auf die Login-Seite umgebogen. Die zugriffsbeschränkte Seite wird also ganz normal aufgerufen, der Inhalt wird aber nicht angezeigt, sondern ein Login-Formular.

Mit dem Menü-Status USR kann man den zugriffsbeschränkten Seiten eine eigene CSS-Klasse zuweisen und diesen damit eine andere Formatierung geben.

Um die Anzeige des Login-Formulars auf zugriffsbeschränkten Seiten kümmert sich eine PHP-Funktion, die auch für die Anzeige der 404-Fehlerseite zuständig ist. Über die localconf.php wird konfiguriert, welche ID und welchen HTTP-Status-Code die 404-Seite und die Login-Seite haben:

localconf.php

$TYPO3_CONF_VARS['FE']['pageNotFound_handling'] = 'USER_FUNCTION:fileadmin/php/pageNotFoundHandling.php:user_pageNotFound->pageNotFound';
$TYPO3_CONF_VARS['FE']['pageNotFound_handling_statheader'] = 'HTTP/1.0 404 Not Found';
$TYPO3_CONF_VARS['FE']['pageNotFound_handling_redirectPageID'] = [page id for 404 page]; // attention: this parameter is not provided by TYPO3, but needed for page-not-found-userfunction
$TYPO3_CONF_VARS['FE']['accessRestrictedPages_handling_statheader'] = 'HTTP/1.0 403 Forbidden'; // attention: this parameter is not provided by TYPO3, but needed for page-not-found-userfunction
$TYPO3_CONF_VARS['FE']['accessRestrictedPages_handling_redirectPageID'] = [page id for login page]; // attention: this parameter is not provided by TYPO3, but needed for page-not-found-userfunction

pageNotFoundHandling.php

class user_pageNotFound {
 
    /**
     * Redirect to 404 error page with language-ID provided by ext. "realurl_force404lang" (if installed)
     * Redirect to login page
     *
     * @param array $params: "currentUrl", "reasonText" and "pageAccessFailureReasons"
     * @param object $tsfeObj: object type "tslib_fe"
     */
    function pageNotFound(&$params, &$pObj) {
        // access restricted page
        if(array_shift($params['pageAccessFailureReasons']['fe_group'])) {
            $pObj->pageErrorHandler(
                '/index.php?id=' . $GLOBALS['TYPO3_CONF_VARS']['FE']['accessRestrictedPages_handling_redirectPageID'] . '&redirect_url=' . urlencode($params['currentUrl']),
                $GLOBALS['TYPO3_CONF_VARS']['FE']['accessRestrictedPages_handling_statheader'],
                $params['pageAccessFailureReasons']['reasonText']
            );
        // 404 not found
        } else {
            // handle default language
            $pObj->pageErrorHandler('/index.php?id=' . $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_redirectPageID'] . (array_key_exists('L', $_GET) ? '&L=' . $_GET['L'] : ''));
        }
    }
}

Als Extension für den Login wird felogin verwendet. Diese Erweiterung muss noch so konfiguriert sein, dass sie auf den Parameter „redirect_url“ hört, der in der URL übermittelt wird. Dazu wählt man Option „Definiert durch GET- oder POST-Variablen“ für den Weiterleitungsmodus aus.

Getestet mit TYPO3 4.7

Thema: TYPO3 | Kommentare (3)

TYPO3: Slider mit gridelements

Geändert: Dienstag, 1. Dezember 2015 | Erstellt: Sonntag, 21. Juli 2013

gridelementsBisher war meine bevorzugte Extension für einen Slider in TYPO3 die Erweiterung jfmulticontents, diese hat aber paar Dinge, die mir nicht so gefallen, unter anderem gibt es mit Ext. gridelements einen kleinen Konflikt bzgl. dem Feld „Spalte“ (colPos). Daher habe ich mich daran gemacht, einen Slider mit der Erweiterung gridelements umzusetzen.

Vorteile des Sliders mit gridelements:

  1. Es muss keine separate Extension installiert werden
  2. Es kann jede beliebige JavaScript-Library und dazu passenden Slider-Plugins eingesetzt werden, mit den Slider-Optionen die man benötigt und den Effekten, die einem gefallen
  3. Es können alle beliebigen Inhalte im Slider angezeigt werden, also z.B. auch Formulare, Plugins, Text mit Bild usw.
  4. Der Slider ist direkt über das Raster-Element konfigurierbar

Zuerst einmal muss man ein einspaltiges Raster-Element für gridelements anlegen. Wie man das genau macht, möchte ich an dieser Stelle nicht näher erläutern, dafür gibt es ausreichend Dokumentation. In Feld „Raster-Konfiguration“ kommt diese Backend-Layout-Konfiguration:

backend_layout {
    colCount = 1
    rowCount = 1
    rows {
        1 {
            columns {
                1 {
                    name = Slider-Elemente
                    colPos = 1
                }
            }
        }
    }
}

Mit dieser Konfiguration werden die Inhalte aus der ersten (und einzigen) Spalte des Raster-Elements eingelesen und im Frontend ausgegeben.

In Feld „Seiteninhalts-Konfiguration“ kommt die FlexForm-Konfiguration für die Slider-Optionen. Als Slider setze ich AnythingSlider ein, daher stehen hier die Optionen für dieses jQuery Plugin:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3DataStructure>
    <meta>
        <langDisable>1</langDisable>
    </meta>
    <sheets>
        <sDEF>
            <ROOT>
                <TCEforms>
                    <sheetTitle>Allgemein</sheetTitle>
                </TCEforms>
                <type>array</type>
                <el type="array">
                    <mode type="array">
                        <TCEforms type="array">
                            <label>Modus</label>
                            <config type="array">
                                <type>select</type>
                                <items type="array">
                                <numIndex index="0" type="array">
                                    <numIndex index="0">Horizontal</numIndex>
                                    <numIndex index="1">h</numIndex>
                                </numIndex>
                                <numIndex index="1" type="array">
                                    <numIndex index="0">Vertikal</numIndex>
                                    <numIndex index="1">v</numIndex>
                                </numIndex>
                                <numIndex index="2" type="array">
                                    <numIndex index="0">Fade</numIndex>
                                    <numIndex index="1">f</numIndex>
                                </numIndex>
                                </items>
                            </config>
                        </TCEforms>
                    </mode>
                    <showMultiple type="array">
                        <TCEforms type="array">
                            <label>Anzahl sichtbare Slider-Elemente (2 bis 6, die Höhe MUSS manuell gesetzt werden)</label>
                            <config type="array">
                                <type>input</type>
                                <size>1</size>
                                <max>1</max>
                                <eval>int</eval>
                                <range>
                                <lower>2</lower>
                                <upper>6</upper>
                                </range>
                            </config>
                        </TCEforms>
                    </showMultiple>
                    <height type="array">
                        <TCEforms type="array">
                            <label>Höhe des Sliders</label>
                            <config type="array">
                                <type>input</type>
                                <size>4</size>
                                <max>4</max>
                                <eval>int</eval>
                            </config>
                        </TCEforms>
                    </height>
                    <infiniteSlides type="array">
                        <TCEforms type="array">
                            <label>Unendliches Sliden (nach dem letzten Element im Slider geht es übergangslos zum ersten weiter, ansonsten erfolgt ein Sprung zurück zum ersten)</label>
                            <config type="array">
                                <type>check</type>
                                <default>1</default>
                            </config>
                        </TCEforms>
                    </infiniteSlides>
                    <animationTime type="array">
                        <TCEforms type="array">
                            <label>Animationsdauer (Millisekunden)</label>
                            <config type="array">
                                <type>input</type>
                                <size>5</size>
                                <max>5</max>
                                <eval>int</eval>
                            </config>
                        </TCEforms>
                    </animationTime>
                </el>
            </ROOT>
        </sDEF>
        <navigation>
            <ROOT>
                <TCEforms>
                    <sheetTitle>Navigation</sheetTitle>
                </TCEforms>
                <type>array</type>
                <el type="array">
                    <buildArrows type="array">
                        <TCEforms type="array">
                            <label>Pfeile anzeigen</label>
                            <config type="array">
                                <type>check</type>
                                <default>1</default>
                            </config>
                            <onChange>reload</onChange>
                        </TCEforms>
                    </buildArrows>
                    <toggleArrows type="array">
                        <TCEforms type="array">
                            <label>Pfeile einblenden bei Mouseover</label>
                            <config type="array">
                                <type>check</type>
                                <default>0</default>
                            </config>
                            <displayCond>FIELD:buildArrows:REQ:true</displayCond>
                        </TCEforms>
                    </toggleArrows>
                    <buildNavigation type="array">
                        <TCEforms type="array">
                            <label>Navigation anzeigen</label>
                            <config type="array">
                                <type>check</type>
                                <default>0</default>
                            </config>
                            <onChange>reload</onChange>
                        </TCEforms>
                    </buildNavigation>
                    <toggleControls type="array">
                        <TCEforms type="array">
                            <label>Navigation einblenden bei Mouseover</label>
                            <config type="array">
                                <type>check</type>
                                <default>0</default>
                            </config>
                            <displayCond>FIELD:buildNavigation:REQ:true</displayCond>
                        </TCEforms>
                    </toggleControls>
                </el>
            </ROOT>
        </navigation>
        <slideshow>
            <ROOT>
                <TCEforms>
                    <sheetTitle>Slideshow</sheetTitle>
                </TCEforms>
                <type>array</type>
                <el type="array">
                    <autoPlay type="array">
                        <TCEforms type="array">
                            <label>Slideshow (automatisches Sliden)</label>
                            <config type="array">
                                <type>check</type>
                                <default>0</default>
                            </config>
                        </TCEforms>
                    </autoPlay>
                    <buildStartStop type="array">
                        <TCEforms type="array">
                            <label>Start-Stop-Button anzeigen</label>
                            <config type="array">
                                <type>check</type>
                                <default>0</default>
                            </config>
                        </TCEforms>
                    </buildStartStop>
                    <autoPlayDelayed type="array">
                        <TCEforms type="array">
                            <label>Zeitverzögerung bis Start (Millisekunden)</label>
                            <config type="array">
                                <type>input</type>
                                <size>5</size>
                                <max>5</max>
                                <eval>int</eval>
                            </config>
                        </TCEforms>
                    </autoPlayDelayed>
                    <delay type="array">
                        <TCEforms type="array">
                            <label>Zeitverzögerung bis zum nächsten Sliden (Millisekunden)</label>
                            <config type="array">
                                <type>input</type>
                                <size>5</size>
                                <max>5</max>
                                <eval>int</eval>
                            </config>
                        </TCEforms>
                    </delay>
                    <pauseOnHover type="array">
                        <TCEforms type="array">
                            <label>Pausieren bei Mouseover</label>
                            <config type="array">
                                <type>check</type>
                                <default>1</default>
                            </config>
                        </TCEforms>
                    </pauseOnHover>
                </el>
            </ROOT>
        </slideshow>
    </sheets>
</T3DataStructure>

AnythingSlider hat noch weitere Optionen, die erachte ich aber als nicht so wichtig, dass dem Redakteur diese zur Verfügung stehen müssten.

Wenn man TYPO3 Version 6.1 oder höher einsetzt, kann man die Bedingung, zu denen ein Feld angezeigt wird, noch etwas verfeinern, indem man ODER- oder UND-Bedingungen definiert, z.B. für das Feld „toggleControls“, das bestimmt, ob die Navigation und der Start-Stop-Button erst beim Mouseover über den Slider eingeblendet wird:

<displayCond>
  <OR>
    <numIndex>FIELD:buildNavigation:REQ:true</numIndex>
    <numIndex>FIELD:buildStartStop:REQ:true</numIndex>
  </OR>
</displayCond>

Nun steht im TYPO3 Backend das Raster-Element „Slider“ zur Verfügung, in das man, wie gewohnt, alle verfügbaren Inhaltselemente einfügen kann:

gridelements slider

Als nächstes muss man die HTML-Ausgabe dieses Raster-Elementes konfigurieren:

TS Setup

tt_content.gridelements_pi1 {
    20.10.setup {
        1 < lib.gridelements.defaultGridSetup
        1 {
            columns {
                default.renderObj.wrap = <li>|</li>
            }
            wrap.stdWrap.cObject = COA
            wrap.stdWrap.cObject {
                wrap = <div class="anythingSliderOuter">|</div>
                10 = COA
                10 {
                    10 = COA
                    10 {
                        wrap = <div class="options">{|}</div>
                        // General settings
                        110 = TEXT
                        110.wrap = "mode":"|",
                        110.field = flexform_mode
                        120 = TEXT
                        120.wrap = "showMultiple":|,
                        120.field = flexform_showMultiple
                        120.if.value = 1
                        120.if.isGreaterThan.field = flexform_showMultiple
                        130 = TEXT
                        130.value = "infiniteSlides":false,
                        130.if.isFalse.field = flexform_infiniteSlides
                        140 = TEXT
                        140.wrap = "animationTime":|,
                        140.field = flexform_animationTime
                        140.if.isTrue.field = flexform_animationTime
                        // Navigation options
                        210 = TEXT
                        210.value = "buildArrows":false,
                        210.if.isFalse.field = flexform_buildArrows
                        220 = TEXT
                        220.value = "toggleArrows":true,
                        220.if.isTrue.field = flexform_toggleArrows
                        230 = TEXT
                        230.value = "buildNavigation":false,
                        230.if.isFalse.field = flexform_buildNavigation
                        240 = TEXT
                        240.value = "toggleControls":true,
                        240.if.isTrue.field = flexform_toggleControls
                        250 = TEXT
                        250.value = "buildStartStop":false,
                        250.if.isFalse.field = flexform_buildStartStop
                        // Slideshow options
                        310 = TEXT
                        310.wrap = "autoPlay":true,
                        310.if.isTrue.field = flexform_autoPlay
                        320 = TEXT
                        320.wrap = "autoPlayDelayed":|,
                        320.field = flexform_autoPlayDelayed
                        320.if.isTrue.field = flexform_autoPlayDelayed
                        330 = TEXT
                        330.wrap = "delay":|,
                        330.field = flexform_delay
                        330.if.isTrue.field = flexform_delay
                        340 = TEXT
                        340.value = "pauseOnHover":false,
                        340.if.isFalse.field = flexform_pauseOnHover
                        // Other options
                        9980 = TEXT
                        9980.wrap = "height":|,
                        9980.field = flexform_height
                        9980.if.isTrue.field = flexform_height
                        9990 = TEXT
                        9990.value = "expand":true
                    }
                    20 = TEXT
                    20.value = <ul class="anythingSliderContents">|</ul>
                }
            }
        }
    }
}

Die daraus resultierende HTML-Ausgabe sieht wie folgt aus:

<div class="anythingSliderOuter">
    <div class="options">{"mode":"h","buildArrows":false,"delay":1000,"expand":true}</div>
    <ul class="anythingSliderContents">
        <li>...</li>
        <li>...</li>
    </ul>
</div>

Man sieht hier, dass die Inhaltselemente in einer unsortierten Liste ausgegeben werden und die Slider-Optionen über ein DIV übermittelt werden. Dieses DIV sollte man natürlich über CSS ausblenden.

Nun muss man nur noch die Optionen im JavaScript einlesen und an das Slider-Plugin übergeben. Da AnythingSlider Probleme hat, die Höhe der Slider-Inhalte korrekt zu bestimmen, wird hier noch dem Slider die Höhe des höchsten Slider-Elementes zugewiesen, falls der Redakteur die Höhe nicht selbst bestimmt hat:

$('ul.anythingSliderContents').each(function(){
    var anythingSliderContents = $(this);
    var anythingSliderContainer = anythingSliderContents.closest('.anythingSliderOuter');
    var options = anythingSliderContainer.find('.options').text();
    if(options) {
        options = $.parseJSON(options);
    } else {
        options = [];
    }
    anythingSliderContainer.css('width', '100%');
    if(options.height) {
        anythingSliderContainer.css('height', options.height);
    } else {
        // determine height
        anythingSliderContainer.css('height', 0);
        anythingSliderContents.children('li').each(function(){
            if($(this).height() > anythingSliderContainer.height()){
                anythingSliderContainer.css('height', $(this).height());
            }
        });
    }
 
    // determine height again when screen size changed
    /*$(this).bind('slideshow_resized', function(event, slider){
        // only, if height isn't set to fixed value
        if(!slider.options.height) {
            anythingSliderContainer.css('height', slider.$el.closest('.anythingSlider').css('height'));
        }
    });*/
    anythingSliderContents.anythingSlider(options);
});

Wenn man alles richtig gemacht hat, hat man einen schönen Slider:

slider demo

Viel Erfolg bei der Implementierung deines Sliders! Über Optimierungsvorschläge bin ich sehr dankbar, so gefällt mir z.B. die Übermittlung der Slider-Optionen über ein DIV nicht wirklich. Gerne verlinke ich hier auch deinen Slider, den du mit gridelements umgesetzt hast.

Thema: TYPO3 | Kommentare (13)

Extbase: Standalone View

Geändert: Dienstag, 11. Oktober 2016 | Erstellt: Sonntag, 5. Mai 2013

Siehe auch EXT:rr_restaurants oder EXT:loewen_css (Implementierung als Utility)

Rendern eines View ohne zugehörige Action, z.B. für ein E-Mail-Template:

$configuration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
$view = $this->objectManager->get(\TYPO3\CMS\Fluid\View\StandaloneView::class);
$view->getRequest()->setControllerExtensionName($this->extensionName);
$view->setFormat('txt');
$view->setLayoutRootPaths($configuration['view']['layoutRootPaths']);
$view->setPartialRootPaths($configuration['view']['partialRootPaths']);
$view->setTemplateRootPaths($configuration['view']['templateRootPaths']);
$view->setTemplate('Mail/MyTemplate');
$view->assign('myParam', $myParam);
$result = $view->render();

Die Funktion setControllerExtensionName() ist dafür zuständig, dass die Sprachen aus der locallang.xml ausgelesen werden können.

Funktioniert auch im TYPO3 BE, dann muss man aber module.tx_myext.view.templateRootPaths (und die anderen Pfade) über ext_typoscript_setup.txt (damit es auf der obersten Ebene verfügbar ist) setzen.

Alternative, bei nur einem Template, das ggf. in fileadmin liegt:

$templateRootPath = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($configuration['view']['templateRootPath']);
$view->setTemplatePathAndFilename($templateRootPath . 'Mail/MyTemplate.txt');

Dieser Code ersetzt die Zeilen 5 bis 8 im ersten Snippet.

 

Thema: TYPO3 Extension-Programmierung | Kommentare (2)

Wie funktioniert jumpurl in direct_mail?

Geändert: Donnerstag, 26. Dezember 2013 | Erstellt: Donnerstag, 25. April 2013

Gerade hatte ich einen Fehler beim Aufrufen einer URL aus einem Newsletter (versendet über direct_mail), in dem ich jumpurls nutze. Die URL war in dieser Form:

www.domain.de/index.php?id=2&rid=t_2&mid=2&aC=7a7f6b54&jumpurl=2

Allerdings wurden beim Redirect auf die eigentliche URL die Platzhalter, z. B. ###USER_uid###, nicht ersetzt. Also habe ich recherchiert, wo die jumpurls gespeichert werden. Ich bin davon ausgegangen, dass diese in einer Tabelle gespeichert werden. Das ist aber nicht der Fall, bei direct_mail werden die jumpurls mit der Funktion checkDataSubmission() verarbeitet:

  1. Anhand dem Parameter „mid“ wird der zugehörige Newsletter aus der Datenbank ausgelesen.
  2. In dem Newsletter wird anhand dem Parameter „jumpurl“ der zugehörige Link geholt, in unserem Beispiel also der zweite Link. Dieser sieht, wenn es sich um den Abmelden-Link handelt, beispielsweise so aus: www.domain.de/index.php?id=3&cmd=delete&aC=###SYS_AUTHCODE###&rU=###USER_uid###
  3. Nun wird anhand dem Parameter „rid“ der Benutzer ermittelt, an den der Newsletter geschickt wurde. In unserem Beispiel hat der Parameter den Wert „t_2„, also hat unser Benutzer die ID 2 und liegt in Tabelle „tt_address„. Alternativ könnte der Wert auch „f_2“ lauten, dann ist der Benutzer in Tabelle „fe_users“ gespeichert.
  4. Nun werden die Platzhalter in der URL mit den Daten des Benutzers ersetzt, Ergebnis ist z. B. eine solche URL: www.domain.de/index.php?id=3&cmd=delete&aC=7a7f6b54&rU=2
  5. Der Parameter „aC“ ist ein Authentifizierungscode, dieser wird von direct_mail weitergereicht, zuvor wurde er aber schon vom TYPO3 System auf die Gültigkeit überprüft.

Nun weiß ich auch, wieso die Platzhalter nicht ersetzt wurden: Der Benutzer war in der Datenbank als gelöscht markiert, er hat sich also bereits vom Newsletter abgemeldet.

Thema: TYPO3 Extensions | Keine Kommentare

Webansicht des Newsletters mit direct_mail

Geändert: Donnerstag, 28. Januar 2016 | Erstellt: Mittwoch, 23. Januar 2013

Bei direct_mail ist es gar nicht so trivial, in einem Newsletter den Link zur Webansicht einzubauen, denn dabei müssen verschiedene Dinge beachtet werden:

  1. Der Link sollte auf die richtige Seiten-ID gehen
  2. Der Link sollte in der Webansicht selbst nicht zu sehen sein
  3. Die Webansicht sollte nicht personalisiert sein

Im Manual von direct_mail steht dazu leider nichts näheres, daher hier meine kleine Anleitung:

1. Vorbereitungen

Damit der Newsletter ordentlich konfiguriert werden kann, mit verschiedenen Inhalten für die Webansicht und dem eigentlichen Newsletter, muss eine Subdomain angelegt werden, z.B. „newsletter.meine-webseite.de“. Die Webansicht des Newsletters wird dann unter dieser Subdomain angeboten. Dafür muss die Subdomain als Domain Record angelegt werden, der an erster Stelle im Newsletter-Root abgelegt ist. Der eigentliche Newsletter, der an die Abonnenten verschickt wird, muss aber über die Hauptdomain verschickt werden. Das erreicht man, indem man in der direct_mail-Konfiguration die Hauptdomain als „Domäne für interne Links“ auswählt:
Konfiguration Hauptdomain

2. Link zur Webansicht

Für den HTML-Newsletter wird mit TypoScript folgender Link erzeugt und ins Newsletter-Template eingebaut:

lib.webview = TEXT
lib.webview {
  value = Klicken Sie hier, wenn Sie diese E-Mail nicht lesen können.
  typolink.parameter.data = page:uid
}

Diese URL sollte vor allem auch in der Nur-Text-Version des Newsletters erscheinen. Dafür setzt man in das Plain-Text-Newsletter-Template einen Platzhalter:

Sie erhalten die Nur-Text-Version unseres Newsletters.
Den vollwertigen Newsletter können Sie sich hier anschauen: ###WEBVIEW###

Dieser Platzhalter wird mit nachfolgender TypoScript-Anweisung durch die URL zur Webansicht ersetzt:

tx_directmail_pi1.10.marks {
  WEBVIEW = TEXT
  WEBVIEW {
    typolink.parameter.data = page:uid
    typolink.returnLast = url
  }
}

3. Link in Webansicht verstecken

Anhand der zuvor angelegten Subdomain kann man das TypoScript-Objekt „webview“ entfernen:

[globalString = IENV:HTTP_HOST = newsletter.*]
lib.webview >
[end]

Genauso kann man im übrigen auch mit dem Link für die Newsletter-Abmeldung verfahren: Auch dieser hat in der Webansicht nichts verloren.

4. Keine Personalisierung

direct_mail bietet die Personalisierung eines Newsletters an, beispielsweise mit Platzhaltern für Name (###USER_name###) oder E-Mail-Adresse (###USER_email###). Diese Platzhalter werden idealerweise auch in der Webansicht mit den Daten des Abonnenten ersetzt. Das geht aber mit direct_mail (noch) nicht, daher sollte man für die Webansicht einen unpersonalisierten Newsletter anbieten.

Mit der Erweiterung multidomain_publishing kann man für jedes Inhaltselement individuell bestimmen, unter welcher Domain es angezeigt wird. Nehmen wir zum Beispiel die Begrüßung, die wir als Inhaltselement „Text“ angelegt haben mit dem Text „Lieber ###USER_name###“. Dieses Inhaltselement stellen wir so ein, dass es nur unter der Hauptdomain angezeigt wird:

Inhaltselement für bestimmte Domain verbergen

Für die Webansicht wird ein zweites Text-Inhaltselement an, das die Begrüßung „Lieber Leser“ enthält, hier stellen wir aber ein, dass es nur unter der Newsletter-Domain angezeigt wird. Daher ist es wichtig (wie in Punkt 1. Vorbereitungen erläutert), dass der Cronjob die Newsletter-Seite unter der Hauptdomain abruft, die Webansicht aber unter der Newsletter-Subdomain angezeigt wird.

Thema: TYPO3 Extensions | Kommentare (3)

Vorstellung Extension getcontentbyajax

Geändert: Dienstag, 29. August 2017 | Erstellt: Freitag, 12. Oktober 2012

Die TYPO3-Erweiterung getcontentbyajax habe ich für www.digitalagentur-mainz.de programmiert, sie ist nun schon seit knapp einem Jahr im TER. Mit dieser Erweiterung wird jede aufgerufene Seite via Ajax nachgeladen: Jeder Klick auf einen internen Link resultiert in einer Ajax-Anfrage. Damit sind nette Effekte möglich, z.B. das Einschieben der Inhalte von der Seite. Diesen Effekt kann man sich bei www.digitalagentur-mainz.de (mittlerweile gab es einen Relaunch) oder auch bei meiner eigenen Webseite (sbtheke.de) anschauen. Aber auch die verbesserte Ladegeschwindigkeit der Seite ist ein nicht unwichtiger Punkt. Die Erweiterung kann mit nur wenigen Einstellungen für bestehende Webseiten aktiviert werden und funktioniert auch mit Inhalten aus fremden Erweiterungen.

Es gibt keinerlei Einschränkungen für den Benutzer, die man sonst oft bei Ajax-Funktionen hat: Beim Aufrufen einer neuen Seite wird die URL in der Adressleiste und der Browsertitel aktualisiert, die Blätterfunktionen des Browsers funktionieren und die Seite funktioniert auch ohne JavaScript.

Das Nachladen der Inhalte funktioniert wie folgt vor:

  1. Der Benutzer klickt auf einen internen Link
  2. Mit JavaScript wird das normale Laden der Seite verhindert, ein Ladebalken wird eingeblendet
  3. Die angefragte URL wird in die Adress-Leiste gesetzt, danach wird sie via Ajax an den Server gesendet
  4. Der Server verarbeitet die URL, erhält so den Inhalt der angefragten Seite und liefert den gewünschten Teilbereich daraus zurück
  5. Mit JavaScript wird der Inhalt ausgetauscht, der Ladebalken wird ausgeblendet
  6. Wenn es sich bei dem angeklickten Link um einen Eintrag in einem Navigationsmenü gehandelt hat, erhält der Link und die übergeordneten Ebenen die Klasse „act“

Wenn du getcontentbyajax einsetzst, freue ich mich über einen Link zu der Webseite. Oder schreibe mir, welche Erfahrungen du mit der Erweiterung gemacht hast – vielleicht gibt es ja Nachteile, von denen ich nichts weiß?

Thema: TYPO3 Extensions | Kommentare (30)

Kunterbuntes TER

Geändert: Freitag, 6. November 2015 | Erstellt: Mittwoch, 26. Oktober 2011

Aktuell gibt es über 5300 Extensions im TER (TYPO3 Extension Repository), viele davon sind schon sehr alt, manche davon funktionieren schon gar nicht mehr mit der aktuellen TYPO3 Version, andere sind auf sehr spezielle Einsatzzwecke ausgerichtet, viele haben keine oder fehlerhafte Dokumentation (die Umwandlung von dem sxw-Dokument in HTML klappt nicht immer), so dass man deren Nutzen nur schwer erkennen kann.

Ich möchte in diesem Beitrag auf die (wenigen) „schlechten“, die unprofessionellen und zweifelhaften Erweiterungen eingehen; Extensions, die doppelt vorhanden oder unnötig sind – also ein wenig „Extension-Bashing“ betreiben. Sei mir nicht böse, wenn eine deiner TYPO3-Erweiterungen darunter ist. Ich möchte keinen an den (Internet-)Pranger stellen. Wer sich dennoch an mir Rächen möchte: in einer meiner fast 20 TYPO3-Erweiterungen finden sich bestimmt auch Fehler ;-)

Extensions mit sehr geringem Umfang

Es mag zwar Erweiterungen geben, die trotz ihres geringen Umfangs durchaus eine Daseinsberechtigung haben, wie z.B. die Erweiterungen example_bepreview, pagenotfound_handler, hyphenator, ka_browserexclusion, langfeautoconfig, indexedsearch_icons oder das beliebte rgaccordion, doch die Extension cs_multiline_page_header ist mir negativ aufgefallen: Diese Erweiterung ermöglicht einen mehrzeiligen Seitentitel und wandelt dafür das Eingabefeld für den Seitentitel in eine Textarea um. Die eine(!) Zeile TCA-Konfiguration, aus der die Extension besteht, schreibt man besser in die Datei „typo3conf/extTables.php“. Ok, ich habe untertrieben, seit der neuesten Version (mittlerweile gab es immerhin 5 Updates der Erweiterung im TER) unterstützt die Extension mehrsprachige Webseiten und hat damit noch eine zusätzliche Zeile TCA-Konfiguration bekommen. Dafür braucht es aber beim besten Willen keine eigene Extension, die das ganze TYPO3-System unübersichtlicher macht und verlangsamt (nur ein kleines bisschen natürlich, aber das summiert sich).

Ähnlich verhält es sich mit den Erweiterungen googleverify und alexa, die lediglich den Verification-Code in den Head-Bereich einer Webseite setzen. Oder mjj_t3quixplorer und mjj_phpmyadmin, die ebenfalls nur aus einer Zeile PHP-Code bestehen. In die gleiche Kategorie lässt sich die Extension cm_pngfix einordnen, die lediglich aus wenigen Zeilen TypoScript- und PHP-Code besteht. Die Funktion der Extension, nämlich halbtransparente PNGs im IE6 zu ermöglichen, lässt mit drei Zeilen TypoScript-Code umsetzen – ganz ohne PHP!

Neidisch blicke ich auf die Extension contentwrapper: Diese wurde schon über 2400 mal heruntergeladen! Dabei besteht sie nur aus ein wenig TypoScript und CSS, damit ein Redakteur seine Inhaltselemente in farbige Boxen setzen kann. Auch hierfür ist eine Extension zu „überdimensioniert“, die knapp zwei Dutzend Zeilen TypoScript Code schreibt man besser zu der allgemeinen TypoScript Konfiguration der Seite.

Was meint ihr? Macht es Sinn, für jede Kleinigkeit eine TYPO3 Erweiterung zu erstellen? Ein Vorteil davon ist sicherlich, dass auch Nicht-Entwickler diese nutzen können.

Extension-Raub

Unverschämt sind Entwickler, die eine bestehende Extension dublizieren und als eigene ausgeben: So basiert die Erweiterung cm_downloads auf (einer älteren Version von) sb_downloader. Oder die Erweiterung cl_metatags auf der Erweiterung metatags. Die Unterschiede sind minimal, 99% des Codes stammt von der originalen Erweiterung. Ich finde das frech, eine Erweiterung, die ein Entwickler in vielen Stunden mühsam erstellt hat, einfach zu kopieren und als seine eigene Kreation auszugeben. Natürlich kann man Erweiterungen für seine Bedürfnisse anpassen, diese sollte man dann aber nicht ins TER hochladen oder zumindest auf den ursprünglichen Entwickler hinweisen. Bei dieser Vorgehensweise sehe ich auch noch ein Problem bei Sicherheitslücken, die in der ursprünglichen Extension entdeckt wird – ob diese auch in das Dublikat übernommen wird, ist fraglich.

Auch der Autor der Extension enter_new_weeaar_googlesitemap hält es nicht für nötig, auf den ursprünglichen Entwickler hinzuweisen bzw. was seine Gründe für sein Erweiterung sind. Diese Erweiterung ist eine 1:1-Kopie von weeaar_googlesitemap, mit nur minimalen Änderungen im PHP-Code des Plugins. enter_new_weeaar_googlesitemap hat eine kuriose Besonderheit: Um sie nutzen zu können, muss man sie in „weeaar_googlesitemap“ umbenennen.

Kuriositäten

Wieso der Entwickler der Extension linkstats und linkclickcounter diese doppelt im TER hat, erschließt sich mir nicht wirklich. Hat ihm der Extension-Key nicht gefallen? Kleiner Tipp: Es gibt die Möglichkeit, Erweiterungen als „obsolete“ zu kennzeichen.

Der Autor der Extension bsd_tmplselect lernt sich wohl gerade in TYPO3 ein und möchte uns an seinem Lernprozess teilhaben. Interessant sind dabei auch seine Upload-Kommentare.

Ganz eindeutig in die Jux-Kategorie gehört die Extension terbingo – diese fordert bei der Installation eine weitere, zufällig gewählte Extension aus dem TER an. Ohne den „großen Bruder“ terbingohelper funktioniert diese Extension erst gar nicht.

Thema: Allgemein, Ärgernisse, Sonstiges, TYPO3 Extensions | Kommentare (5)

TYPO3: Verschiedene Seiten-Templates mit Fluid und BE Layout

Geändert: Donnerstag, 26. Dezember 2013 | Erstellt: Donnerstag, 26. Mai 2011

Mit der Fluid Template Engine (ab TYPO3 Version 4.3) und dem Backend Layout (ab TYPO3 Version 4.5) kann man mit wenig Aufwand dem Redakteur verschiedene Seiten-Layouts zur Auswahl anbieten, die er über eine Select-Box in den Seiteneigenschaften einer Seite wählen kann (siehe Abbildung).

Das macht Erweiterungen wie z.B. rlmp_tmplselector unnötig. Hier die Schritt-für-Schritt-Anleitung für die Einrichtung und Konfiguration der Seiten-Templates:

1) Backend Layout anlegen

Backend Layouts legt man als Datensätze in einem beliebigen SysFolder ab (außer, man hat eine „General Record Storage Page“ gewählt, dann muss man die Datensätze dort ablegen). Die Erstellung ist sehr einfach, TYPO3 stellt dafür in dem Datensatz einen Wizard zur Verfügung, hier am Beispiel eines einfachen zwei-spaltigen Layouts:

Als „Spaltennummer“ wird eine Zahl vergeben. Diese wird weiter unten verwendet, um den Inhalt einzulesen. Meistens benötigt man als Seiten-Layout ein 1-spaltiges, ein 2-spaltiges und eines, das nur den Seiten-Inhalt (ohne Header, Footer, Randspalten usw.) ausgibt, z.B. für Popups oder Lightboxen.

2) HTML-Templates erstellen

Als nächstes legt man die HTML-Templates für die Seiten-Layouts an. Ich habe dabei folgende Struktur vorliegen:

fileadmin/templates/fluid/ für die Seiten-Templates
fileadmin/templates/fluid/layouts/ für die Templates, welche die grobe Struktur der Seite vorgeben (Rahmen-Layout)
fileadmin/templates/fluid/partials/ für die Templates, die Seiten-Teile enthalten (z.B. Subnavigationen oder den Kopfbereich). Diese Seiten-Teile können in unterschiedlichen Layouts oder Seiten-Templates eingebunden werden. In diesem Beispiel-Setup werden diese aber nicht benötigt.

fileadmin/templates/fluid/layouts/default.html

<div id="header">...</div>
<div id="content">
  <f:render section="content" />
</div>
<div id="footer">...</div>

fileadmin/templates/fluid/1col.html

<f:layout name="default" />
<f:section name="content">
  <div id="content_main">
    <f:format.html>{content}</f:format.html>
  </div>
</f:section>

fileadmin/templates/fluid/2col.html

<f:layout name="default" />
<f:section name="content">
  <div id="content_main">
    <f:format.html>{content}</f:format.html>
  </div>
  <div id="content_left">
    <f:format.html>{content_left}</f:format.html>
  </div>
</f:section>

fileadmin/templates/fluid/popup.html

<div id="content">
  <f:format.html>{content}</f:format.html>
</div>

Hinweis: Bei mir gab es Probleme mit dem Rendering. Standardmäßig jagt Fluid den Content durch die Rendering-Funktion „parseFunc“ mit den Einstellungen von „lib.parseFunc_RTE“. Allerdings ist in diesen Einstellungen keine iframes, Formulare usw. vorgesehen (diese kann man und soll man über den RTE gar nicht einpflegen), so dass die Tags <iframe> und <form> sichtbar auf der Seite ausgegeben werden. Um das zu verhindern, gibt es mehrere Lösungen:

1) Verwendung von „f:format.raw“ (Fluid Version > 1.3.0):

<f:format.raw>{content}</f:format.raw>

2) TypoScript-Objekt direkt einbinden:

<f:cObject typoscriptObjectPath="lib.content" />

Und in TypoScript:

lib.content < styles.content.get

3) Ein nicht existierendes Rendering-Setup angeben, z.B. lib.parseFunc_FLUID:

<f:format.html parseFuncTSPath="lib.parseFunc_FLUID">{content}</f:format.html>

Lösung 1 und 2 ist von marcoseiler.de

3) TypoScript Konfiguration

Allgemeine Konfiguration und Zuweisung der Platzhalter

TS Setup

page.10 = FLUIDTEMPLATE
page.10 {
  partialRootPath = fileadmin/templates/fluid/partials/
  layoutRootPath = fileadmin/templates/fluid/layouts/
  variables {
    content < styles.content.get
    content_left < styles.content.get
    content_left.select.where = colPos=1
  }
}

In die Platzhalter „content“ und „content_left“ werden nun die Inhalte eingelesen, die vom Redakteur im Backend in den entsprechenden Spalten angelegt wurde. Gei „content_left“ lesen wir die Inhalte aus „Spaltennummer“ 1 ein, also die Inhalte aus Spalte „Linker Rand“, die weiter oben im Backend Layout definiert wurde.

Zuweisung BE Layout zu HTML-Template

Je nachdem, welches Backend Layout in den Seiteneigenschaften ausgewählt wurde, sollte ein anderes Seiten-Template verwendet werden. Dies geschieht mit diesen TypoScript-Anweisungen:

TS Setup

page.10.file.cObject = CASE
page.10.file.cObject {
  key.data = levelfield:-1, backend_layout_next_level, slide
  key.override.field = backend_layout
  default = TEXT
  default.value = fileadmin/templates/fluid/2cols.html
  2 = TEXT
  2.value = fileadmin/templates/fluid/1col.html
  3 = TEXT
  3.value = fileadmin/templates/fluid/popup.html
}

Standardmäßig wird dabei das 2-Spalten-Layout verwendet (dieses sollte deshalb auch auf der Root-Seite in zwei Select-Boxen für das Backend-Layout ausgewählt werden). Die Templates werden über die IDs der Backend-Layouts zugewiesen. In meinem Fall hat das 1-spaltige Backend-Layout die ID 2, das Popup-Backend-Layout die ID 3.

Optional: CSS Datei einbinden, abhängig von gewählen Layout

page.headerData.10 = CASE
page.headerData.10 {
  stdWrap.wrap = <link rel="stylesheet" type="text/css" href="path/to/css/|" media="all" />
  key.data = levelfield:-1, backend_layout_next_level, slide
  key.override.field = backend_layout
  default = TEXT
  default.value = layout_2col.css
  2 = TEXT
  2.value = layout_1col.css
  3 = TEXT
  3.value = layout_popup.css
}

Hinweis: Ich habe hier das Raute-Symbol (#) als Trennzeichen verwendet, da bei Verwendung einer Pipe (|) mein WordPress-Editor eine fehlerhafte Ausgabe erzeugt.

Optional: body-Tag mit Klasse auszeichnen

Für das Layout ist es oft nötig, dass man in CSS weiß, welches Layout aktuell gewählt ist. Deshalb kann man dem body-Tag je nach gewählten Layout eine andere Klasse geben:

TS Setup

page.bodyTagCObject = CASE
page.bodyTagCObject {
  stdWrap.wrap = < body class="|" >
  key.data = levelfield:-1, backend_layout_next_level, slide
  key.override.field = backend_layout
  default = TEXT
  default.value = layout-2col
  2 = TEXT
  2.value = layout-1col
  3 = TEXT
  3.value = layout-popup
}

Thema: TYPO3 | Kommentare (19)