2026年6月16日

2026年6月16日

WordPressのナビゲーションメニューが動作しない問題を解決する方法

はじめに

WordPressのテーマにナビゲーションメニューを設定したのに表示されない・管理画面の「外観」→「メニュー」でメニューを作成したが割り当て先がない・wp_nav_menu()を呼び出しても何も出力されない・カスタムウォーカーを使ったドロップダウンメニューが崩れる・ブロックテーマでナビゲーションブロックのメニューが正しく動かないといった問題は、ナビゲーションメニューの登録と出力の仕組みを正しく理解することで解決できます。

症状・原因

  • register_nav_menus()after_setup_themeフック以外で呼び出している
  • テーマにメニューロケーションが登録されていないため「メニュー」画面にロケーション選択肢がない
  • wp_nav_menu()theme_locationパラメータが正しくない
  • has_nav_menu()でメニューが割り当てられているか確認していない

解決手順

ステップ1:メニュー設定の状態を診断する

# 登録されているメニューロケーションを確認
wp eval "
\$locations = get_registered_nav_menus();
foreach (\$locations as \$location => \$description) {
    \$assigned = has_nav_menu(\$location);
    echo \$location . ': ' . \$description . ' (' . (\$assigned ? '割当あり' : '未割当') . ')' . PHP_EOL;
}
"

# 作成されているメニューを確認
wp menu list --format=table

# メニューに登録されているアイテムを確認
wp menu item list {menu_id} --format=table

# テーマがナビゲーションをサポートしているか確認
wp eval "echo current_theme_supports('menus') ? 'supported' : 'not supported';"

ステップ2:ナビゲーションメニューを正しく登録する

// after_setup_theme フックで登録(必須)
add_action('after_setup_theme', function(): void {
    register_nav_menus([
        'primary'   => 'メインナビゲーション',
        'footer'    => 'フッターメニュー',
        'mobile'    => 'モバイルメニュー',
        'secondary' => 'サブナビゲーション',
    ]);
});

// テンプレートでメニューを出力
function display_primary_menu(): void {
    if (has_nav_menu('primary')) {
        wp_nav_menu([
            'theme_location'  => 'primary',
            'menu_class'      => 'nav-menu',
            'container'       => 'nav',
            'container_class' => 'main-navigation',
            'container_id'    => 'site-navigation',
            'depth'           => 2,          // 2階層まで表示
            'fallback_cb'     => false,      // フォールバックを無効化
        ]);
    }
}

// メニューが未割り当ての場合のフォールバック
function my_menu_fallback(array $args): void {
    echo '<nav class="main-navigation">';
    wp_list_pages(['title_li' => '', 'depth' => 1]);
    echo '</nav>';
}

ステップ3:カスタムウォーカーでメニューをカスタマイズする

// Bootstrap 5対応のカスタムウォーカー
class Bootstrap_Nav_Walker extends Walker_Nav_Menu {

    public function start_lvl(
        string &$output,
        int $depth = 0,
        stdClass $args = null
    ): void {
        $output .= '<ul class="dropdown-menu">';
    }

    public function start_el(
        string &$output,
        WP_Post $item,
        int $depth = 0,
        stdClass $args = null,
        int $id = 0
    ): void {
        $classes   = empty($item->classes) ? [] : (array) $item->classes;
        $has_child = in_array('menu-item-has-children', $classes, true);

        $class_names = implode(' ', array_filter([
            'nav-item',
            $has_child ? 'dropdown' : '',
            in_array('current-menu-item', $classes, true) ? 'active' : '',
        ]));

        $output .= '<li class="' . esc_attr($class_names) . '">';
        $output .= '<a href="' . esc_url($item->url) . '" class="nav-link'
            . ($has_child ? ' dropdown-toggle' : '') . '"'
            . ($has_child ? ' data-bs-toggle="dropdown"' : '') . '>'
            . esc_html($item->title) . '</a>';
    }
}

// ウォーカーを指定してメニューを出力
wp_nav_menu([
    'theme_location' => 'primary',
    'walker'         => new Bootstrap_Nav_Walker(),
]);

ステップ4:メニューアイテムにカスタムフィールドを追加する

