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フィルターでログイン状態に応じてアイテムを動的追加の手順で解決します。