Smarty und CiviCRM-Tokens - ein kleines Syntax - HowTo

CiviCRM nutzt die Template-Engine Smarty. Mit dieser können u.a. in E-Mails Texte und Daten personalisiert ausgegeben werden. Das lässt sich bei individuell gestalteten Anreden nutzen, aber theoretisch auch darüber hinausgehend. So könnte etwa ein bestimmtes Element eines Newsletters - z.B. eine Veranstaltungsankündigung - nur Empfängern in einem bestimmten Postleitzahlenbereich ausgeliefert werden.

Leider ist der Einsatz von Smarty nicht ganz einfach, und das Ganze ist - anders als andere Bereiche von CiviCRM - nicht gut dokumentiert. Daher geben wir hier einige grundsätzliche Hinweise und demonstrieren den Einsatz von Smarty-Syntax anhand einiger Beispiele.

Voraussetzungen
  1. Bitte beachtet, dass Smarty in der Datei civicrm.settings.php aktiviert sein muss!

  2. Außerdem gibt es momentan ein Problem, falls Ihr den CKEditor verwendet. Bei diesem werden nämlich beim Umschalten zwischen Quellcode und WYSIWYG-Ansicht Sonderzeichen fehlerhaft umgewandelt, und die Smarty-Syntax ist hinüber. Für dieses Problem haben wir einen Bug Report eingereicht, den man hier verfolgen kann.
    Ein Workaround ist, stattdessen einen anderen Editor, z.B. TinyMCE zu verwenden (Administration > Verwaltungskonsole > Voreinstellungen für die Anzeige).

Grundsätzliche Hinweise

Zunächst ist zu beachten, dass in den geschweiften Klammern zwei unterschiedliche Arten von Elementen stehen.

  • {contact.first_name} ist kein Smarty-Element, sondern ein CiviCRM-Token. Dieser wird von CiviCRM einfach aufgelöst, d.h. für jeden Empfänger (des Mailings oder des PDF-Briefs) mit den vorhandenen Daten aufgefüllt. Diese "Platzhalter" kann man im Mail-Editor einfach über "Platzhalter einfügen" einsetzen.

  • die weiteren Elemente, die ihr unten seht, sind eine einfache if-else-Anweisung in Smarty-Syntax. Eine allgemeine Einführung dazu gibt es hier.

Beim Erzeugen eines Mailings oder eines PDF-Briefs werden als erstes alle CiviCRM-Token mit dem Inhalten des jeweiligen Felds ersetzt werden (z.B. wird {contact.first_name} zu "Fabian"). Erst dann wird die Smarty-Logik angewendet, also beispielsweise "if-else-Bedingungen" geprüft.

Auch aus diesem Grund ist es ratsam, CiviCRM-Token vor der Ausgabe in eine Variable einzulesen und erst danach auszugeben, da sich sonst möglicherweise Syntaxfehler ergeben können. Das Einlesen erfolgt mit Hilfe von {capture} - eine in Smarty integrierte Funktion, die den Inhalt zwischen den öffnenden und schließenden Tags in eine Variable speichert, anstatt ihn auszugeben. Weitere Informationen dazu findet Ihr in der Smarty-Dokumentation.

Beispiel 1: Einfache "wenn-dann-Bedingung" 1

Folgende Syntax bewirkt, dass "Du heißt Fabian" ausgegeben wird, wenn im Feld "contact.first_name" "Fabian" steht. Andernfalls wird "Du heißt leider nicht Fabian sondern (Vorname des Kontakts)".

{capture assign=first_name}{contact.first_name}{/capture}
{if $first_name eq 'Fabian'}
      Du heißt Fabian
{else}
      Du heißt leider nicht Fabian sondern {$first_name}
{/if}

Beispiel 2: Einfache "wenn-dann-Bedingung" 2

Die "wenn-dann-Bedingung" funktioniert auch mit leeren Feldern. Folgende Syntax bewirkt, dass "Du bist arbeitssuchend" ausgegeben wird, wenn das Feld "contact.current_employer" leer ist, andernfalls wird "Du bist angestellt" ausgegeben

