2026年7月5日
2026年7月5日
WordPressのナビゲーションメニューをカスタマイズする方法
はじめに
「WordPressのナビゲーションメニューにカスタムCSSクラスを追加したい」「メニューアイテムにアイコンSVGを挿入したい」「ドロップダウンメニューをカスタマイズしたい」「メニューエリアを複数箇所に登録したい」——ナビゲーションメニューの細かいカスタマイズはWalkerクラスかフィルターで実現できます。
症状・原因
WordPressのメニュー出力はwp_nav_menu()が担い、HTML構造は内部でWalker_Nav_Menuクラスが生成します。デフォルト出力では
// functions.php: メニューエリアを登録
add_action( 'after_setup_theme', function(): void {
register_nav_menus( [
'primary' => 'プライマリーナビゲーション',
'footer' => 'フッターナビゲーション',
'mobile' => 'モバイルナビゲーション',
'social' => 'ソーシャルリンク',
'breadcrumb' => 'パンくず用メニュー',
] );
} );
// テンプレートファイル(header.php): メニューを表示
wp_nav_menu( [
'theme_location' => 'primary',
'menu_class' => 'nav__list',
'container' => 'nav',
'container_class' => 'nav',
'container_id' => 'site-navigation',
'depth' => 2, // ドロップダウンの深さ(0=無制限)
'fallback_cb' => false, // メニュー未設定時のフォールバックを無効化
'items_wrap' => '<ul id="%1$s" class="%2$s" role="menubar">%3$s</ul>',
] );
ステップ2:メニューアイテムにカスタムクラスを追加する
// functions.php: nav_menu_css_class フィルターでクラスを追加
add_filter( 'nav_menu_css_class', function( array $classes, WP_Post $item, stdClass $args ): array {
// 'primary' メニューの全アイテムに 'nav__item' クラスを追加
if ( isset( $args->theme_location ) && 'primary' === $args->theme_location ) {
$classes[] = 'nav__item';
}
// 現在のページのアイテムにカスタムクラスを追加
if ( in_array( 'current-menu-item', $classes, true ) ) {
$classes[] = 'is-active';
}
// 親メニュー(子を持つ)アイテムにクラスを追加
if ( in_array( 'menu-item-has-children', $classes, true ) ) {
$classes[] = 'has-dropdown';
}
return $classes;
}, 10, 3 );
// メニューリンクに属性を追加
add_filter( 'nav_menu_link_attributes', function( array $atts, WP_Post $item, stdClass $args ): array {
if ( isset( $args->theme_location ) && 'primary' === $args->theme_location ) {
$atts['class'] = 'nav__link';
}
// 子メニューを持つアイテムにARIA属性を追加
if ( in_array( 'menu-item-has-children', (array) $item->classes, true ) ) {
$atts['aria-haspopup'] = 'true';
$atts['aria-expanded'] = 'false';
}
return $atts;
}, 10, 3 );
ステップ3:メニューアイテムのHTMLをカスタマイズする
// functions.php: walker_nav_menu_start_el フィルターでアイテムHTMLを変更
add_filter( 'walker_nav_menu_start_el', function( string $item_output, WP_Post $item, int $depth, stdClass $args ): string {
// 'social' メニューにSVGアイコンを追加
if ( isset( $args->theme_location ) && 'social' === $args->theme_location ) {
$icons = [
'Twitter' => '<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.74l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>',
'Facebook' => '<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>',
];
$title = $item->title;
if ( isset( $icons[ $title ] ) ) {
// アイコンをリンクテキストの前に挿入
$item_output = str_replace(
'>'. $item->title . '<',
'>' . $icons[ $title ] . '<span class="screen-reader-text">' . esc_html( $item->title ) . '</span><',
$item_output
);
}
}
return $item_output;
}, 10, 4 );
ステップ4:ドロップダウンメニューのHTMLとCSSを実装する
// functions.php: サブメニューのラッパーにカスタムクラスを追加
add_filter( 'nav_menu_submenu_css_class', function( array $classes, stdClass $args, int $depth ): array {
$classes[] = 'nav__dropdown';
$classes[] = 'nav__dropdown--depth-' . $depth;
return $classes;
}, 10, 3 );
/* style.css: ドロップダウンナビゲーション */
.nav__list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
gap: 0;
}
.nav__item {
position: relative;
}
.nav__link {
display: block;
padding: 1rem 1.25rem;
color: inherit;
text-decoration: none;
white-space: nowrap;
transition: background 0.15s;
}
.nav__link:hover,
.nav__item.is-active > .nav__link {
background: rgba(255,255,255,0.1);
}
/* ドロップダウン */
.nav__dropdown {
display: none;
position: absolute;
top: 100%;
left: 0;
min-width: 200px;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
list-style: none;
margin: 0;
padding: 0.5rem 0;
z-index: 100;
}
.nav__item.has-dropdown:hover > .nav__dropdown,
.nav__item.has-dropdown:focus-within > .nav__dropdown {
display: block;
}
ステップ5:モバイルメニューのトグルを実装する
// assets/js/nav-toggle.js: ハンバーガーメニュー
document.addEventListener('DOMContentLoaded', () => {
const toggle = document.getElementById('nav-toggle');
const nav = document.getElementById('site-navigation');
if (!toggle || !nav) return;
toggle.addEventListener('click', () => {
const isOpen = nav.classList.toggle('is-open');
toggle.setAttribute('aria-expanded', isOpen.toString());
toggle.setAttribute('aria-label', isOpen ? 'メニューを閉じる' : 'メニューを開く');
});
// ドロップダウンのキーボード操作
nav.querySelectorAll('[aria-haspopup="true"]').forEach(link => {
link.addEventListener('click', e => {
e.preventDefault();
const expanded = link.getAttribute('aria-expanded') === 'true';
link.setAttribute('aria-expanded', (!expanded).toString());
});
});
});
注意事項
nav_menu_css_classフィルターの第3引数$argsはオブジェクトで、theme_locationプロパティはwp_nav_menu()に渡した値です。複数メニューがある場合は必ずtheme_locationで条件を絞ってください。:hoverのみを使うとキーボード操作・タッチデバイスで問題が生じます。:focus-withinやaria-expandedと組み合わせてアクセシビリティを確保してください。wp_nav_menu()のwalker引数に独自Walkerクラスを渡す方法もありますが、フィルターで対応できる場合はフィルターの方がシンプルです。まとめ
ナビゲーションメニューのカスタマイズは「register_nav_menus()でエリアを登録→wp_nav_menu()でコンテナ・クラス・深さを指定→nav_menu_css_class/nav_menu_link_attributesフィルターでクラスとARIA属性を追加→walker_nav_menu_start_elでSVGアイコンを挿入→CSSとJSでドロップダウン・ハンバーガーを実装」の流れで整備します。関連記事:WordPressのウォーカークラスでメニューをカスタマイズする方法、WordPressのウィジェットエリアを追加する方法。