Shortcodes mit gemischter Schreibweise in einem Artikel Schneller "Hack", um das Shortcodes-Parsen zu verbessern.

Über die “Shortcode-API” von Wordpress gibt es schon viele Artikel und Anleitungen. Auch über die verschiedenen Schreibweisen, die unterstützt werden:

  • [shortcode]
  • [shortcode attribut="wert" /]
  • [shortcode]Inhalt[/shortcode]

Interessant wird es nun aber, wenn man – so wie ich – einen Shortcode geschrieben hat, der sowohl in der “self-contained” (Variante 1 und 2) als auch als “enclosing” (Variante 3) Form vorkommen können soll. Verwendet man nämlich beides in dem gleichen Artikel, dann führt das zu unerwarteten Ergebnissen1.

Das Problem

In meinem Fall der Shortcode [link], mit dessen Hilfe ich auf Artikel oder Seiten linken kann. Dabei habe ich – faul wie ich nunmal bin – die Möglichkeit eingebaut, entweder nur [link to=”post_slug|ID”] zu schreiben oder [link to=”post_slug|ID”]Irgendein text, der statt dem Artikel- oder Seitentitel angezeigt werden soll, wobei ein %s mit dem Titel ersetzt wird [/link].

Das klappte auch alles soweit ganz gut, bis ich in einem Test-Artikel beide Varianten mischte2:

\{link to="erdbeer-tiramisu"]

\{link to="stroppy-me-in-concert"]Auftritt\{/link]

Das Resultat war ähnlich dem Folgenden:

\{link to="stroppy-me-in-concert"]Auftritt

wobei der Text zum Artikel “Erdbeer-Tiramisu” verlinkt war.

Nach stundenlanger Suche fand ich die Ursache im regulären Ausdruck, der die Shortcodes herausfiltert. Und da Ursachen finden immer der erste Schritt zur Lösung eines Problems ist, war nach ein bißchen ausprobieren und Dokumentation lesen die Lösung auch schon gefunden.

Die Lösung

Wie bei vielen Problemen, so ist auch hier die Lösung – so die Ursache erst einmal gefunden ist – verblüffend einfach.

In der Datei wp-includes/shortcodes.php einfach den regulären Ausdruck von

178
return '(.?)\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?)';

ändern in

178
return '(.?)\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:((?:.(?!\[\2))+?)\[\/\2\])?(.?)';

und schon kann man beide Varianten der Shortcodes für einen Tag in einem Artikel mischen und es funktioniert wie erwartet.

Dazu brauchte es nur einen negativen Lookahead, der auschließt, daß das Suchmuster passt, wenn im Inhalt des Shortcodes derselbe Shortcode noch einmal geöffnet wird3.

Einen Nachteil hat diese Lösung jedoch: Man ändert eine Kern-Datei von , d.h. man muss beim nächsten Aktualisieren die Änderung wieder einfügen. Ich habe (noch) keine Ahnung, wo oder wie man dem -Team Bugs melden kann, und bis ich das herausgefunden habe, werde ich diese Änderung wohl nach jeder Aktualisierung vergessen – und diesen Artikel wieder lesen :)


  1. Einfach mal ausprobieren. Alles was zwischen dem letzten self-contained Shortcode und dem schließenden Tag des nächsten enclosing Shortcode steht, wird als Inhalt des letzten self-contained Shortcode angesehen und so behandelt. 

  2. irgendwie verträgt sich Markdown und das Escapen von Shortcodes auch nicht so richtig, deshalb die “{” als Startzeichen. – vielleicht kümmer ich mich darum als nächstes ;) 

  3. Ganz genau: (.+?) wird zu (?:(.(?![\2)+?)), wobei (?![\2) der negative Lookahead ist. 

Erlaubtes HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">