ショートコードの出力位置がずれる原因|echo ではなく return

結論

ショートコードの出力位置がずれる原因は、コールバック内で echo や get_template_part() などを直接出力していることです。ショートコードは「戻り値で本文の該当箇所を置き換える」仕組みなので、return で文字列を返します。

テンプレートファイルを読み込みたい場合は、出力バッファで包みます。

add_shortcode( 'tpl', function () {
    ob_start();
    get_template_part( 'parts/card' );
    return ob_get_clean();
} );

原因・仕組み

the_content の途中で do_shortcode が実行され、本文の文字列の中の [タグ] が、コールバックの戻り値で置き換えられます。この処理が終わる前に、コールバック内で echo された内容は、その時点ですぐ画面に出力されます。一方、本文は処理が終わってから出力されるので、echo した部分が本文より前(多くは記事の先頭やテーマの上部)に表示されます。

公式のリファレンスにも、ショートコードの関数は置き換える文字列を返すもので、直接出力すると意図しない結果になる、と書かれています。

手順(サンプルコード)

1. 悪い例(そのまま使わない)

add_shortcode( 'bad_echo', function () {
    echo '<span>ECHOED</span>'; // 本文より先に出力される
    return '';
} );

2. 良い例:文字列を返す

add_shortcode( 'good_return', function () {
    return '<span>RETURNED</span>';
} );

3. 関数が echo する場合は出力バッファで受ける

add_shortcode( 'tpl', function () {
    ob_start();
    echo '<p>from template</p>';      // 既存の echo 型の関数をここで呼ぶ
    return ob_get_clean();
} );

get_template_part() や、echo するテンプレート関数を使うときの定番です。エラー時にバッファが残らないよう、ob_start() と ob_get_clean() は同じ関数内で対にします。

動作確認(検証環境と結果)

WordPress 7.1.2(ja)、PHP 8.2.12 の CLI 環境で実行しました。

  • apply_filters( 'the_content', 'before [bad_echo] after' ) の戻り値は <p>before after</p>(ショートコードの位置には何も入らない)で、<span>ECHOED</span> は戻り値より先に標準出力へ出た。
  • do_shortcode( 'before [bad_echo] after' ) の戻り値は before after、ob_start で捕まえた echo 分は <span>ECHOED</span>。
  • ob_start() で包んだ [tpl] は x<p>from template</p>y と、正しい位置に入った。

ログは testsshortcode-output-position-wrong-echo-vs-return.md に保存しています。

ショートコードの出力位置がずれる原因の注意点

  • 出力バッファ内で例外が出ると、バッファが閉じられず出力が崩れることがあります。例外が起きうる処理には try/finally を検討します。
  • 返す HTML は、ショートコード自身でエスケープします。属性の扱いはショートコードの作り方と属性を参照してください。
  • 戻り値が長大になる場合は、sprintf や配列の implode で組み立てると読みやすくなります。
  • キャッシュしたい場合は、set_transient() に戻り値の文字列を保存できます(echo 型だとできません)。

ショートコードの出力位置がずれる原因でよくあるミス

  • ショートコードの中で the_title() などの echo 型テンプレートタグを直接呼ぶ。get_the_title() のような get_ 系を使います。
  • return と echo の両方を書く。
  • ob_start() したのに ob_get_clean() を返さず、ob_end_flush() で出力してしまう。
  • 戻り値に NULL(return 忘れ)を返す。

ショートコードの出力位置がずれる原因のチェックリスト

  • コールバック内に echo / print が残っていないか
  • テンプレート読み込みは ob_start() で包んだか
  • the_* ではなく get_the_* を使っているか
  • 戻り値は常に文字列か
  • 本文の途中に正しく入ることを確認したか

ショートコードの出力位置がずれる原因のFAQ(よくある質問)

Q. 既存プラグインのショートコードが先頭に出るのは、同じ原因ですか?
A. その可能性が高いです。作者に報告するか、ob_start で包んだラッパーのショートコードを作る方法があります。

Q. ウィジェットやテンプレートでも同じですか?
A. テンプレートで echo do_shortcode() する場合は、戻り値が文字列なので、同じ書き方で問題ありません。

Q. get_template_part() の戻り値は使えますか?
A. 戻り値は void または false で、HTML は返しません。出力バッファを使います。

筆者の見解(ショートコードの出力位置がずれる原因)

「echo 型のコードを無理に return 型に直す」のではなく、最初から get_ 系の関数と文字列の組み立てで書く方が、テストしやすいと考えます。出力バッファは便利ですが、使いすぎると流れが追いにくくなるため、既存のテンプレートを再利用したい場面に限るのが良いと思います。

ショートコードの出力位置がずれる原因の関連項目

出典(一次情報)

PR当サイトはアフィリエイト広告を利用しています。掲載内容は広告主から依頼・指示を受けたものではなく、筆者の調査・体験にもとづきます。
タイトルとURLをコピーしました