第3回:WordPressテーマのテンプレート分離とナビゲーションメニュー実装 - header.phpとfooter.phpで保守性アップ

はじめに

Miyagi です。WordPress テーマ開発プロジェクトの 3 日目です! 前回は Claude Code を活用して WordPress の簡単なテーマをバイブコーディングで実装しました。でも、よく見るとindex.phpsingle.phpに同じヘッダーやフッターのコードが重複していて、これは保守性が悪いな…と気づきました。今日はテンプレートを適切に分離して、より実用的なテーマに進化させていきます!

目次

 

概要

結論として、テンプレート分離によってコードの重複が解消され、保守性の高いテーマ構造になりました。

今日はheader.phpfooter.phpへの分離、ナビゲーションメニュー機能の実装、固定ページ用のpage.php作成など、実用的なテーマに必要な機能を追加していきました。Claude Code に適切なプロンプトを投げることで、WordPress のベストプラクティスに沿った実装ができました。

 

テンプレートファイルの分離

まずは重複しているヘッダーとフッターのコードを分離することにしました。

使用したプロンプト:

「index.php と single.php の共通部分を header.php と footer.php に分離してください。
get_header()と get_footer()を使った実装でお願いします」

Claude Code の実装結果:

  • header.php: サイトのヘッダー部分(DOCTYPE、head、サイトタイトルなど)
  • footer.php: サイトのフッター部分(コピーライト、閉じタグなど)
  • index.phpsingle.phpの書き換え

実装のポイント: get_header()get_footer()を使うことで、自動的にheader.phpfooter.phpを読み込むようになります。これによりコードの重複が解消され、デザインの変更も一箇所で済むようになりました。

<?php get_header(); ?>
<!-- メインコンテンツ -->
<?php get_footer(); ?>

この構造、Vue.js のコンポーネント分割と似た考え方で、すごく理解しやすかったです。 だだ、header.php と footer.php に分離しただけでは見た目では判別が難しいです。 Claude Code に指示を出して、装飾してもらいましょう。

使用したプロンプト:

現状のコードでは、見た目では分からないため、分離化ができたかどうか判別がつきません。
header.php と footer.php に何か簡単な装飾をしてください。

成果物: WordPress テーマ開発 Day3 Step1 ヘッダーは緑、フッターは黒で装飾してくれました!いい感じです。

 

ナビゲーションメニューの実装

次に、ユーザーがサイト内を移動しやすくするためのナビゲーションメニューを実装しました。

追加プロンプト:

「WordPress のカスタムメニュー機能を使えるようにしたいです。
管理画面からメニューを設定できるようにしてください」

Claude Code が追加してくれた機能:

  • functions.phpの作成
  • register_nav_menus()によるメニュー位置の登録
  • header.phpへのwp_nav_menu()の追加
  • メニュー用の基本 CSS

実装後の流れ:

  1. WordPress 管理画面で「外観 > メニュー」が使えるように
  2. メニュー項目を自由に追加・編集可能に
  3. header 部分に自動でメニューが表示される

これでやっと Web サイトらしい見た目になってきました!管理画面から簡単にメニューを編集できるのは便利ですね。

 

固定ページテンプレートの追加

ブログの記事以外に、「会社概要」や「お問い合わせ」のような固定ページも必要になることが多いので、page.phpを作成してもらいました。

プロンプト内容:

「固定ページ用のテンプレート page.php を作成してください。
single.php とは少し違うレイアウトにしたいです」

Claude Code の実装:

  • page.phpの作成
  • 固定ページ専用のスタイル
  • ナビゲーション機能の除外(固定ページでは前後の記事リンクは不要)

WordPress のテンプレート階層: WordPress は自動的に適切なテンプレートを選択してくれます:

  • 投稿 → single.php
  • 固定ページ → page.php
  • トップページ → index.php

この仕組み、最初は複雑に感じましたが、使ってみると理にかなっていて分かりやすいです。

 

functions.php の活用

functions.phpは WordPress テーマの機能を拡張する重要なファイルです。今日はメニュー機能を使用しました。

functions.php の基本構造:

<?php
// メニューの登録
function my_theme_setup() {
    register_nav_menus(array(
        'primary' => 'プライマリーメニュー'
    ));

    add_theme_support('post-thumbnails');
    add_theme_support('title-tag');
}
add_action('after_setup_theme', 'my_theme_setup');

成果物:

  • ヘッダーメニュー WordPress テーマ開発 Day3 Step2
  • 固定ページ WordPress テーマ開発 Day3 Step3

固定ページに遷移するメニューと固定ページの作成ができました。 TypeScript でフックを使うような感覚で、WordPress のadd_action()でテーマ機能を拡張できるんですね。 また、メニュー機能以外にも以下の機能があるようです。これらは今後の実装で試してみたいと思います。

