WordPress/ACF:カスタムフィールドでショートコードを実行する最適解ガイド

要点

  • the_field() は基本的にショートコードを実行しません(WYSIWYG は除く)。
  • もっとも安全で壊れにくい方法は get_field()do_shortcode() の手動ラップ。
  • 規模が大きいなら ACFの acf/format_value フィルタで型や名前ごとに自動化。
  • セキュリティと可読性のため、許可リスト/権限チェックを入れておくのが実務的。

1) まずは前提:どのフィールドが“そのままでは”動くのか?

  • WYSIWYG(エディタ)the_content 相当の処理が入るため、ショートコードは実行される
  • テキスト/テキストエリア/数値 など実行されない(ただの文字列として出力)。

つまり、WYSIWYG 以外のフィールドでショートコードを使いたいときに以下の方法を使います。


2) 手早く確実:get_field() を do_shortcode() で包む

テンプレート側のピンポイント対応。副作用が少なく、まずはこれでOK。

<?php
// テンプレート例
$value = get_field('my_text_field'); // the_field()は即出力なので使わない
if (!empty($value)) {
    echo do_shortcode($value);
}

ポイント

  • the_field() は即出力&加工できないので get_field() を使う
  • 何でもかんでも do_shortcode() するのは危険。この方法は適用箇所を限定できるのが強み。

3) 規模が大きいなら:acf/format_value で自動化

3-1. フィールド名を指定して実行(局所適用)

<?php
// functions.php
add_filter('acf/format_value/name=my_text_field', function ($value) {
    if (is_string($value) && $value !== '') {
        $value = do_shortcode($value);
    }
    return $value;
}, 10, 1);

3-2. 型(テキストエリア等)を一括で実行(広域適用)

<?php
// 例:textarea型の値に限ってショートコードを展開
add_filter('acf/format_value/type=textarea', function ($value) {
    if (is_string($value) && $value !== '') {
        // 段落ズレ対策でunautop→do_shortcodeの順にかけることもある
        $value = shortcode_unautop($value);
        $value = do_shortcode($value);
    }
    return $value;
}, 10, 1);

運用Tips

  • 一括適用は便利な反面、想定外の場所でもショートコードが動く可能性。
  • まずは フィールド名限定で導入 → 影響範囲を確認 → 必要なら型単位に拡張、が安全。

4) セキュリティと運用のベストプラクティス

4-1. 許可するショートコードをホワイトリスト化

<?php
// 許可リスト
function my_allowed_shortcodes(): array {
    return ['gallery', 'contact-form-7', 'my_shortcode'];
}

// 許可されたものだけを展開する実行関数
function my_safe_do_shortcode(string $text): string {
    // 文中から[xxx]を抽出して検査する簡易例
    preg_match_all('/\[([a-zA-Z0-9_-]+)/', $text, $m);
    $tags = array_unique($m[1] ?? []);
    $allowed = my_allowed_shortcodes();

    foreach ($tags as $tag) {
        if (!in_array($tag, $allowed, true)) {
            // 許可外ショートコードは文字列のまま残す(あるいは除去)
            // ここでは除去例:
            $text = preg_replace('/\[' . preg_quote($tag, '/') . '[^\]]*\](?:.*?\[\/' . preg_quote($tag, '/') . '\])?/s', '', $text);
        }
    }
    return do_shortcode($text);
}

上の関数に置き換えるだけで、予期しないショートコードの実行を防止できます。

4-2. 投稿権限で挙動を変える(一般ユーザーが編集するサイト向け)

<?php
add_filter('acf/format_value/name=my_text_field', function ($value) {
    if (!is_string($value) || $value === '') return $value;

    // 管理者のみフル許可、それ以外はホワイトリスト実行
    if (current_user_can('manage_options')) {
        return do_shortcode($value);
    }
    return my_safe_do_shortcode($value);
}, 10, 1);

4-3. XSS対策(任意のHTML混入が懸念される場合)

<?php
add_filter('acf/format_value/name=my_text_field', function ($value) {
    if (!is_string($value) || $value === '') return $value;

    $value = my_safe_do_shortcode($value);

    // 許可HTMLだけを通す(必要に応じて $allowed_html を拡張)
    $allowed_html = wp_kses_allowed_html('post');
    return wp_kses($value, $allowed_html);
}, 10, 1);

5) よくあるハマりどころと対処

  • 改行や段落が崩れる
  • shortcode_unautop()do_shortcode() の前に。
  • ACF 側の「自動整形(改行→)」設定や、WYSIWYG のツールバー/整形オプションを見直す。
  • 入れ子ショートコードが動かない
  • 実装順序(shortcode_unautopdo_shortcode)と、目的のショートコードが適切に add_shortcode() 済みか確認。
  • パフォーマンス懸念
  • ショートコードの中で重いクエリを回していると遅くなる。
  • 可能なら wp_cache_* で結果キャッシュ、WP_Query は最小化。
  • WYSIWYGで二重整形
  • WYSIWYG は元から整形が入るため、追加で wpautop() をかけない。必要なら ACF の設定側で自動整形をOFF。

6) 動作確認のための最小ショートコード例

<?php
// functions.php
add_shortcode('hello_box', function ($atts, $content = '') {
    $atts = shortcode_atts(['title' => 'Hello'], $atts, 'hello_box');
    // ここでHTMLを返す(必要ならwp_ksesで絞る)
    $title = esc_html($atts['title']);
    $content = wpautop(do_shortcode($content)); // ネスト対応
    return "<div class=\"hello-box\"><h3>{$title}</h3>{$content}</div>";
});

ACFのテキストエリアに以下を保存して、上記のいずれかの方法で展開してください。

[hello_box title="ようこそ"]ここに本文や[gallery]など[/hello_box]

7) 導入パターン別のおすすめ

  • 小規模/箇所限定:テンプレートで get_field()do_shortcode()
  • 中〜大規模/同型多数acf/format_value/name=... でフィールド名をホワイトリスト運用
  • サイト全体で積極運用型単位(type=textarea など)+ my_safe_do_shortcode で安全網を張る

まとめ

  • WYSIWYG以外のACFフィールドでショートコードを動かすには、
  1. 手動ラップ(局所)か、2) acf/format_value(自動化)を使う。
  • 運用では 許可リスト・権限・XSS対策 をセットで。
  • 改行・段落崩れは shortcode_unautop() の併用と整形設定の見直しで解消。

コメント

タイトルとURLをコピーしました