Eigenes Custom Form Element für tx_form-Extension – Typo3 v8

How-To für das Erstellen eines Custom Form Elements für die tx_form-Extension unter Typo3 v8.

Falls man ein Custom Form Element erstellen möchte, haltet euch an das How-To. Für detaillierte Informationen und die Dokumentation zur ext:form besucht: https://docs.typo3.org/typo3cms/extensions/form/Index.html

Außerdem haben wir eine „Anleitung für Dummies und Normalsterbliche, die einfach einen Job zu erledigen haben“ erstellt – eine Kurzfassung mit farblicher Kennzeichnung und einem simplen Online-Generator.

weiterlesen

Datei-Upload in eigenem Typo3 Backend Module

Zum Upload einer Datei im Backend oder Frontend von Typo3 8+ hilft die ExtendedFileUtility mit ein paar schönen Methoden.

Für Suchmaschinen: Upload einer Datei in eigenem Backend-Module von Typo3. Upload file in typo3 backend module. File-Upload Typo3 backend, move_uploaded_file() in Mod-Controller. Typo3 ExtendedFileUtility upload example. TYPO3\CMS\Core\Utility\File\ExtendedFileUtility::init(). Upload files in TYPO3 from Frontend. Datei vom Frontend hochladen und im Controller an Ort bewegen. Typo3 upload file data. f:form.upload nutzen zum Upload einer Datei aus dem Backend oder Frontend.

weiterlesen

Extbase/Fluid ViewHelper für TCA Tabellen-Wizard (tablewizard) in eigener Extension nutzen

Problem: Man möchte in einer eigenen Extension den Tabellen-Wizard für ein TCA-Feld nutzen und diese dann per css_styled_content in einem Fluid-Template ausgeben lassen. Leider konnte ich keinen ViewHelper dafür finden und auch die ersten Verdächtigen z.B. über so etwas wie f:format.html parseFuncTSPath =“tt_content.table.20″ scheiterten.

Für Suchmaschinen: tca tablewizard viewhelper für tabellen. Eigener ViewHelper für tablewizard Daten Typo3. Parse tablewizard data in fluid template. tablewizard String in Tabelle konvertieren in eigener Extension. Tabellendaten in Typo3 Fluid ViewHelper umwandeln. Konvertieren von Daten aus dem Tabellen-Assistenten für Typo3. tablewizard in eigener Extension nutzen und in Fluid per css_styled_content parsen lassen.

Table-Wizard im TCA nutzen
Dazu nutzt man im TCA das Script wizard_table.php:

'tabellen_daten_feld' => array(
   'label' => 'Lebenslauf',
   'l10n_mode' => 'mergeIfNotBlank',
   'config' => array (
      'type' => 'text',
      'cols' => '30',   
      'rows' => '5',
      'default' => '',
      'wizards' => array(
         '_PADDING' => 2,
         'list' => Array(
            'notNewRecords' => 1, 
            'type' => 'script',
            'title' => 'Table wizard',
            'icon' => 'wizard_table.gif',
            'script' => 'wizard_table.php',
            // So kann die Option "kleine Felder" automatisch deaktiviert werden
            // 'script' => 'wizard_table.php?TABLE[textFields]=0',
            'params' => array(
               'xmlOutput' => 0
            )
         ),
      ),
   ),
),

ViewHelper für das Rendern der Tabelle
Der ViewHelper nutzt css_styled_content um die per Zeilenumbruch und mit dem Pipe-Symbol (|) getrennte Spalten und Zeilen in eine Tabelle umzuwandeln.

registerArgument('table', 'string', 'Die Tabellen-Daten, Delimiter ist das Pipe-Symbol', false, null);
      $this->registerArgument('layout', 'string', 'Die Zahl, die an der Klasse contenttable-XX erscheint', false, null);
   }

    /**
     * Rendert die Tabelle mit csc_styled_content
     */

    public function render() {

      if (!$this->arguments['table']) {
         $this->arguments['table'] = html_entity_decode($this->renderChildren());
      }
      
      $this->cscController->cObj = $this->configurationManager->getContentObject();
      $this->cscController->cObj->data = $this->arguments;

      return $this->cscController->render_table( null, array('field'=>'table') );
      
      
    }
}
?>

