Weaver II テーマ で Youtube を埋め込む

少し前の記事

Jetpack by WordPress.com プラグインで Youtube の画を埋め込んでいるのだけれど、説明どおりにやっても小さくできない。縦は縮むのに横幅はそのまま。別の環境で見るとまたちがうのだろうか。

と書いたけれど、原因がわかった。

youtube を埋め込むには、

  1. Weaver II テーマは独自にショートコード weaver-youtube を持っているので、これを使う。横幅は percent というパラメータで指定する。
  2. 上記を使わず、Jetpack by WordPress.com プラグインのショートコード youtube を使う。ただし Weaver II テーマで設定されているスタイルと干渉する。

のどちらかによる。はじめ (a)に気づいていなかったので (b)の方法にしていた。気づいたいま、どうするか。記事を書く際にテーマやプラグインに依存した記述をすると、そのテーマまたはプラグインを外したときに変なことになる可能性がある。将来 Weaver II テーマを使わなくなる可能性と Jetpack by WordPress.com プラグインを使わなくなる可能性を比べると、後者のほうが断然低そうなので、やはり (b)の記述のままにすることにした。

さてそうすると、どちらの方法でも youtube を埋め込む iframe には class="youtube-player" が指定されているのだが、 Weaver II テーマではそれに対するスタイルが

.youtube-player {
    width: 100%;
}

と設定されていたのであった。(a)の方法では、その上で画像の横幅を制御しているのであろう。そのまま (b)の方法を使うと、前に書いたように、w=320 のような横幅指定を付けてもそれが適用されない。

ここでは、記事の記述は(b)の方法にしたので、このスタイル指定をやめるため、Weaver II テーマの設定画面の advanced Options → <HEAD> Section の Custom CSS Rules に

.youtube-player {
    width: auto;
}

と書くことにした。これでうまくいくようになった。

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

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

問題

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

たとえば

これは適当な文です。

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

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

という文章を書いた場合、まず wptexturize() によって 80&#8242;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 あたりにありそうです。