楽天セール開催中!ポイント最大11倍! セール会場へ

WordPress自作テーマ制作③│メニューとウィジェットの作成

このページはクラシック形式の自作テーマ向けです。

ブロックテーマのサイトエディターやSWELLの親テーマへそのまま貼る手順ではありません。

作業前にテーマファイルをバックアップし、本文の部分コードと末尾のまとめを重複して貼らないでください。

WordPressの自作テーマをスターターテーマを使わずにフルスクラッチで作成してみています。

ということで、今回はメニューとウィジェットを表示させてみます。

目次

著者

WEB制作をしているデジタルノマド
WordPressのカスタマイズが好きで、色々と自作しています。

WordPressのカスタマイズに困ったらご相談ください!

WordPressのメニューを表示する

外観のメニューからグローバルメニュー・フッターメニューを作成して表示させてみます。

管理画面にメニューを表示する

下記はテーマのメニュー対応を宣言するコードです。

後述のregister_nav_menu()でもメニュー対応が登録されるため、すでにメニュー位置を登録している場合に追加必須の処理ではありません。

管理画面の外観からメニュー機能へアクセスできるようにするための設定箇所。
// 外観のメニュー表示
add_theme_support('menus');

メニュー設定

以下のコードをfunctions.phpに入れると、メニュー設定の項目にメニュー位置のオプションが設定できます。

function setup_nav_menu() {
    register_nav_menu('global_menu', 'グローバルメニュー');
    register_nav_menu('footer_menu', 'フッターメニュー');
}
add_action('after_setup_theme', 'setup_nav_menu');
グローバルメニューとフッターメニューを登録した後の管理画面の設定状況。

メニューの表示

header.phpのメニューを表示させたい場所に、下記のコードを挿入します。

    <nav class=" global-menu-nav">
        <ul class="global-menu-list">
            <?php
            wp_nav_menu([
                'container' => '',
                'theme_location' => 'global_menu',
        'fallback_cb' => false,
                'items_wrap'      => '%3$s',
                'link_before'     => '<span >',
                'link_after'      => '</span>',
            ]);
            ?>
        </ul>
    </nav>

またfooter.phpのメニューを表示させたい場所に、下記のコードを挿入します。

<ul class="footer-menu-list">
    <?php
    wp_nav_menu([
        'container'       => '',
        'theme_location'  => 'footer_menu',
        'fallback_cb' => false,
        'items_wrap'      => '%3$s',
        'link_before'     => '<span >',
        'link_after'      => '</span>',
    ]);
    ?>
</ul>
項目備考
containerulを囲う要素を指定(div, nav, false)※空白はfalseと同じ。
theme_location登録した位置設定(ロケーション名)を指定

メニューの表示確認

以上の設定をしたうえで、状態の確認をしてみます。

ちゃんとメニューの表示が反映されました。

※グローバルメニューとフッターメニューにそれぞれカスタムリンクを3つ入れた状態です。

グローバルメニューとフッターメニューにカスタムリンクを3つ入れて表示が反映された状態の確認。

メニューの標準クラスを残す

メニューのクラスは現在位置や子メニューの有無を示します。

テーマのCSSや操作に使われるので、この例では削除しません。

<li id="menu-item-8" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-8">

下記は標準クラスとIDを残す方針を示したコメントです。

このコメントを追加しても、既存のクラス削除フィルターを解除する効果はありません。

旧コードを使っている場合は、そのフィルターの登録を確認して取り除いてください。

// メニューの標準クラス・IDは維持します。

独自CSSでも current-menu-item や menu-item-has-children を利用できます。

クラス削除用の旧フィルターは追加しないでください。

<li class="menu-item current-menu-item">

WordPressのウィジェットを表示する

次にウィジェットを設置してみます。

管理画面にウィジェットを表示する

下記はウィジェット対応を宣言するコードです。

後述のregister_sidebar()でもウィジェット対応は有効になるため、表示するエリアの登録まで進めてください。

管理画面の外観からウィジェットへアクセスできるようにするための設定箇所。
// 外観のウィジェット表示
add_theme_support('widgets');

ウィジェットエリアの登録

以下のコードをfunctions.phpに入れると、ウィジェットの項目に登録ができます。

function register_area() {
    register_sidebar([
        'name' => 'サイドバー',
        'id' => 'sidebar',
        'description' => 'サイドバーに表示されます。',
        'before_widget' => '<div id="%1$s" class="%2$s">',
        'after_widget' => '</div>',
    ]);
    register_sidebar([
        'name' => 'フッター',
        'id' => 'footer',
        'description' => 'フッターに表示されます。',
        'before_widget' => '<div id="%1$s" class="%2$s">',
        'after_widget' => '</div>',
    ]);
}
add_action('widgets_init', 'register_area');

参考

ウィジェットエリアにプラスボタンからテキストブロックを追加した様子。

+ボタンを押して、適当にテキストのブロックを追記しました。

ウィジェットの表示

