Poprawka poprawki shortcodes w WordPressie

Niedawno miałem okazję tworzyć od podstaw skórkę do WordPressa, co dość szybko zmieniło się w proces wyszukiwania sposobów na obejście problemów spowodowanych założeniami jakimi kierowali się twórcy tego CMS. Jednym z kłopotów na które się natknąłem, była niedopracowana obsługa tzw. „shortcodes” w edytorze, spowodowana wstawianiem paragrafów do każdej nowej linii.

W skrócie, jeżeli w treści bloga wpiszemy przykładowo:

tekst 1
[shortcode]
tekst 2

WordPress przekształci to w kod html:

<p>tekst 1</p>
<p>wynik działania shortcode</p>
<p>tekst 2</p>

Ma to swój sens, ale tylko jeżeli wynikiem działania shortcode jest tekst lub kod, który powinien znaleźć się wewnątrz nowego paragrafu. W moim jednak przypadku, skróty generowały nowe elementy blokowe i umieszczanie ich wewnątrz tagu „p” dawało w wyniku wadliwy kod html:

tekst 1
[shortcode]
tekst 2
[/shortcode]
tekst 3

zmieniało się w:

<p>tekst 1</p>
<p><div class="xyz"></p>
<p>tekst 2</p>
<p></div></p>
<p>tekst 3</p>

Wtyczką na ratunek

Powyższy problem miała rozwiązać wtyczka „Shortcode Empty Paragraph Fix” z oficjalnego repozytorium WordPressa, z ponad 4000 aktywnych instalacji i 18 ocenami 5 gwiazdek. Jej sercem była prosta funkcja modyfikująca treść wpisu:

function shortcode_empty_paragraph_fix( $content ) {

    // define your shortcodes to filter, '' filters all shortcodes
    $shortcodes = array( 'your_shortcode_1', 'your_shortcode_2' );

    foreach ( $shortcodes as $shortcode ) {

        $array = array (
            '<p>[' . $shortcode => '[' .$shortcode,
            '<p>[/' . $shortcode => '[/' .$shortcode,
            $shortcode . ']</p>' => $shortcode . ']',
            $shortcode . ']<br />' => $shortcode . ']'
        );

        $content = strtr( $content, $array );
    }

    return $content;
}

add_filter( 'the_content', 'shortcode_empty_paragraph_fix' );

Z pozoru jest to rozwiązanie doskonałe, możemy określić które skróty będą poprawiane, obsługiwane są zarówno skróty otwierające jak i zamykające, dla każdego skrótu wywoływana jest tylko jeden raz funkcja strtr co powinno wpłynąć pozytywnie na wydajność. Jest tylko jeden minus… powyższa funkcja nie działa.

strtr nie jest tym czym się wydaje

Autor nie wziął pod uwagę sposobu działania strtr wywoływanego z parametrem w postaci tablicy. Okazuje się, że jeżeli dwie pary ciągów do podmiany będą dotyczyły tego samego fragmentu źródłowego, użyta będzie tylko jedna z nich. Na przykład:

<?php

$content = 'ala [kot] bela [kot] ala [kot test1 kot] test2';
var_dump($content);

$arr = array(
    '[kot' => '(kot',
    'kot] ' => 'kot) ',
);

$result = strtr($content, $arr);
var_dump($result);

$result = strtr($result, $arr);
var_dump($result);

da w wyniku:

string(46) "ala [kot] bela [kot] ala [kot test1 kot] test2"
string(46) "ala (kot] bela (kot] ala (kot test1 kot) test2"
string(46) "ala (kot) bela (kot) ala (kot test1 kot) test2"

Pierwsze strtr zamieniło „[kot” na „(kot” oraz „kot]” na „kot)”, ale w przypadku „[kot]” druga reguła już nie zadziałała. Konieczność ponownego wywołania funkcji na ciągu wynikowym powoduje, że wykorzystanie tablicy w tym przypadku traci cały sens z punktu widzenia wydajności rozwiązania.

Poprawka poprawki

Lepszym rozwiązaniem jest użycie kodu autorstwa maxxscho z GitHuba:

function shortcode_empty_paragraph_fix($content)
{  
    $array = array (
        '<p>[' => '[',
        ']</p>' => ']',
        ']<br />' => ']'
    );

    $content = strtr($content, $array);

    return $content;
}

add_filter('the_content', 'shortcode_empty_paragraph_fix');

Niestety, w tym przypadku kosztem braku możliwości wyboru listy obsługiwanych skrótów, co może w wyniku powodować, że paragrafy i znaki końca linii będą usuwane nawet w miejscach, gdzie byśmy sobie tego nie życzyli.


Opublikowano

w

przez

Tagi:

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *