web-dev-qa-db-ja.com

WPが私の<a>コンテナを気に入らないのはなぜですか?

最近私は、ショートコードが生成するすべての要素がタグで囲まれるような、いくつかのショートコードに取り組んでいます。残念ながらこれは望みどおりにレンダリングされていません、なぜならthe_contentのフィルタwpautop、あるいはあなたがショートコードや通常のコンテンツを表示するのに使っているものが何であれ。

セットアップ

以下のショートコードを作成したと想像してください。

<?php

function example_shortcode($atts, $content = null) {
    extract(shortcode_atts(
        array(
           'before' => '',
           'after' => '',
           'link' => '',
        ), $atts)
    );

    $before = (!empty($atts['before'])) ? '<div class="before">'.$atts['before'].'</div>' : '';
    $after = (!empty($atts['after'])) ? '<div class="after">'.$atts['after'].'</div>' : '';
    $link = (!empty($atts['link'])) ? ' href="'.$atts['link'].'"' : '';

    return '<a'.$link.'>'.$before.do_shortcode($content).$after.'</a>';
}
add_shortcode('example_shortcode', 'example_shortcode');

また、以下の内容のページを作成しました。

some text before the shortcode

[example_shortcode before="Welcome" after="Goodbye" link="#"]

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum

[/example_shortcode]

some text after the shortcode

テスト

デフォルトの優先度で wpautop フィルタを追加すると、出力は次のようになります。

<p>some text before the shortcode</p>
<a href="#"><div class="before">Welcome</div></p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<p><div class="after">Goodbye</div></a>
<p>some text after the shortcode</p>

あるいはremove_filter('the_content', 'wpautop');を追加すると、正しいHTMLも返します。

some text before the shortcode

<a href="#"><div class="before">Welcome</div>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum

<div class="after">Goodbye</div></a>

some text after the shortcode

しかし、例えばwpautopフィルタがより高い優先順位で追加された場合...

<?php
remove_filter('the_content', 'wpautop');
add_filter('the_content', 'wpautop', PHP_INT_MAX);

それから出力は次のようにすべてをめちゃくちゃに返します:

<p>some text before the shortcode</p>
<p><a href="#">
</a></p><div class="before"><a href="#">Welcome</a></div><a href="#">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<div class="after">Goodbye</div>
</a><p><a href="#"></a></p>
<p>some text after the shortcode</p>

問題と私の目標

一度開くだけで閉じる必要があるのに、なぜ<a>タグが複数回追加されるのですか?

これは私がレンダリングしたいHTMLであり、example_shortcode関数内の<a>タグを例えば<div>タグこれらのタグの出力が異なるのはなぜですか?

<p>some text before the shortcode</p>
<a href="#">
<div class="before">Welcome</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<div class="after">Goodbye</div>
</a>
<p>some text after the shortcode</p>
2
Fleuv

wpautop()は誰の気持ちも損なうことなくバスケットケースだと言っても差し支えないと思いますが、別の優先順位で削除して追加することはしないでください。実際の出力ではなく、壊れたhtmlを認識します。これには1回だけ<a>タグが含まれます。

通常の優先順位で作成された破損HTMLを修正するために、このコードをショートコードの内容に適用すると、ほとんどの問題が修正されます。

function cleanup_sc_content( $sc_content ) {
    $sc_content = force_balance_tags( $sc_content );
    $sc_content = preg_replace( '/<p>\s*+(<br\s*\/*>)?\s*<\/p>/i', '', $sc_content );
    return $sc_content;
}

これは、元のremove_empty_p()関数 Posted を@Michelleによって再利用することです(これは、@ mtinsley(github ninnypants、original Gist )によるものです)。

それを使うために、私は個人的にそれをフィルタとして追加するのではなく、ショートコードの内容に直接適用します。例えば:

return '<a' . $link . '>' . $before  
   . cleanup_sc_content( do_shortcode( shortcode_unautop( $content ) ) ) 
   . $after . '</a>';

shortcode_unautop()はショートコードの内容で実行されますが、wpautop()は実行されませんが、実際にはそうではありませんが)shortcode_unautop()ハックも必要です。しかしながら、wpautop()の絶え間ない強烈な「修正」と、当てはまるかどうかわからない、多くの未解決で紛らわしいバグ(長年にわたる)を考えると、この(そしてすべての)解決策は不安定になるでしょう。

2
bonger