{capture assign=current_employer}{contact.current_employer}{/capture}
{if $current_employer eq ''}
      Du bist arbeitssuchend
{else}
      Du bist angestellt
{/if}

Beispiel 3: "Wenn-dann-sonst-Bedingung"

Folgende Syntax bewirkt, dass die passende Grußformel je nach Geschlecht gewählt wird. Wenn das Geschlecht nicht hinterlegt ist, wird eine allgemeine Grußformel ausgegeben.

{capture assign=gender}{contact.gender}{/capture}
{capture assign=first_name}{contact.first_name}{/capture}
{if $gender eq 'Mann'}
    Lieber
{elseif $gender eq 'Frau'}
    Liebe
{else}
    Liebe(r)
{/if}
{$first_name}

Verschachtelte "Wenn-dann-sonst-Bedingung"

Folgende Syntax bewirkt, dass die individuelle Grußformel (contact.postal_greeting) genutzt wird, wenn eine hinterlegt ist. Ansonsten wird die passende Grußformel je nach Geschlecht gewählt. Wenn das Geschlecht nicht hinterlegt ist, wird eine allgemeine Grußformel ausgegeben. Dafür wird eine verschachtelte if-else Anweisung eingesetzt

{capture assign=postal_greeting}{contact.postal_greeting}{/capture}
{capture assign=gender}{contact.gender}{/capture}
{capture assign=first_name}{contact.first_name}{/capture}
{if $postal_greeting eq ''}
    {if $gender eq 'Mann'}
        Lieber
    {elseif $gender eq 'Frau'}
        Liebe
    {else}
        Liebe(r)
    {/if}
    {$first_name}
{else}
    {$postal_greeting}
{/if}

Bild des Benutzers Martin Peth
Über den Autor

Martin Peth
Gründer und Gesellschafter bei SYSTOPIA

4 Kommentare
  1. anon
    19. Jan 2015

    Die hier verwendete Syntax fuer CiviCRM-Tokens innerhalb von Smarty-Ausdruecken ist leider *nicht* empfehlenswert: Gewisse Sonderzeichen in den Token-Inhalten fuehren bestenfalls zu Syntax-Fehlern, schlimmstenfalls zu Sicherheitsluecken. Korrekt ist es, die Tokens zunaechst explizit in Smarty-Variablen einzulesen, und erst dann in Smarty-Ausdruecken zu verwenden:

    {capture assign=first_name}{contact.first_name}{/capture}
    {if $first_name=='Fabian'}...{/if}

  1. Bild des Benutzers Björn Endres
    20. Jan 2015

    Das ist ein guter Einwand, aber auch nicht ganz richtig. Denn da die Tokens ja -wie beschrieben- vor dem Eingreifen von Smarty ersetzt werden, könnte man auch in Deinem Beispiel Syntaxfehler konstruieren, z.B.:

    {contact.first_name} = {/capture}

    Oder auch genauso Sicherheitslücken:

    {contact.first_name} = {/capture}{crmAPI var='result' entity='Contact' action='get'}{foreach from=$result.values item=Contact}{$Contact.display_name}{/foreach}{capture assign=egal}

    Ich gebe Dir aber recht, dass die Capture-Variante robuster ist. Wir werden mal schauen, ob wir den Artikel daraufhin überarbeiten.

  1. anon
    23. Feb 2015

    Grundsaetzlich sollte beim Ersetzen der CiviCRM-Tokens ein Smarty-Escaping stattfinden, das die Nutzung in Konstrukten wie {capture}{/capture} sicher macht -- *nicht* hingegen die Nutzung innerhalb von Smarty-Ausdruecken. Die Variante mit {capture} *sollte* also sicher sein.

    Natuerlich stellt sich die Frage, in wie weit das auch tatsaechlich konsequent umgesetzt ist... Ich habe das Mal eben getestet, und es funktioniert korrekt beim Versand von Emails (sowohl Mass-Mailings als auch "send email to contacts"), nicht hingegen bei "Print PDF letter". Oha.

  1. Bild des Benutzers Fabian Schuttenberg
    24. Feb 2015

    Wir haben die Syntax im Artikel überarbeitet - danke noch mal für den Hinweis, antrik.