Textpattern-Tags in Tags: Der gordische Knoten

19. Juni 2006

(English version? This way!)

Tags, die Textpattern zur Steuerung von Seitenvorlagen und anderen Funktionen verwendet, erhalten viele Informationen über ihre Attribute. Beispielsweise verwendet der Tag txp:section den Wert des Attributs title, um entweder den Titel oder den Namen einer Sektion auszugeben:

<txp:section title="1" /> [...]

Ebenso ist es einfach möglich, Textpattern-Tags als Attributwerte für HTML-Elemente zu verwenden. Oftmals ist es zu Beispiel nützlich, dem HTML- body einer Seite eine eindeutige Klasse zuzuordnen. Gerne leite ich solche Eigenschaften von der aktuellen Sektion der Website ab, die vom Tag txp:section ausgegeben wird:

<body class="<txp:section title="0" />"> [...]

Diese Verschachtelung sieht für einen XML-Puristen schon sehr seltsam aus und erfordert etwas Übung, damit zwischen den spitzen Klammern und den Anführungszeichen ein ausgewogenes Gleichgewicht herrscht. Funktionieren tut es trotzdem, da Textpattern seine Tags über ein recht einfaches “Suchen & Ersetzen”-Verfahren in die “echten” Werte umformt.

Ein gordischer Textpattern-Knoten

Richtig schlimm und für Textpattern nicht mehr entschlüsselbar sind Konstruktionen, die einen Textpattern-Tag als Attribut eines weiteren, äußeren Textpattern-Tags erfordern würden.

Beispiel: Eine E-Mail-Adresse soll aus dem benutzerdefinierten Feld #1 eines Artikels stammen. Eine nützliche Funktion für ein Website, in der mehrere Autoren Beiträge verfassen und eventuell ihre E-Mail-Adresse beim Beitrag anführen wollen. Der Autor könnte einfach im Benutzerfeld #1 seine E-Mail-Adresse eintragen (someone@domain.com) und der zugehörige Artikelbaustein würde an geeigneter Stelle für die Anzeige sorgen. Die naive Umsetzung wäre etwa so:

<txp:email email="" />

Leider unterbricht Textpattern seine Untersuchung der Tags beim ersten Auftreten von “/>” und fällt damit auf die Nase.

Tags in Tags

Die Umsetzung solcher “Tags in Tags” erfordert etwas PHP, den direkten Aufruf der Taghandler-Funktionen und die Anwendung von Basis-Wissen über die Methoden, mit denen Textpattern Attributwerte an diese Taghandlerfunktionen übergibt. Klingt kompliziert, lässt sich aber auf einige nachvollziehbare Schritte reduzieren:

Schritt 1: Löse von innen nach außen auf

Gemäß obigem Beispiel ist das innerste Textpattern-Tag txp:custom_field, das nächst-äußere txp:email. Weitere Verschachtelungen sind nach eben dieser Methode auflösbar.

Schritt 2: Baue eine PHP-Sequenz, die die Taghandler gemäß der festgestellten Reihenfolge aufruft

Die Taghandler-Funktionen tragen genau die Namen der Tags (ohne das vorangestellte txp:. Für txp:custom_field lautet der Name der Taghandler-Funktion also custom_field, für txp:emailemail. Attributwerte werden über Arrays von 'name' => 'wert'-Paaren übergeben.

Damit lässt sich also der innerste Teil so in PHP formulieren:

custom_field (array(
    'name' => 'custom1'
));

Mit dem Rückgabewert dieses innersten Teils bauen wir das Attribut für den äußeren Teil. Aus Gründen der Übersichtlichkeit benutzen wir eine Variable ($a) als Zwischenspeicher für die E-Mail-Adresse. Weitere Attribute werden über beistrichgetrennte 'name' => 'wert'-Paare angefügt. Die Reihenfolge ist beliebig.

$a = custom_field (array(
   'name' => 'custom1'
));
email (array(
    'email' => $a, 
    'linktext' => 'mail me'
));

Schritt 3: Stecke diese PHP-Sequenz in einen Baustein

Ein neuer Textpattern-Baustein vom Typ “misc” nimmt diesen PHP-Code auf und wird selbst wieder in Artikeln oder Artikel-Bausteinen via txp:output_form verwendet. Natürlich kann man dieses Schnipsel auch direkt in einen Artikelbaustein schreiben, falls die Übersicht nicht dagegen spricht. Das Ergebnis der gesamten Bemühungen wird über echo auf der Seite ausgegeben.

<txp:php>
$a = custom_field (array ('name' => 'custom1'));
echo email (array(
    'email' => $a, 
    'linktext' => 'mail me'
));
</txp:php>

Fertig!

Ein Fallstrick

Das einzig beachtenswerte an dieser Anleitung zur Rätsellösung sind Textpattern-Tags ohne Attribute. Diese Tags erfordern die Übergabe eines leeren Arrays als Parameter des Taghandlers:

<txp:php>
$a = section (array ());
</txp:php>

Irgendwas ist ja immer…

Falls die Resultate nicht den Erwartungen entsprechen, können Zwischenresultate über die Funktion dmp() auf der Seite ausgegeben werden. Damit ist es möglich, Erwartungen und tatsächliche Zustände zur Deckung zu bringen, zum Beispiel hier über den Inhalt der ersten Benutzerfelds, der in $a zu finden sein müsste:

<txp:php>
$a = custom_field ( array ('name' => 'custom1') );
dmp ($a);
echo email (array('email' => $a, 'linktext' => 'mail me'));
</txp:php>

Mit Hilfe dieser gezeigten Nachhilfe-Technik lassen sich recht flexible Ideen in Textpattern abbilden, die die Möglichkeiten der statischen Tag-Konstruktionen weit übersteigen und in einigen Fällen PHP-Programmierung für ein Plugin vermeiden helfen.

(Seil-Foto von sxc.hu)

Kommentare

  1. Finde ich gut, dass du es so ausführlich und mit Erläuterungen aufgeschrieben hast. Danke.

    Der Vollständigkeit halber möchte ich trotzdem erwähnen dass der Ansatz in der FAQ seit über einem halben Jahr kurz beschrieben ist:
    http://textpattern.com/faq/160/can-i-use-tags-within-tags.

    Der aktuelle Parser basiert auf regulären Ausdrücken – die sind zwar schneller, erlauben eben aber auch nur eine begrenzt mächtige Sprache zu definieren. IIRC hat Alex in Crockery bereits einen flexibleren Parser geschrieben (Typ-2/Kellerautomat, für die Informatiker unter uns), welcher immerhin das Schachteln von gleichnamigen Tags erlauben wird (was ebenfalls gelegentlich nachgefragt wird).

    Um Tag-Attribute flexibler aus dem Kontext zu “füttern” haben wir uns auch schon Gedanken gemacht. Das wird aber wohl noch ein bißchen länger dauern, und ggf. anders aussehen als Tags als Attribute… mal sehen.