2026年6月3日

2026年6月3日

WordPressのショートコードが機能しない問題を解決する方法

はじめに

WordPressにadd_shortcode()でカスタムショートコードを登録したのに記事に[my_shortcode]と入力しても文字がそのまま表示されてしまう・ショートコードがウィジェットのテキストエリアで機能しない・ショートコードをカスタムフィールドやタイトルに入れても処理されない・PHPのechoを使ったショートコード関数の中でHTMLが2重に出力される・入れ子にした子ショートコードが親より先に実行されてしまうといった問題は、add_shortcode()の登録タイミング・returnechoの混同・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_textwidget_text_contentフィルターにdo_shortcodeを追加・カスタムフィールドはecho do_shortcode($value)・タイトルや抜粋でもthe_titlethe_excerptフィルターに追加、④shortcode_atts()absint()filter_var(FILTER_VALIDATE_BOOLEAN)で型変換・入れ子ショートコードはdo_shortcode($content)・属性値のホワイトリストチェック、⑤remove_shortcode()で競合するショートコードを削除・add_shortcode()で独自実装に差し替え・wp evalでパフォーマンスをプロファイルの手順で解決します。

お気軽にご相談ください

お見積りへ お問い合わせへ