サイドバー用のコードはsidebar.phpに、フッター用のコードはfooter.phpの表示したい場所に配置します。

完成版のfooter.phpはget_sidebar()でsidebar.phpを読み込むため、サイドバー用のコードをfooter.phpにも重ねて置かないでください。

サイドバー

<?php if (is_active_sidebar('sidebar')) : ?>
    <div id="sidebar_widget">
        <?php dynamic_sidebar('sidebar'); ?>
    </div>
<?php endif; ?>

フッター

    <?php if (is_active_sidebar('footer')) : ?>
        <div id="footer_widget">
            <?php dynamic_sidebar('footer'); ?>
        </div>
    <?php endif; ?>

ウィジェットの確認

ウィジェットエリアに入れたテキストブロックが表示されています。

ウィジェットエリアに追加したテキストブロックが実際に反映されて表示されている確認。

この時点でのコードまとめ

  • index.php → 前回から変更なし
  • sidebar.php → 下記「サイドバーを一度だけ表示する完成版」の説明に従い、上のサイドバー用コードを配置
header.php
<!doctype html>
<html <?php language_attributes(); ?>>

<head>
    <meta charset="utf-8">
    <meta name="format-detection" content="telephone=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
    <?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

    <nav class=" global-menu-nav">
        <ul class="global-menu-list">
            <?php
            wp_nav_menu([
                'container' => '',
                'theme_location' => 'global_menu',
        'fallback_cb' => false,
                'items_wrap'      => '%3$s',
                'link_before'     => '<span >',
                'link_after'      => '</span>',
            ]);
            ?>
        </ul>
    </nav>
footer.php
<?php get_sidebar(); ?>

<!-- サイドバーはget_sidebar()で一度だけ読み込みます。 -->

<ul class="footer-menu-list">
    <?php
    wp_nav_menu([
        'container'       => '',
        'theme_location'  => 'footer_menu',
        'fallback_cb' => false,
        'items_wrap'      => '%3$s',
        'link_before'     => '<span >',
        'link_after'      => '</span>',
    ]);
    ?>
</ul>
<footer id="footer">
    <?php if (is_active_sidebar('footer')) : ?>
        <div id="footer_widget">
            <?php dynamic_sidebar('footer'); ?>
        </div>
    <?php endif; ?>
</footer>
<?php wp_footer(); ?>
</body>

</html>
functions.php
<?php

// 外観のメニュー表示
add_theme_support('menus');

// 外観のウィジェット表示
add_theme_support('widgets');

// タイトルタグの表示
add_theme_support('title-tag');

// アイキャッチの表示
add_theme_support('post-thumbnails');

// WordPressのバージョン情報
remove_action('wp_head', 'wp_generator');

// 絵文字
add_filter('emoji_svg_url', '__return_false');
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('admin_print_scripts', 'print_emoji_detection_script');
remove_action('wp_print_styles', 'print_emoji_styles');
remove_action('admin_print_styles', 'print_emoji_styles');

// Windows Live Writeの停止
remove_action('wp_head', 'wlwmanifest_link');

// EditURI(RSD Link)の停止
remove_action('wp_head', 'rsd_link');

// 記号の自動変換停止(wptexturize無効化)
add_filter('run_wptexturize', '__return_false');

// https://api.w.org/の停止
remove_action('wp_head', 'rest_output_link_wp_head');

// ブロックとテーマの標準CSSは停止しません。

// メニューの標準クラス・IDは維持します。

// メニュー位置の設定
function setup_nav_menu() {
    register_nav_menu('global_menu', 'グローバルメニュー');
    register_nav_menu('footer_menu', 'フッターメニュー');
}
add_action('after_setup_theme', 'setup_nav_menu');

// ウィジェットエリアの登録
function register_area() {
    register_sidebar([
        'name' => 'サイドバー',
        'id' => 'sidebar',
        'description' => 'サイドバーに表示されます。',
        'before_widget' => '<div id="%1$s" class="%2$s">',
        'after_widget' => '</div>',
    ]);
    register_sidebar([
        'name' => 'フッター',
        'id' => 'footer',
        'description' => 'フッターに表示されます。',
        'before_widget' => '<div id="%1$s" class="%2$s">',
        'after_widget' => '</div>',
    ]);
}
add_action('widgets_init', 'register_area');

サイドバーを一度だけ表示する完成版

完成版のfooter.phpには、get_sidebar()でsidebar.phpを読む処理と、同じsidebarを直接出力する処理が重なっていました。

実テーマでウィジェットが2回表示され、sidebar_widgetのIDも重複することを再現したため、footer.phpの直接出力を外しました。

下の画面ではサイドバーの検証リンクが1回だけ表示されます。

sidebar.phpにウィジェットを出す処理を置き、footer.phpはget_sidebar()で読み込む構成に統一してください。

本文の部分コードと完成版を重複して追記しないことも必要です。