Der ViewHelper kann so eingesetzt werden:
Dabei kann unter „layout“ eine Zahl angegeben werden, die bei an der Tabelle als z.B. class=“contenttable-2″ erscheint.

{namespace VH=Pfad\ZuDeinen\ViewHelpers}

{tabellen_daten_feld}



{VH:table(layout:2,table:tabellen_daten_feld)}

Multiple YouTube Videos auf Seite in iFrame andere anhalten / stoppen

Problem: Man hat auf einer Seite mehrere YouTube Videos als iFrame eingebunden. Die Videos lassen sich aber parallel starten und dadurch laufen alle Videos gleichzeitig. Dieses Script stoppt alle anderen Videos auf der Seite automatisch, wenn eines der Videos gestartet wird:

Für Suchmaschinen: youtube alle videos stoppen wenn ein video startet, stop all iframes youtube videos when one video starts. Andere Videos anhalten, wenn ein Video läuft. Automatisch alle YouTube Filme anhalten wenn neues Video play gedrückt wird. Immer nur ein Video abspielen in YouTube iFrame auch wenn mehrere Videos auf der gleichen Seite eingebunden wurden.

(function ($) {
   $(function () {

      var tag = document.createElement('script');
      tag.src = "https://www.youtube.com/iframe_api";
      tag.type='text/javascript';
      $('body').append(tag);
   
      $('iframe[src*="youtube"]').each(function(){
         var $me = $(this);
         var src = $me.attr('src');
         if (src.indexOf('enablejsapi=1') == -1) {
            $me.attr({src: src + (src.indexOf('?') == -1 ? '?' : '&') + 'enablejsapi=1'});
         }
      });
   
      window.onYouTubeIframeAPIReady = function () {
   
         var playerCurrentlyPlaying = null;
         var player_cnt = 0;
         
         $('iframe[src*="youtube"]').each(function(){
            
            var $me = $(this);
            var player_id = $me.attr("id");
            
            if (!player_id) {
               player_id = "ytpl-"+(player_cnt++);
               $me.attr({id:player_id});
            }
            
            var player = new YT.Player( player_id, { 
               events: {   
                  'onReady': function () {},
                  'onStateChange': function (event) {
         
                     if (event.data == YT.PlayerState.PLAYING) { 
                        if (playerCurrentlyPlaying && playerCurrentlyPlaying != $me.data().player) {
                           playerCurrentlyPlaying.pauseVideo();
                        }
                        playerCurrentlyPlaying = $me.data().player;
                     }         
                  }
               }   
            });
            
            $me.data({player:player});
         });   
      }
   
   });
})(jQuery);

Deutscher Paket Dienst (DPD) SOAP Schnittstelle mit PHP nutzen um Versandetikett als PDF zu generieren

Hier ein schnelles Beispiel, wie die per PHP SoapClient() und DPD-WSDL-Schnittstelle ein Versand-Etikett als PDF generiert werden kann.

Für Suchmaschinen: PHP SOAP-Header für Authentifizierung, authenticate SOAP-Header, DPD-Api Versandetikett generieren, Generate DPD Label, DPD parse SOAP response, Fatal error: Uncaught SoapFault exception: [soap:Server] Fault occurred while processing. in getLabel.php:107 Stack trace: #0 getLabel.php(107): SoapClient->__call(’storeOrders‘, Array) #1 getLabel.php(107): SoapClient->storeOrders(Array).

