WordPress: フィルターより前にショートコードを実行させる

検索のしかたがよくなかったのか、日本語での情報をうまく見つけることができませんでした。そこで WordPress Code: Earlier Shortcodes をほぼそのまま訳しつつ、ここに記しておきます。

問題

僕がひっかっかった問題も、そのページのはじめにあるのとほぼ同じでした。すなわち、WordPress のショートコードは優先順位(プライオリティ)が 11 であり、そのため wpautop()wptexturize() などデフォルトのフィルター群(デフォルトの優先順位は 10)の後に実行されることになります。

たとえば

これは適当な文です。

ここに [foobar]80's pop[/foobar] などと書いたとします。

これはまた適当な文です。

という文章を書いた場合、まず wptexturize() によって 80′s pop と変換されたものが ショートコード foobar に囲まれた内容として渡され、意図しない結果になることがあります。

解決策その1

まず思いついたのはフィルターの優先順位を下げてしまおうというものでした。ちょうど Solution to WordPress adding br and p tags around shortcodes と同じです。ショートコードの処理を書くあたりに

remove_filter( 'the_content', 'wpautop' );
remove_filter( 'the_content', 'wptexturize' );
add_filter( 'the_content', 'wpautop' , 12);
add_filter( 'the_content', 'wptexturize' , 12);

と書いてしまおうというものです。

当面の問題、すなわちショートコード foobar については、これで回避されましたが、ちょっと不安が残ります。WordPress のデフォルトが「ショートコードはフィルターの後」なのですから、他の人がそれを前提に作ったものを使ったときに問題が出るかもしれません[1]

解決策その2

そこでもうしばらく検索して、最初に紹介した WordPress Code: Earlier Shortcodes を見つけました。そこにあるサンプルコードを、コメントを適当に訳しながら再掲しますと、

// これは実際には何もしない。ダミー。
add_shortcode( 'foobar', '__return_false' );
 
// ショートコードの実際の処理
function foobar_run_shortcode( $content ) {
    global $shortcode_tags;
 
    // 現在のショートコード群をバックアップをとってから、すべて削除する
    $orig_shortcode_tags = $shortcode_tags;
    remove_all_shortcodes();
 
    add_shortcode( 'foobar', 'shortcode_foobar' );
 
    // ショートコードを実行 (直前の行で加えた当該のショートコードのみ)
    $content = do_shortcode( $content );
 
    // 元のショートコード群を復元する
    $shortcode_tags = $orig_shortcode_tags;
 
    return $content;
}
 
add_filter( 'the_content', 'foobar_run_shortcode', 7 );

解説

この関数は、まず登録されているショートコードの一覧が格納されている変数 $shortcode_tags を大域変数化し、それを別の変数にコピーし(後で復元させるため)、それからそれを空にします。これで登録されているショートコードは何もありません。

ここに当該のショートコードただひとつを登録し、do_shortcode() で 内容(content)に適用します。その後で、先ほど保存しておいたショートコード群を復元して登録し(ここで当該のショートコードは抹消されるので二重に適用されることはありません)ます。そしてdo_shortcode() の返り値の内容(content)を返します。

最後に、wptexturize() より前に実行されるように優先順位をつけて(1から9の値にします。ここでは 7 にします)、フィルターとして上記の関数を登録します。

感想

それにしてもなんだかまわりくどいなあと思いました。今回見つけた記事やそこに多くのコメントがあるように、ショートコードの優先順位を変更したいという需要があるのですから、登録時に自由に優先順位を設定できる関数が WordPress 本体にあってもいいように思います。

参照した記事の最も新しいコメントはつい最近のようですし、サンプルとほぼ同じコードが本体の持っているショートコード embed にも採用されているように、いまでも(いまのところ)、この方法がこの問題の解決策のようです。

  1. 丹念に読む気は起きませんが、ショートコードの優先順位を wpautop() より下げた経緯が ticket 6444 あたりにありそうです。

“WordPress: フィルターより前にショートコードを実行させる” への 1 件のフィードバック

コメントをどうぞ