WordPress のショートコードは、記事本文の中に [gallery] のように書けば自動で展開されます。ところが、テーマの single.php や page.php などの PHP テンプレートに直接ショートコードの文字列を書いても、そのままでは展開されず、ただの文字として表示されてしまいます。そこで使うのが do_shortcode() です。この記事では、PHP テンプレートの中でショートコードを実行して展開する方法を、初心者〜中級者の方に向けて、シグネチャ・戻り値の扱い・属性や変数の渡し方・存在チェックまで具体的なコードで解説します。
目次
テンプレートに書いたショートコードが展開されない理由
記事本文に書いたショートコードが展開されるのは、本文が出力されるときに WordPress が the_content というフィルターを通していて、その中で do_shortcode() が自動的に呼ばれているからです。つまり「本文に書けば自動で処理される」のは the_content 経由で表示される場合に限られます。
一方、テンプレートファイルに直接 echo '[gallery ids="1,2,3"]'; のように書いても、そのフィルターを通らないため、ブラウザには [gallery ids="1,2,3"] という文字列がそのまま表示されます。テンプレート側で明示的にショートコードを解釈・展開したいときに do_shortcode() を使う、というのが基本の考え方です。
do_shortcode() のシグネチャと戻り値
do_shortcode() のシグネチャは次のとおりです。渡した文字列の中にあるショートコードを探して展開し、展開後の文字列を返します。画面に出力するわけではないので、表示するには自分で echo する必要があります。
do_shortcode(
$content, // ショートコードを含む文字列
$ignore_html = false // HTML内のショートコードを無視するか(省略可)
);
// 戻り値:ショートコードを展開したあとの文字列
それぞれの引数の意味は次の表のとおりです。
| 引数 | 意味 |
|---|---|
$content | 展開したいショートコードを含む文字列。ショートコードが含まれていなければ、そのまま返る。 |
$ignore_html | true にすると、HTML タグの内側に書かれたショートコードを展開せずに残す。既定は false。 |
戻り値が文字列である点はよく間違えるところです。do_shortcode( '[myshortcode]' ); とだけ書いても、返ってきた文字列を捨てているので画面には何も表示されません。次のように echo を付けて出力します。
テンプレートでショートコードを出力する基本例
もっとも基本的な使い方は、ショートコードの文字列を do_shortcode() に渡し、その戻り値を echo で出力するだけです。ここでは仮に [recent_posts] という自作ショートコードがある前提で、テンプレートの好きな位置に出力してみます。
<?php
// ショートコードを展開して、その結果を出力する
echo do_shortcode( '[recent_posts]' );
?>
これで、記事本文に [recent_posts] と書いたときと同じ内容が、テンプレートの任意の位置に表示されます。サイドバーやフッター、記事一覧の合間など、本文以外の場所にショートコードの出力を差し込みたいときに便利です。
属性付きのショートコードを渡す
ショートコードに属性がある場合も、記事本文に書くのと同じ形式の文字列をそのまま渡します。たとえば WordPress 標準の [gallery] ショートコードで、表示する画像を ids 属性で指定するなら次のように書きます。
<?php
// 添付画像 ID を指定してギャラリーを表示する
echo do_shortcode( '[gallery ids="12,45,78" columns="3"]' );
?>
属性の値はダブルクォートで囲みます。文字列全体はシングルクォートで囲んでいるので、属性側のダブルクォートはそのまま書けます。もし文字列をダブルクォートで囲む場合は、内側のクォートをエスケープするか、後述のように変数を組み立てる形にすると読みやすくなります。
変数を埋め込んで組み立てる
投稿 ID やカスタムフィールドの値など、動的な値を属性に入れたいことはよくあります。その場合は、いったん変数でショートコードの文字列を組み立ててから do_shortcode() に渡すと分かりやすくなります。値を "..." で囲む都合上、sprintf() を使うと引用符の入れ子で悩まずに済みます。
<?php
// 現在の投稿 ID を属性に埋め込む
$post_id = get_the_ID();
// sprintf でショートコード文字列を組み立てる
$shortcode = sprintf( '[related_posts post_id="%d" count="5"]', $post_id );
echo do_shortcode( $shortcode );
?>
変数の値がユーザー入力など信頼できないものを含む場合は、属性に埋め込む前に esc_attr() や intval() などで適切にサニタイズしておくと安全です。上の例では %d で整数として扱っているため、数値以外が混ざっても 0 に変換されます。
任意のテキストを本文と同じように整形したいとき
カスタムフィールドなどに保存したテキストを表示する際、その中にショートコードを書いておいて展開したい、というケースがあります。この用途で do_shortcode() を使うと、ショートコードは展開されますが、段落への変換(wpautop)やその他の本文用フィルターは適用されません。
本文とまったく同じ整形をかけたい場合は、do_shortcode() ではなく apply_filters( 'the_content', $text ) を使います。こちらは the_content に登録されたすべてのフィルター(ショートコードの展開を含む)を通すため、記事本文と同じ見た目になります。
<?php
$text = get_post_meta( get_the_ID(), 'custom_body', true );
// (A) ショートコードだけを展開したいとき
echo do_shortcode( $text );
// (B) 本文と同じ整形(段落変換なども)を通したいとき
echo apply_filters( 'the_content', $text );
?>
どちらを選ぶかは目的次第です。「ショートコードだけ展開できれば十分」なら do_shortcode()、「記事本文と同じ見た目にしたい」なら apply_filters( 'the_content', ... ) と覚えておくとよいでしょう。
ショートコードが登録されているか確認する
展開したいショートコードが、そもそもそのタイミングで登録されているとは限りません。プラグインを停止していたり、登録される前に呼び出していたりすると、ショートコードは展開されずタグの文字列のまま残ります。無駄な処理や表示崩れを避けたいときは、事前に存在チェックをしておくと安心です。
文字列の中に特定のショートコードが含まれているかは has_shortcode() で調べられます。第1引数に対象の文字列、第2引数にショートコードのタグ名を渡すと、含まれていれば true を返します。
<?php
$content = get_the_content();
// 本文に [gallery] が含まれているかを判定する
if ( has_shortcode( $content, 'gallery' ) ) {
echo '<p class="notice">この記事にはギャラリーがあります</p>';
}
?>
「文字列の中に含まれているか」ではなく「そのタグ名のショートコードがシステムに登録されているか」を確認したいときは shortcode_exists() を使います。タグ名だけを渡し、登録済みなら true を返します。プラグインの有無で処理を分けたい場合などに役立ちます。
<?php
// [contact_form] が登録されているときだけ出力する
if ( shortcode_exists( 'contact_form' ) ) {
echo do_shortcode( '[contact_form]' );
}
?>
has_shortcode() は「文字列を対象にした含有チェック」、shortcode_exists() は「登録状況のチェック」という違いを押さえておくと使い分けやすくなります。
展開されずタグが残ってしまうとき
ショートコードが登録される前に呼んでいる
do_shortcode() は、その時点で登録されていないショートコードを見つけても、エラーにはせずタグの文字列をそのまま残します。プラグインやテーマの init より前のタイミングで呼び出していると、まだ add_shortcode() による登録が終わっておらず、展開されないことがあります。ショートコードを呼び出す処理は、テンプレートの表示処理の中など、登録が済んだ十分に遅いタイミングで行うようにします。
タグ名や属性のスペルが違う
登録されているタグ名と、渡した文字列のタグ名が一致していないと展開されません。前述の shortcode_exists() で登録名を確認し、大文字小文字やアンダースコアの違いがないかを見直します。属性名が違う場合はショートコード自体は展開されますが、値が効かないため、こちらは各ショートコードの仕様に合わせて属性名を確認します。
HTML の内側にあるショートコードを無視したい・したくない
第2引数の $ignore_html を true にすると、HTML タグの内側(属性値など)に書かれたショートコードは展開されずに残ります。通常は既定の false のままで問題ありませんが、意図せず HTML の中のショートコードが処理されて壊れる場合は、この引数の指定を見直してみてください。
作る側との関係
この記事はショートコードを「呼び出す・展開する」側の話でした。ショートコード自体を作る側は add_shortcode() でタグ名とコールバックを登録し、属性は shortcode_atts() で既定値とマージして受け取ります。do_shortcode() はあくまで、そうして登録済みのショートコードを、任意の文字列やテンプレート内から実行するための関数だと考えると全体像がつかみやすくなります。
まとめ
do_shortcode() は、PHP テンプレートや任意の文字列の中のショートコードを展開し、その結果を文字列で返す関数です。返すだけで出力はしないので echo が必要なこと、属性付きの文字列や変数で組み立てた文字列も渡せること、そして本文と同じ整形をかけたいときは apply_filters( 'the_content', $text ) を使うことがポイントです。存在チェックには has_shortcode() と shortcode_exists() を使い分け、登録タイミングやタグ名の違いで展開されないケースにも気を配れば、テンプレートの好きな場所にショートコードの出力を安全に差し込めるようになります。