2026年6月16日
2026年6月16日
WordPressのナビゲーションメニューが動かないときの原因と直し方(表示されない・Walkerのエラー)
クラシックテーマのナビゲーションメニューは、テーマが register_nav_menus() で「位置」を登録し、管理画面でその位置にメニューを割り当て、テンプレートの wp_nav_menu() が出力する、という3段階で表示されます。どこかが欠けると、何も表示されない、固定ページの一覧が代わりに出る、といった症状になります。
この記事では、状態の確かめ方と、症状ごとの原因と直し方を説明します。コードは WordPress 6.9 と PHP 8.3 で動作を確認しています(2026年10月時点)。functions.php を編集する前にはバックアップを取ってください。
まず状態を確かめる
WP-CLI が使える場合は、次のコマンドで「位置が登録されているか」「メニューが割り当てられているか」「メニューに項目があるか」を一度に確かめられます。
# テーマが登録しているメニューの位置
wp menu location list
# 作成済みのメニューと、割り当てられている位置・項目数
wp menu list --fields=term_id,name,slug,locations,count
# メニューの項目(main はメニューのスラッグか ID に置き換える)
wp menu item list main --fields=db_id,title,menu_item_parent
出力の例です。
location description
primary メインナビゲーション
footer フッターメニュー
term_id name slug locations count
3 Empty empty footer 0
2 Main main primary 3
この例では、primary には項目が3つある Main が割り当てられています。footer に割り当てられた Empty は項目が0件なので、フッターには何も表示されません。
WP-CLI が使えない場合は、「外観」→「メニュー」の「位置を管理」タブで、位置ごとの割り当てを確認できます。
症状と原因の早見表
| 症状 | よくある原因 |
|---|---|
| 「外観」に「メニュー」が無い | テーマが register_nav_menus() を呼んでいない(ブロックテーマなど) |
| 「メニュー設定」や「位置を管理」に位置が出ない | register_nav_menus() が呼ばれていない、または呼んでいるファイルが読み込まれていない |
| メニューの代わりに固定ページの一覧が出る | 位置にメニューが割り当てられていない、または theme_location の綴りが違い、既定の fallback_cb(wp_page_menu)が動いている |
| 何も表示されない | 上と同じ原因で fallback_cb が false、または割り当てたメニューに項目が無い |
| 画面が真っ白になる、致命的エラーが出る | カスタム Walker のメソッドの引数が親クラスと合っていない |
| ドロップダウンが開かない | depth が 1、CSS フレームワークの JavaScript が読み込まれていない、必要なクラスが付いていない |
位置が登録されていない場合
テーマの functions.php で、after_setup_theme フックから register_nav_menus() を呼びます。登録すると、テーマがメニュー機能に対応した扱いになり、「外観」→「メニュー」が表示されます。
<?php
add_action( 'after_setup_theme', function () {
register_nav_menus(
array(
'primary' => 'メインナビゲーション',
'footer' => 'フッターメニュー',
)
);
} );
登録したら、「外観」→「メニュー」でメニューを作り、画面下部の「メニュー設定」で位置にチェックを入れて「メニューを保存」を押すか、「位置を管理」タブで割り当てます。
子テーマで位置を追加する場合も、子テーマの functions.php に同じように書きます。テンプレートの theme_location に書くキー(ここでは primary)は、登録したキーと一字一句同じにします。
ブロックテーマの場合
Twenty Twenty-Five などのブロックテーマは、サイトエディターのナビゲーションブロックでメニューを管理します。テーマが register_nav_menus() を呼ばないため、「外観」→「メニュー」は表示されません。「外観」→「エディター」でヘッダーのナビゲーションブロックを選び、そこでメニューを編集します。以前のクラシックメニューは、ナビゲーションブロックのメニュー選択から取り込めます。
wp_nav_menu() が何も出さない・固定ページの一覧が出る場合
wp_nav_menu() は、theme_location に指定した位置にメニューが割り当てられていないと、fallback_cb に指定した関数を呼びます。既定値は固定ページの一覧を出す wp_page_menu なので、「作ったメニューではなく固定ページが並ぶ」ときは、割り当てが無いか、theme_location の綴りが違っています。fallback_cb を false にしていると、同じ状況で何も出力されません。
また、位置に割り当てたメニューの項目が0件のときは、theme_location を指定していれば何も出力されません。
テンプレートでは、割り当ての有無を has_nav_menu() で確かめてから出力すると、意図しない固定ページの一覧が出るのを防げます。
<?php
if ( has_nav_menu( 'primary' ) ) {
wp_nav_menu(
array(
'theme_location' => 'primary',
'container' => 'nav',
'container_class' => 'main-navigation',
'menu_class' => 'nav-menu',
'depth' => 2,
'fallback_cb' => false,
)
);
}
has_nav_menu() は「割り当てがあるか」だけを返します。割り当てたメニューに項目が無くても true になるため、何も出ないときは前述の wp menu list で項目数も確認してください。
カスタム Walker で致命的エラーになる場合
Walker_Nav_Menu を継承したクラスで、メソッドに親クラスにない型宣言を付けると、クラスを読み込んだ時点で致命的エラーになり、サイトが表示されなくなります。たとえば次のように書くと、
<?php
// 誤り: 親クラスにない型宣言を付けている
class Bootstrap_Nav_Walker extends Walker_Nav_Menu {
public function start_el( string &$output, WP_Post $item, int $depth = 0, stdClass $args = null, int $id = 0 ): void {
// ...
}
}
PHP 8.3 では次のエラーになります。
PHP Fatal error: Declaration of Bootstrap_Nav_Walker::start_el(string &$output, WP_Post $item, int $depth = 0, ?stdClass $args = null, int $id = 0): void must be compatible with Walker_Nav_Menu::start_el(&$output, $data_object, $depth = 0, $args = null, $current_object_id = 0)
親クラスの引数には型宣言がありません。PHP では、上書きするメソッドの引数を親より狭い型にすることはできないため、string や WP_Post を付けた時点で互換性がないと判断されます。また、PHP 8.4 では stdClass $args = null のように型付きの引数に null の既定値だけを付ける書き方(暗黙の nullable)が非推奨になりました。
直し方は、引数の並びと既定値を親クラスと同じにし、型宣言を付けないことです。WordPress 6.9 の Walker_Nav_Menu のメソッドは次の形です。
public function start_lvl( &$output, $depth = 0, $args = null )
public function end_lvl( &$output, $depth = 0, $args = null )
public function start_el( &$output, $data_object, $depth = 0, $args = null, $current_object_id = 0 )
public function end_el( &$output, $data_object, $depth = 0, $args = null )
修正した Bootstrap 5 用の Walker です。
<?php
class Bootstrap_Nav_Walker extends Walker_Nav_Menu {
// 親クラスと同じ引数(型宣言なし・同じ既定値)にする
public function start_lvl( &$output, $depth = 0, $args = null ) {
$output .= '<ul class="dropdown-menu">';
}
public function start_el( &$output, $data_object, $depth = 0, $args = null, $current_object_id = 0 ) {
$menu_item = $data_object;
$classes = empty( $menu_item->classes ) ? array() : (array) $menu_item->classes;
$has_child = in_array( 'menu-item-has-children', $classes, true );
$current = in_array( 'current-menu-item', $classes, true );
if ( 0 === $depth ) {
$output .= '<li class="nav-item' . ( $has_child ? ' dropdown' : '' ) . '">';
} else {
$output .= '<li>';
}
if ( 0 === $depth && $has_child ) {
$output .= '<a class="nav-link dropdown-toggle" href="' . esc_url( $menu_item->url ) . '" role="button" data-bs-toggle="dropdown" aria-expanded="false">';
} else {
$link_class = $depth > 0 ? 'dropdown-item' : 'nav-link';
$output .= '<a class="' . $link_class . ( $current ? ' active' : '' ) . '" href="' . esc_url( $menu_item->url ) . '"' . ( $current ? ' aria-current="page"' : '' ) . '>';
}
$output .= esc_html( $menu_item->title ) . '</a>';
}
}
end_lvl()(</ul>)と end_el()(</li>)は親クラスのものをそのまま使います。テンプレートでは次のように渡します。
<?php
wp_nav_menu(
array(
'theme_location' => 'primary',
'container' => false,
'menu_class' => 'navbar-nav',
'depth' => 2,
'walker' => new Bootstrap_Nav_Walker(),
)
);
致命的エラーで管理画面にも入れない場合は、FTP や SSH で該当のコードを一時的にコメントアウトするか、テーマのフォルダー名を変えて既定のテーマに切り替えてから直します。エラーの全文は、wp-config.php で WP_DEBUG と WP_DEBUG_LOG を true にすると wp-content/debug.log に記録されます。
ドロップダウンが開かない場合
次の順に確かめます。
wp_nav_menu()のdepthが1になっていないか。1だと子メニューは出力されません。Bootstrap のドロップダウンなら2にします。- 「外観」→「メニュー」で、子にしたい項目が親の項目の右に字下げされて(親の下の階層になって)いるか。
- CSS フレームワークの JavaScript が読み込まれているか。Bootstrap 5 なら
bootstrap.bundle.min.jsが必要で、リンクにdata-bs-toggle="dropdown"、子メニューのulにdropdown-menuクラスが付いている必要があります。ブラウザーの開発者ツールで、出力された HTML とコンソールのエラーを確かめます。
変更が反映されない場合
メニューを保存しても表示が変わらないときは、ページキャッシュ(キャッシュ系プラグイン、サーバーのキャッシュ、CDN)が古いページを返していることがあります。キャッシュを削除してから確認してください。
メニューの HTML を自前でキャッシュする場合は、現在のページを示す current-menu-item などのクラスがページごとに変わる点に注意が必要です。ページを区別せずにキャッシュすると、別のページのクラスが付いたままのメニューが表示されます。
まとめ
- まず
wp menu location listとwp menu listで、位置の登録・割り当て・項目数を確かめる - 位置が出ないときは、
after_setup_themeでregister_nav_menus()を呼ぶ。ブロックテーマはナビゲーションブロックで管理する - 固定ページの一覧が出るのは、割り当てが無いか
theme_locationの綴り違いでwp_page_menuが動いているため。has_nav_menu()で割り当てを確かめてから出力する - カスタム Walker のメソッドは、親クラスと同じ引数・既定値にし、型宣言を付けない
- ドロップダウンは
depth、メニューの階層、JavaScript の読み込みの順に確かめる