Home » Blog » Wordpress » Probleme mit ShortCodes

Probleme mit ShortCodes

WordPress-Logo Seid WordPress 2.5 bietet das Blogging-System seinen Erweiterungen (Plugins) die neue Möglichkeit an,  mit so genannten ShortCodes Inhalte einfach und dynamisch zu modifizieren. Dazu muss eine Modifikations-Funktion auf einen entsprechenden ShortCode registriert werden, welcher dann automatisch aufgerufen wird. Ein ShortCode kann dabei noch zusätzliche Parameter definieren, die dann dieser Funktion zur Auswertung durchgereicht werden (Beispiel mit zwei Parameter: [ShortCode Param1=Wert1 Param2=Wert2]). Eines der berühmtesten WordPress-Erweiterungen, welche in der neusten Version diese Technologie einsetzt, ist die Gallery-Verwaltung NextGEN Gallery. Und mit ihrem Einsatz fällt ein kleiner Fehler in WordPress auf: ShortCodes kombiniert mit sehr langen Beiträgen führen bei der Anzeige gerne zu einem leeren Ergebnis.

Dies sieht sehr verdächtig nach einem Speicher-Problem aus. Doch wo genau tritt der Fehler auf und was kann man dagegen unternehmen? Ein kleiner Suchtrip durch den Quellcode von WordPress (zum Zeitpunkt dieses Artikels in der Version 2.7 ) zeigte bald, dass der Inhalt einer meiner langen Artikel in der Funktion wpautop() in der Datei ./wp-includes/formatting.php verloren ging. Und zwar genau in der vorletzte Zeile der Funktion:

$pee = preg_replace('/<p>\s*?(' . get_shortcode_regex() . ')\s*<\/p>/s', '$1', $pee); // don't auto-p wrap shortcodes that stand alone

(WordPress 2.7, Datei formatting.php, Funktion wpautop(), Zeile 153)

Diese Funktion sorgt dafür, dass vor der Ausgabe der Beiträge Zeilenumbrüche in HTML-Zeilenumbrüche (<br />) und HTML-Paragraphen (<p />) umgewandelt werden. Sie wird vor der Ersetzung der ShortCodes aufgerufen. Die letzte Ersetzung sucht nun allein stehende ShortCodes und entfernt mögliche (automatisch hinzugefügte) Paragraphen um diese. Die hier aufgerufene Methode get_shortcode_regex() liefert dabei das Suchmuster für die definierten ShortCodes zurück. Diese befindet sich in der Datei ./wp-includes/shortcodes.php ab der Zeile 165. Der hier zurück gelieferte reguläre Ausdruck sucht nach einem Muster in der folgenden Form:
WP 2.7 RegEx In diesem Ausdruck werden zwei nicht-gierige (non-greedy, lazy) Quantoren eingesetzt. Dies bedeutet, es wird sehr viel Backtracking betrieben: die RegEx-Engine überspringt im ersten Schritt die Zeichen, welche auf solche nicht-gierigen Quantoren passen, da ja an dieser Stelle versucht wird, so wenig wie möglich einzufangen. Trotzdem merkt sich die Engine, wo sie notfalls nachschauen muss, falls der ganze restliche Text so erstmal nicht in das Suchmuster passt. Der “ganze Rest” bei großen Beiträgen mit mehreren nicht-gierigen Quantoren kann ganz schön viel sein, was die Historie gerne anwachsen lässt. Wir dürfen nicht vergessen: die RegEx-Engine geht am Ende nach und nach wieder ein Schritt zurück und prüft erneut nach, ob sie ein Ergebnis findet (Backtracking). Um den Aufwand zu minimieren, bietet es sich an, den zu überprüfenden “Rest” lokal einzuschränken. In unserem Fall wird der Zeichenbereich der Parameterpaare mit dem Endzeichen “]” eines Tags begrenzt. Ändern wir nun den roten Abschnitt (.*?) zu ([^\]]*?), trennen wir somit die Non-Greedy-Bereiche (Parameterpaare und mögliche Zwischeninhalte) und minimieren den Aufwand und somit den Speicherverbrauch. Unser überlanger Artikel müsste wieder erscheinen.

Mit einer kleine Schönheitsoperation können wir noch die (in meinen Augen) unnütze grüne, nicht-einfangende Klammerung um den eingefangenen optionale Schrägstrich entfernen: (?:(\/))? zu (\/)?. Die modifizierte Methode get_shortcode_regex() sieht nun wie folgt aus:

function get_shortcode_regex() {
    global $shortcode_tags;
    $tagnames = array_keys($shortcode_tags);
    $tagregexp = join( '|', array_map('preg_quote', $tagnames) );

    return '\[('.$tagregexp.')\b([^\]]*?)(\/)?\](?:(.+?)\[\/\1\])?';
}

(WordPress 2.7, Datei shortcodes.php, Funktion get_shortcode_regex(), Zeile 165)

(Problems in Wordpress with long posts and plugins like NextGEN Gallery)

Matthias Brusdeylins

Referenzen auf diesen Beitrag

smilkobuta
(25. Januar 2009)

Kommentare

1
25. Januar 2009 um 16:52 Uhr

Very Thanks to you!!!
I finally understood the source of this problem and problem itself.
I can’t read German but your comment image is very easy to understand.

Danke schön!!

2
25. Januar 2009 um 17:57 Uhr

I report your code to WordPress Trac
http://trac.wordpress.org/ticket/8962

3
27. Januar 2009 um 00:15 Uhr

Thanks for reporting this bug to WP Trac. I hope they understand, that they have to divide the two Non-Greedy-Char-Areas (in our example on the first square bracket “]” – red text). So the engine needs less backtrackings and in this case less memory…
that’s all… :-)

4
16. Juni 2009 um 21:19 Uhr

Auch in WordPress 2.8 ist der Fehler weiterhin vorhanden.
Hier liegt der Speicher-Fresser ebenfalls in der nicht-gierigen Klammerung. Die letzte Zeile in der Funktion get_shortcode_regex() lautet hier nun korrigiert:
return '(.?)\[('.$tagregexp.')\b([^\]]*?)(\/)?\](?:(.+?)\[\/\2\])?(.?)';

Das Ticket ist weiterhin offen:
http://core.trac.wordpress.org/ticket/8553

WP 2.9 soll es richten… dabei ist es sooo einfach…

5
21. November 2009 um 00:02 Uhr

In Wordpress 2.8.6 besteht das Problem weiterhin. Der Fix oben (Austausch der RegEx-Zeile) geht aber auch hier und muss nach dem Update wieder durchgeführt werden…

6
23. Dezember 2009 um 23:49 Uhr

Mit Wordpress 2.9 ist dieses Problem noch größer geworden. Der hier beschreibene Fix reicht wohl nicht mehr aus. Da unter WP 2.9 auch mein Theme nicht mehr funktioniert (warum auch immer ?!), werde ich mich diesem Thema wohl erst ab WP 3.0 annehmen. Dann mit einem komplett überarbeiteten Theme.

Ihre Meinung zählt

* Pflichtfeld. eMail-Adresse bleibt unveröffentlicht, wird aber für das Gravatar-Bild herangezogen.

Senden