2026年6月3日
2026年6月3日
WordPressのショートコードが機能しない問題を解決する方法
はじめに
WordPressにadd_shortcode()でカスタムショートコードを登録したのに記事に[my_shortcode]と入力しても文字がそのまま表示されてしまう・ショートコードがウィジェットのテキストエリアで機能しない・ショートコードをカスタムフィールドやタイトルに入れても処理されない・PHPのechoを使ったショートコード関数の中でHTMLが2重に出力される・入れ子にした子ショートコードが親より先に実行されてしまうといった問題は、add_shortcode()の登録タイミング・returnとechoの混同・do_shortcode()の呼び出し漏れが原因です。
症状・原因
- ショートコードハンドラー関数が
echoを使っている(returnが必要) add_shortcode()をinitフックより前に呼んでいる- テーマやプラグインが
the_contentフィルターを削除しているためdo_shortcodeが動かない - ウィジェットのテキストフィールドではデフォルトでショートコードが処理されない
解決手順
ステップ1:ショートコードの状態を診断する
# 登録されているショートコード一覧
wp eval "
global \$shortcode_tags;
foreach (array_keys(\$shortcode_tags) as \$tag) {
echo '[' . \$tag . ']' . PHP_EOL;
}
" | sort
# 特定のショートコードが登録されているか確認
wp eval "echo shortcode_exists('my_shortcode') ? '登録済み' : '未登録';"
# ショートコードを手動で実行してテスト
wp eval "echo do_shortcode('[my_shortcode title=\"テスト\"]');"
# the_content フィルターの確認
wp eval "
global \$wp_filter;
if (isset(\$wp_filter['the_content'])) {
foreach (\$wp_filter['the_content']->callbacks as \$priority => \$callbacks) {
foreach (\$callbacks as \$cb) {
echo \$priority . ': ' . (is_string(\$cb['function']) ? \$cb['function'] : '[closure]') . PHP_EOL;
}
}
}
"
ステップ2:ショートコードを正しく登録する
// ✅ 正しいショートコードの書き方
// 1. return で返す(echo は NG)
// 2. shortcode_atts() で属性を処理
// 3. 出力をエスケープする
add_shortcode('my_box', function(array|string $atts, ?string $content = null): string {
// デフォルト値とユーザー指定の属性をマージ
$atts = shortcode_atts([
'title' => 'お知らせ',
'color' => 'blue',
'class' => '',
], $atts, 'my_box'); // 第3引数にショートコード名を渡す
// 入れ子ショートコードを処理
$inner = $content ? do_shortcode($content) : '';
// return で HTML を返す(echo は絶対にしない)
return sprintf(
'<div class="my-box my-box--%s %s"><h3>%s</h3><div class="my-box__body">%s</div></div>',
esc_attr($atts['color']),
esc_attr($atts['class']),
esc_html($atts['title']),
wp_kses_post($inner)
);
});
ステップ3:さまざまな場所でショートコードを使えるようにする
// ウィジェットのテキストフィールドでショートコードを有効化
add_filter('widget_text', 'do_shortcode');
add_filter('widget_text_content', 'do_shortcode');
// カスタムフィールドでショートコードを処理
$value = get_post_meta($post_id, 'my_field', true);
echo do_shortcode($value);
// 投稿タイトルでショートコードを処理
add_filter('the_title', 'do_shortcode');
// excerpt でショートコードを処理
add_filter('the_excerpt', 'do_shortcode');
// ACF などのカスタムフィールドプラグインの出力で処理
add_filter('acf/format_value/type=textarea', 'do_shortcode');
ステップ4:ショートコードの属性と入れ子を処理する
// 属性のバリデーションと型変換
add_shortcode('my_list', function(array|string $atts, ?string $content = null): string {
$atts = shortcode_atts([
'count' => 5,
'show' => 'true',
'type' => 'ul',
], $atts, 'my_list');
// 型変換
$count = absint($atts['count']);
$show = filter_var($atts['show'], FILTER_VALIDATE_BOOLEAN);
$type = in_array($atts['type'], ['ul', 'ol'], true) ? $atts['type'] : 'ul';
if (! $show) return '';
// 入れ子の [my_item] ショートコードを処理
$items = do_shortcode($content ?? '');
return "<{$type} class=\"my-list\">{$items}</{$type}>";
});
add_shortcode('my_item', fn(array|string $atts, ?string $content = null): string =>
'<li>' . wp_kses_post(do_shortcode($content ?? '')) . '</li>'
);
ステップ5:ショートコードのデバッグと競合解決
// ショートコードが処理されない場合のデバッグ
add_filter('the_content', function(string $content): string {
// ショートコードが残っているか確認
if (preg_match('/\[my_shortcode/', $content)) {
error_log('Shortcode not processed: ' . substr($content, 0, 200));
}
return $content;
}, 999);
// ショートコードを手動で処理して出力(テンプレート内)
echo do_shortcode('[my_box title="テスト" color="red"]内容[/my_box]');
// 競合するプラグインのショートコードを上書き
remove_shortcode('gallery'); // WordPress標準ギャラリーを削除
add_shortcode('gallery', 'my_custom_gallery_shortcode'); // 独自実装に差し替え
# ショートコードのパフォーマンスをプロファイル
wp eval "
\$start = microtime(true);
\$result = do_shortcode('[my_shortcode]');
\$time = microtime(true) - \$start;
echo 'Output length: ' . strlen(\$result) . ' bytes' . PHP_EOL;
echo 'Time: ' . round(\$time * 1000, 2) . 'ms' . PHP_EOL;
"
注意事項
- ショートコードのコールバック関数は必ず
returnでHTML文字列を返してください。echoを使うと出力が本文の先頭に出力されてレイアウトが崩れます shortcode_atts()の第3引数にショートコード名を渡すとshortcode_atts_{tag}フィルターが使えるようになり、外部からデフォルト値を変更できます- ショートコードをFSEテーマ(Full Site Editing)のブロックエディターで使う場合は、
/wp:shortcodeブロックまたはdo_shortcode()をrender_callbackで呼び出すカスタムブロックに移行することを検討してください
まとめ
WordPressショートコード不動作の解決は①shortcode_exists()で登録確認・do_shortcode()で手動テスト・the_contentフィルターのコールバック一覧を確認・$shortcode_tagsグローバルで全ショートコードを一覧表示、②コールバックでechoでなくreturnで返す・shortcode_atts()でデフォルト値とマージ・esc_attr()・wp_kses_post()で出力をエスケープ・コンテンツ部分はdo_shortcode($content)で再帰処理、③widget_text・widget_text_contentフィルターにdo_shortcodeを追加・カスタムフィールドはecho do_shortcode($value)・タイトルや抜粋でもthe_title・the_excerptフィルターに追加、④shortcode_atts()でabsint()・filter_var(FILTER_VALIDATE_BOOLEAN)で型変換・入れ子ショートコードはdo_shortcode($content)・属性値のホワイトリストチェック、⑤remove_shortcode()で競合するショートコードを削除・add_shortcode()で独自実装に差し替え・wp evalでパフォーマンスをプロファイルの手順で解決します。