getAuth(array(
      'delisId'          => 'your-Id',
      'password'         => 'your-Password',
      'messageLanguage'   => 'de_DE'
   ));
   
   // ...und das Token merken
   $auth = $res->return;
   
   
   // Jetzt das Label generieren:
   
   $c = new SoapClient('https://public-ws-stage.dpd.com/services/ShipmentService/V3_1?wsdl');
   
   $token = array(
      'delisId'         => $auth->delisId,
      'authToken'         => $auth->authToken,
      'messageLanguage'   => 'de_DE'
   );
   
   // Set the header with the authentication token
   $header = new SOAPHeader('http://dpd.com/common/service/types/Authentication/2.0', 'authentication', $token);
   $c->__setSoapHeaders($header);
   
   try {
      $res = $c->storeOrders( array
         (
            "printOptions" => array(
               "paperFormat" => "A4",
               "printerLanguage" => "PDF"
            ),
            "order" => array(
               "generalShipmentData" => array(
                  "sendingDepot" => $auth->depot,
                  "product" => "CL",
                  "mpsCompleteDelivery" => false,
                  "sender" => array(
                     "name1" => "Sender Name",
                     "street" => "Sender Street 2",
                     "country" => "DE",
                     "zipCode" => "65189",
                     "city" => "Wiesbaden",
                     "customerNumber" => "123456789"
                  ),
                  "recipient" => array(
                     "name1" => "John Malone",
                     "street" => "Johns Street 34",
                     "country" => "DE",
                     "zipCode" => "65201",
                     "city" => "Wiesbaden"
                  )
               ),
               "parcels" => array(
                  "parcelLabelNumber" => "09123829120"
               ),
               "productAndServiceData" => array(
                  "orderType" => "consignment"
               )
            )
         )
      );
   } catch (SoapFault $exception) {
      echo $exception->getMessage();
      die();
   }
   
   // Et voilà!
   
   header('Content-type: application/pdf');
   echo $res->orderResult->parcellabelsPDF;
?>

direct_mail_subscription / real_url: Kurze URLs in Opt-In Bestätigungsmails von Newsletter-Anmeldung

Mit folgendem Trick bekommt man in die Bestätigungsmails von direct_mail_subscription eine kürzere URL. Hintergrund des Ganzen: Die URLs sind in den E-Mails teilweise so lang, dass sie umbrechen, was bei manchem Benutzern zu unvollständigen URLs bei Klick auf den Link führt.

Per Default sieht der Link in dem Subpart „EMAIL_TEMPLATE_CREATE_SAVED“ der Opt-In-Mail so aus:

http://www.beispiel.de/pfad/zu/seite.html?1=1&cmd=setfixed&sFK=approve&rU=3919&fD%5B_FIELDLIST%5D=uid&fD%5Bhidden%5D=0&aC=12732843

Schöner wäre es z.B. so:

http://www.beispiel.de/opt/nl/a/3919/12732843/0/0/

Folgende Schritte zu einer kurzen URL:

1. In den Seiteneigenschaften der Opt-In-Seite unter „Pfadsegment für untergeordnete Seiten“ einen kurzen Begriff eingeben, im Beispiel hier „opt“ und das Häkchen vor „Den gesamten Pfad überschreiben“ setzen.

2. In der typo3conf/realurl_conf.php folgende neue Regel für die postVarSets definieren:

'nl'     =>   array(
    array(   'GETvar'     => 'sFK', 
        'valueMap'    => array(
          'a'  => 'approve',
          'd' => 'DELETE'
        ),
      ),
    array( 'GETvar'   => 'rU', ),
    array( 'GETvar'   => 'aC', ),
    array(   'GETvar'   => 'cmd', 
        'valueMap'    => array(
          'setfixed'  => 'setfixed'
        ),
        'valueDefault'  => 'setfixed',
      ),
    array(   'GETvar'   => 'fD[_FIELDLIST]',
        'valueMap'  => array(
          'uid'    => 'uid'
        ),
        'valueDefault'  => 'uid',
      ),
    array( 'GETvar'   => 'fD[hidden]',
        'valueMap'  => array(
          '0'      => '0'
        ),
        'valueDefault'  => '0',
      ),
),

3. In dem Mail-Templates folgende Links für Bestätigung/Abmeldung verwenden:

Bitte klicken Sie auf diesen Link um die Anmeldung fertig zu stellen:
###THIS_URL###opt/nl/a/###FIELD_uid###/###SYS_AUTHCODE###/0/0/

Falls Sie keinen Newsletter möchten, klicken Sie hier:
###THIS_URL###opt/nl/d/###FIELD_uid###/###SYS_AUTHCODE###/0/0/

TemplaVoila-Field in TypoScript auslesen