拡張可能な機能:

  • アイキャッチ画像のサポートadd_theme_support('post-thumbnails')
  • タイトルタグの自動生成add_theme_support('title-tag')
  • ウィジェットエリアの登録:サイドバーやフッター用

 

まとめ

Day 3 で大きく進化したテーマ構造を振り返ります。

🎯 達成できたこと

  • header.php、footer.php へのテンプレート分離
  • コードの重複解消と保守性向上
  • ナビゲーションメニュー機能の実装
  • 固定ページ用テンプレート(page.php)の作成
  • functions.php によるメニュー表示

📂 現在のファイル構成

wp-content/themes/my-first-theme/
├── index.php        # メイン投稿一覧
├── single.php       # 記事詳細ページ
├── page.php         # 固定ページ
├── header.php       # ヘッダー共通部分
├── footer.php       # フッター共通部分
├── functions.php    # 機能拡張
└── style.css        # テーマ情報・スタイル

💻 コード

  index.php

<?php get_header(); ?>

<main>
  <?php if (have_posts()) : ?>
  <?php while (have_posts()) : the_post(); ?>
  <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>
    >
    <h2>
      <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
    </h2>
    <div class="post-content">
      <?php the_content(); ?>
    </div>
    <div class="post-meta">
      <p>
        投稿日:
        <?php the_date(); ?>
        | 投稿者:
        <?php the_author(); ?>
      </p>
    </div>
  </article>
  <?php endwhile; ?>
  <?php else : ?>
  <p>投稿が見つかりませんでした。</p>
  <?php endif; ?>
</main>

<?php get_footer(); ?>

  header.php

<!DOCTYPE html>
<html <?php language_attributes(); ?>
  >
  <head>
    <meta charset="<?php bloginfo('charset'); ?>" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title><?php bloginfo('name'); ?></title>
    <?php wp_head(); ?>
  </head>
  <body <?php body_class(); ?>
    >
    <div class="container">
      <header
        style="background-color: #4CAF50; color: white; padding: 20px; border-radius: 5px; margin-bottom: 20px;"
      >
        <h1>
          <a
            href="<?php echo home_url(); ?>"
            style="color: white; text-decoration: none;"
            ><?php bloginfo('name'); ?></a
          >
        </h1>
        <p style="margin: 0; font-style: italic;">
          📄
          <?php bloginfo('description'); ?>
        </p>

        <nav
          style="margin-top: 15px; padding-top: 15px; border-top: 1px solid rgba(255,255,255,0.3);"
        >
          <?php
                wp_nav_menu(array(
                    'theme_location' =>
          'primary', 'container' => false, 'menu_class' => '', 'items_wrap' => '
          <ul
            style="list-style: none; padding: 0; margin: 0; display: flex; gap: 20px; flex-wrap: wrap;"
          >
            %3$s
          </ul>
          ', 'link_before' => '', 'link_after' => '', )); ?>
        </nav>
      </header>
    </div>
  </body>
</html>

  footer.php

        <footer style="background-color: #333; color: white; padding: 20px; border-radius: 5px; margin-top: 40px; text-align: center;">
            <p style="margin: 0;"<?php echo date('Y'); ?> <?php bloginfo('name'); ?> | ✨ Powered by WordPress</p>
        </footer>
    </div>
    <?php wp_footer(); ?>
</body>
</html>


  functions.php

<?php
// テーマのセットアップ
function my_theme_setup() {
    // メニューの登録
    register_nav_menus(array(
        'primary' =>
'プライマリーメニュー', )); } add_action('after_setup_theme', 'my_theme_setup');
// メニューのリンクにスタイルを追加 function
my_theme_nav_menu_link_attributes($atts, $item, $args) { if
($args->theme_location == 'primary') { $atts['style'] = 'color: white;
text-decoration: none; padding: 8px 12px; background-color:
rgba(255,255,255,0.2); border-radius: 4px; display: block; transition:
background-color 0.3s;'; } return $atts; }
add_filter('nav_menu_link_attributes', 'my_theme_nav_menu_link_attributes', 10,
3);

💡 学んだこと

  • WordPress のテンプレート階層の仕組み
  • DRY 原則(Don’t Repeat Yourself)の重要性
  • get_header()get_footer()などのテンプレートタグの使い方
  • functions.phpでのフック活用

テンプレートを分離することで、コードがすっきりして管理しやすくなりました。Vue.js でコンポーネント分割するのと似た感覚で、WordPress の設計思想が理解できてきた気がします。次回(第4回)では、functions.php について深掘りしていく予定です。

 

最後まで読んでいただき、ありがとうございました!
この記事が少しでもお役に立てれば嬉しいです。良い開発ライフを!