// メニューアイテムにアイコンフィールドを追加
add_action('wp_nav_menu_item_custom_fields', function(int $item_id, WP_Post $item): void {
    $icon = get_post_meta($item_id, '_menu_item_icon', true);
    echo '<div class="field-icon">';
    echo '<span class="description">アイコン(FontAwesomeクラス)</span>';
    echo '<input type="text" name="menu-item-icon[' . $item_id . ']" value="' . esc_attr($icon) . '">';
    echo '</div>';
}, 10, 2);

// メニューアイテムのカスタムフィールドを保存
add_action('wp_update_nav_menu_item', function(int $menu_id, int $menu_item_db_id): void {
    if (isset($_POST['menu-item-icon'][$menu_item_db_id])) {
        $icon = sanitize_html_class($_POST['menu-item-icon'][$menu_item_db_id]);
        update_post_meta($menu_item_db_id, '_menu_item_icon', $icon);
    }
}, 10, 2);

// メニューアイテムの出力にアイコンを追加
add_filter('walker_nav_menu_start_el', function(string $item_output, WP_Post $item): string {
    $icon = get_post_meta($item->ID, '_menu_item_icon', true);
    if ($icon) {
        $item_output = str_replace(
            $item->title,
            '<i class="' . esc_attr($icon) . '"></i> ' . $item->title,
            $item_output
        );
    }
    return $item_output;
}, 10, 2);

ステップ5:メニューのキャッシュと動的変更を管理する

// メニューをキャッシュして高速化
function get_cached_nav_menu(string $location): string {
    $cache_key   = 'nav_menu_' . $location . '_' . get_current_user_id();
    $cached_menu = wp_cache_get($cache_key, 'nav_menus');

    if (false !== $cached_menu) {
        return $cached_menu;
    }

    ob_start();
    wp_nav_menu(['theme_location' => $location, 'fallback_cb' => false]);
    $menu = ob_get_clean();

    wp_cache_set($cache_key, $menu, 'nav_menus', 10 * MINUTE_IN_SECONDS);
    return $menu;
}

// メニュー更新時にキャッシュをクリア
add_action('wp_update_nav_menu', function(): void {
    wp_cache_flush_group('nav_menus');
    // Redis Object Cache を使っている場合
});

// ログイン状態に応じてメニューアイテムを動的に変更
add_filter('wp_nav_menu_items', function(string $items, stdClass $args): string {
    if ($args->theme_location !== 'primary') {
        return $items;
    }
    if (is_user_logged_in()) {
        $items .= '<li><a href="' . wp_logout_url(home_url()) . '">ログアウト</a></li>';
    } else {
        $items .= '<li><a href="' . wp_login_url() . '">ログイン</a></li>';
    }
    return $items;
}, 10, 2);

注意事項

  • register_nav_menus()は必ずafter_setup_themeフック内で呼び出してください。子テーマのfunctions.phpの場合はこのフックが適切な場所です
  • ブロックテーマ(Twenty Twenty-Three以降)ではナビゲーションブロックを使います。register_nav_menus()ではなくサイトエディターでメニューを管理します

まとめ

WordPress ナビゲーションメニュー問題の解決は①get_registered_nav_menus()でロケーション確認・has_nav_menu()で割り当て確認・wp menu listでメニュー一覧確認、②after_setup_themeフックでregister_nav_menus()を呼び出す・wp_nav_menu()theme_location/container/depthを設定・has_nav_menu()で割り当てを確認してから出力、③Walker_Nav_Menuを継承したBootstrap_Nav_Walkerを作成・start_lvl/start_elでHTML構造をカスタマイズ・walkerパラメータで指定、④wp_nav_menu_item_custom_fieldsフックでアイコンフィールドを追加・wp_update_nav_menu_itemフックで保存・walker_nav_menu_start_elフィルターで出力にアイコンを挿入、⑤wp_cache_get/setでメニューをキャッシュ・wp_update_nav_menuフックでキャッシュをクリア・wp_nav_menu_itemsフィルターでログイン状態に応じてアイテムを動的追加の手順で解決します。

お気軽にご相談ください

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