Für Suchmaschinen, Phrasen nach denen ich selbst gesucht habe: „per ts auf tv field zugreifen“, Per TypoScript auf TV Feld zugreifen, TV-Feld per TypoScript auslesen. Feldwert von TemplaVoila in HMENU verwenden. Auf ein Datenfeld in TV per TS zugreifen. Mit Typoscript auf Felder eines FCE zugreifen. Zugriff auf TV aus Typoscript.

Aufgabe: Der Redakteur soll bei den Seiteneigenschaften ein Icon auswählen können, das vor dem Menüpunkt dargestellt wird. In TemplaVoilà wurde dazu bei einem Seitentemplate ein Feld angelegt (field_navi_icon) vom Typ „Auswahlliste“. Das Feld wird nicht gemappt, sondern ist später einfach nur eine Auswahlliste unter den Seiteneigenschaften einer Seite. Die Werte dieser Liste sind z.B.

select

  
    Default Icon
    
  
  
    Palme (icon-1)
    icon-1
  
  
    Segelboot (icon-2)
    icon-2
  
  
    Foto (icon-3)
    icon-3
  
  
  
    Kein Icon (no-icon)
    no-icon
  


Da mir leider keine Möglichkeit bekannt ist, direkt per TypoScript auf ein bestimmtes Feld von TemplaVoilà zuzugreifen, schreiben wir dazu eine kleine benutzerdefinierte Funktion. Die Datei unter „fileadmin/scripts/class.userfunctions.php“ speichern:

pi_loadLL();
    $this->pi_setPiVarDefaults();
    $this->pi_initPIflexForm();

    $def = array(  'field'      => 'tx_templavoila_flex',
            'flex_data'     => 'field_content', 
            'sheet_pointer' => 'sDEF', 
            'lang'       => 'lDEF', 
            'value_def'   => 'vDEF',
            'pid'      => $GLOBALS['TSFE']->id 
          );
    
    if ($conf['pid.']) {
      $conf['pid'] = $this->cObj->cObjGetSingle($conf['pid'], $conf['pid.']);
    }
    
    foreach ($def as $k=>$v) if (!$conf[$k]) $conf[$k] = $v;
    
    if ($conf['pid']) {
      $flex_array = t3lib_div::xml2array($this->cObj->TEXT(array('data'=>'DB : pages : '.$conf['pid'].' : tx_templavoila_flex')));
    } else {
      $flex_array = t3lib_div::xml2array($this->cObj->data[''.$conf['field'].'']);
    }
    $tv_field = $this->pi_getFFvalue($flex_array, $conf['flex_data'], $conf['sheet_pointer'], $conf['lang'], $conf['value_def']);
    
    return $tv_field;
  }

}
?>

Die benutzerdefinierte Funktion binden wir jetzt per TypoScript-Setup ein, damit wir später darauf zugreifen können:

page {
   includeLibs.myUserFuncs = fileadmin/scripts/class.userfunctions.php
}

Per TypoScript wird ein „normales“ HMENU/TMENU aufgebaut, allerdings mit dem kleinen Zusatz, das Feld in TemplaVoilà auszulesen und in das li-Tag der Navi als Klasse mit einzubauen:

lib.navi_main = HMENU