2026年10月2日の検証環境で、PC幅1280pxとスマホ幅390pxの親子メニュー・本文・ウィジェットを確認しました。

子リンクをEnterで開くと、リンク先の記事本文へ移動します。

この段階の例はメニュー階層を通常のリストで表示しており、折りたたみ式のスマホメニューは実装していません。

掲載コードはクラシックテーマ用です。

外観のウィジェットで保存した内容と公開側を比べ、テーマのCSSで整える前にもリンクと本文が読めるか確認してください。

戻す場合は変更前のfooter.phpを復元します。

全デザインの完成やブロックテーマへの対応を確認した結果ではありません。

サイドバーを一度だけ出力し親子メニューを保持した自作テーマ画面
2026年10月2日、隔離WordPressで撮影した実画面です。

ウィジェットを保存して公開表示を確かめる

ウィジェットエリアの登録ができたら、「外観 → ウィジェット」でサイドバーを開き、段落ブロックへ確認用の文字を入力します。

更新して画面を開き直し、文字が残っていることを確認してください。

ウィジェットの保存とPHPファイルの保存は別の操作です。

本記事のfunctions.php・sidebar.php・footer.phpを組み合わせた検証テーマで、段落「サイドバー保存確認20261002」を追加し、更新後の再読み込みと公開表示を確認しました。

PC幅1280pxとスマホ幅390pxで、確認用の段落とsidebarのIDはいずれも1回だけ表示されています。

画像には検証環境に既存のウィジェットも写っています。

同じ文字が2回出る場合は、完成版のfooter.phpにget_sidebar()とdynamic_sidebar()を重ねて書いていないか確認します。

管理画面では保存できても公開側に出ない場合は、登録したIDとsidebar.phpの呼び出し先を照合してください。

確認後は追加した段落を外し、必要なら変更前のウィジェット設定とファイルへ戻します。

サイドバーへ保存した段落が1回表示される検証テーマの実画面
検証環境で保存した段落がサイドバーに1回表示された実画面。装飾前のテーマです。

メニューを保存して表示場所とリンク先を確認する

「外観 → メニュー」で作成したメニューを選び、投稿または固定ページの項目を追加します。

同じメニューを両方に表示する場合は、「グローバルメニュー」と「フッターメニュー」の両方を選択して保存します。

別の内容にする場合はメニューを分けて作成し、それぞれ対応する表示場所だけを選択して保存します。

編集画面を再読み込みして、項目名と選択した表示場所が保持されていることを確かめます。

テンプレートのwp_nav_menu()のtheme_locationを、functions.phpで登録したglobal_menuとfooter_menuに合わせてください。

表示場所の選択だけでは、テンプレートにメニューは追加されません。

公開側では長い項目名の折り返し、現在のページに付くcurrent-menu-item、Tabキーでの移動とEnterキーでのリンク先を確認します。

検証では1280pxと390pxの両方で保存した項目名が表示され、Enterキーで投稿へ移動できました。

元に戻すときは表示場所の選択を解除して保存し、テンプレートの変更もバックアップから戻します。

保存したメニューと表示場所の設定
2026年10月2日撮影/WordPress 7.1.2/記事のクラシックテーマ構成を使った検証環境。

まとめ

今まで気になっていたメニューとウィジェット。

どちらともに似たような設定から表示することができました。

応用すれば好きな場所に表示ができるということで、既存のテーマでも応用できると思います。

過去のコードは、GitHubのMOTOKI-LLC/WAZA-codeにもまとめていますが、本文と異なる場合は本文の構成を参照してください。

メニュー未割当時は fallback_cb を false にして自動ページ一覧を出さない設定です。

「外観 → メニュー」で各位置に割り当てます。

変更後はTabで各リンクに移動できること、現在位置の表示、スマホで長いメニュー名が収まることを確認してください。

2023年の画面は当時の記録です。

後半の2026年10月2日の実画面は、記載した検証環境で確認した結果です。

戻すときは変更前のテーマファイルへ復元します。

公式仕様:wp_nav_menu。

GitHubの過去コードと本文が異なる場合は、今回修正した本文を参照してください。

完成版のfunctions.phpでは、ブロックライブラリ・クラシックテーマ・グローバルスタイルのCSSを一括停止しません。

投稿本文やウィジェット内のブロック表示に必要なためです。

既に旧版を貼った場合は、global-styles-inline-css、classic-theme-styles、wp-block-libraryの停止処理を削除してください。

この変更はメニュー登録やウィジェット登録には影響しません。

  • URLをコピーしました!

制作をご依頼いただく場合

WordPressのホームページ制作

サイトの目的と更新方法に合わせて、構成・デザイン・WordPressの構築をご相談いただけます。対応範囲、制作実績、最新の費用・制作期間はサービスページをご確認ください。

WAZAの有料記事のサブスクリプションも開始しました。

サービス

Service

WordPressサイトのカスタマイズのサービスに関心がありましたら、ぜひ詳細をご覧ください。

目次