要点
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_unautop
→do_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フィールドでショートコードを動かすには、
- 手動ラップ(局所)か、2)
acf/format_value
(自動化)を使う。
- 運用では 許可リスト・権限・XSS対策 をセットで。
- 改行・段落崩れは
shortcode_unautop()
の併用と整形設定の見直しで解消。
コメント