lib.navi_main {
  
  entryLevel = 1
  
  special = directory
  // Dieser Wert muss natürlich angepasst werden:
  special.value = 67
  
  wrap = 
    |
1 = TMENU 1.expAll = 1 1.noBlur = 1 1.wrap = | 1.NO = 1 1.NO { before.cObject = LOAD_REGISTER before.cObject.navi_icon.cObject = USER before.cObject.navi_icon.cObject { userFunc = user_functions->get_tv_field flex_data = field_navi_icon pid = TEXT pid.field = uid } stdWrap.wrap = | wrapItemAndSub =
  • |
  • |*|
  • |
  • |*|
  • |
  • wrapItemAndSub.insertData = 1 ATagParams.dataWrap = class="lv-0" } 1.ACT < .1.NO 1.ACT { stdWrap.dataWrap = | wrapItemAndSub =
  • |
  • |*|
  • |
  • |*|
  • |
  • ATagParams.dataWrap = class="lv-0 active" } 1.CUR < .1.ACT 1.CUR { stdWrap.dataWrap = | wrapItemAndSub =
  • |
  • |*|
  • |
  • |*|
  • |
  • ATagParams.dataWrap = class="lv-0 selected" } }

    Das Ergebnis ist ein Menü, das im HTML-Quelltext z.B. so aussieht:

    
    

    Jeder Menüpunkt hat den Feld-Wert aus TemplaVoilà als Klasse angehängt bekommen. Die zusätzliche Angabe der Ziel-pid als Klasse „pid-{uid}“ finde ich ebenfalls sehr praktisch. Alles weitere ist Sache von CSS. Dort nutze ich das span-Element z.B. zur Darstellung des Icons als Hintergrundbild.

    Typo3 Formhandler, SwiftMailer, PowerMail oder direct_mail sendet keine Mails

    Merkhilfe und Checkliste falls Formhandler keine Mails versendet. Ich fange tief im Eingemachten an, weil mich das Problem eben bis in das Server-Betriebssystem und die Konfigurationsdateien von Ubuntu getrieben hat. Für Suchmaschinen: Ubuntu -f Parameter, Formhandler Return-Path overwritten by postfix, postfix falschen Absender, postfix ignoriert From-Header in php-Mail-Befehl, From-Header wird von Postfix überschrieben

    Erst mal einen kleinen Test machen um zu prüfen, wo das Problem zu suchen ist. Je nach Server-Konfiguration kann es sein, dass eine gültige From-Angabe im Header des mail()-Befehls zwingend ist, oder dass sie per -f-Parameter übergeben werden muss. Folgendes PHP-Script auf den Server spielen und testen, ob Mails grundsätzlich über den php-Befehl mail() versendet werden:

    $header = 'From: webmaster@example.com'."\r\n".'Reply-To: webmaster@example.com'."\r\n".'X-Mailer: PHP/' . phpversion();
    $ok = mail ( "deine@email.de" , "das ist ein Test" , "Test", $header );
    

    Wenn die Mail ankam: Es muss irgendwas einfaches sein. Dazu schreibe ich später einen Beitrag 😉

    Wenn die Mail nicht ankam: Zuerst SPAM-Ordner prüfen! Auch dort nichts? Dann die Zeile mit dem mail() oben durch den 5. undokumentierten -f-Parameter ergänzen:

    $ok = mail ( "deine@email.de" , "das ist ein Test" , "Test", $header, "-f deine@email.de" );

    Die E-Mail-Adresse muss eine gültige (und dem Server bekannte) E-Mail-Adresse sein. Bei z.B. HostEurope ist das die E-Mail, die unter „Einstellungen -> Skripte -> Standard-E-Mail-Adresse“ zwingend im KIS angegeben sein muss.

    Wenn die E-Mail jetzt angekommen ist, dann liegt das an der Server-Einstellung. Dazu habe ich zwei Lösungen gefunden, eine bleibt eher Anwendungsseitig und zwingt Typo3 beim Aufruf von mail() noch den -f-Parameter zu verwenden. Die andere Lösung geht ins Eingemachte und setzt den Parameter zwingend für Apache / PHP und Postfix.

    Hilfreich sind übrigens auch immer die Logfiles von Postfix, die man unter var/log/mail.info findet. Wenn dort immer „OK“ steht, aber die Mails trotzdem nicht versendet wurden, ist man mit dem -f-Parameter auf der richtigen Spur.

    Lösung 1: Im Formhandler-Setup und der localconf.php

    1. In der typo3conf/localconf.php diese Zeile ergänzen:

    $TYPO3_CONF_VARS['SYS']['forceReturnPath'] = '1';

    2. In der Setup der Formhandler-Konfiguration darauf achten, dass die return_path-Angabe existiert. Als return_path die gleiche Angabe wie beim -f-Parameter verwenden.

    finishers {
       2.class = Tx_Formhandler_Finisher_Mail
       2.config {
          admin {
             ...
             return_path = deine@email.de
             ...
          }
          user {
             ...
             return_path = deine@email.de
             ...
          }
       }
    }

    Lösung 2: Postfix und php.ini

    1. Die Postfix-Konfiguration bearbeiten unter etc/postfix/main.cf

    myhostname = domainname.de

    2. In der etc/php5/apache2/php.ini den Absender für sendmail_path ergänzen:

    sendmail_path = /usr/sbin/sendmail -t -i -fwww-data@eswe-verkehr.de

    3. Postfix und Apache rebooten per Terminal-Befehl

    # sudo /etc/init.d/postfix restart
    # sudo /etc/init.d/apache2 restart

    Sollte das nicht reichen, hilft evtl. der Abschnitt „Mail“ in diesem speziellen Beitrag:
    http://labor.99grad.de/2016/10/03/installation-typo3-unter-ampps/

    Ansatz 3: Typo3 4.7 SwiftMailer

    Bei manchen Servern hatten wir das Problem, dass der seit Typo3 4.7 implementierte SwiftMailer Ärger machte. Leider fehlt seit 4.7 die Möglichkeit über „substituteOldMailAPI=0“ auf den alten Mail-Befehl umzuschalten.
    Folgender Test ist für dieses Problem typisch: Im Install-Tool unter „Grundkonfiguration“ gibt es einen Abschnitt, bei dem man sich eine Testmail schicken lassen kann. Wenn diese Mail nicht ankommt (was wir bei den Virtual Server Paketen von HostEurope mit PowerMail und direct_mail_subscription hatten) liegt es wieder an dem -f Parameter, der in der localconf.php so festgelegt werden muss:

    ## Für HostEurope V-Server: Problem, das sonst direct_mail_subscription / powermail / Testmail aus dem Install-Tool nicht funktioniert haben 
    $TYPO3_CONF_VARS['MAIL']['defaultMailFromAddress'] = 'hier@die-email.de';
    $TYPO3_CONF_VARS['MAIL']['defaultMailFromName'] = 'Dein Name';
    $TYPO3_CONF_VARS['MAIL']['transport'] = 'sendmail';
    $TYPO3_CONF_VARS['MAIL']['transport_sendmail_command'] = '/usr/sbin/sendmail -t -f hier@die-email.de';
    

    Der -f-Parameter unter „transport_sendmail_command“ muss bei HostEurope genau der Einstellung für die „Standard-E-Mail“ unter „Webpaket -> Konfiguration -> Skripte“ im KIS entsprechen.

    Problem mit htmlSpecialChars in Typoscript

    Seltsames Phänomen. Folgendes Typoscript sollte eigentlich die Headline eines Inhaltselementes für TemplaVoilà zur Verfügung stellen. Allerdings greift die htmlSpecialsChars-Option nicht. So werden Sonderzeichen wie das „&“-Zeichen nicht richtig in &amp; umgewandelt.

    Das hier hat NICHT funktioniert:

    lib.fce_header = TEXT
    lib.fce_header {
       value = {register:tx_templavoila_pi1.parentRec.header}
       insertData = 1
       htmlSpecialChars = 1
    }	
    

    Das hier war der Trick, mit dem es dann funktionierte:

    lib.fce_header = TEXT
    lib.fce_header {
       stdWrap.dataWrap = {register:tx_templavoila_pi1.parentRec.header}
       htmlSpecialChars = 1
    }	
    

    Extension für PDF download Statistik Tracking in Typo3 (dbdownloadtracker)

    Wir haben gestern unsere Typo3-Extension ins TER hochgeladen, die sich sehr leicht installieren läßt und zentral das Tracking der Downloads von PDF und ZIP Dateien ermöglicht. Die Statistiken werden in einer übersichtlichen Tabelle dargestellt, die sich zeilenweise oder vollständig „Nullen“ läßt um die Statistik zurückzusetzen.

    Die Downloads können nach Seiten im Seitenbaum und Datum gefiltert werden. Schöner Nebeneffekt: Falls Google Analytics per _gaq auf der Seite installiert ist, werden die Statistiken auch direkt an Ananlytics gesendet und können dort eingesehen werden.

    PDF Download Tracker (dbdownloadtracker)

    Für Suchmaschinen: Tracking von PDF Downloads in Typo3, Analytics PDF Typo3, Download Counter Typo3, Zahl der Downloads Statistik Typo3, Extension zum Zählen der PDF-Downloads, Wie oft wurde ein PDF geladen? Zahl der Datei-Downloads in Typo3? aw_stats PDF download