WordPress構築 ②テーマ開発

#PHP #WordPress #テーマ開発

今回はFigmaMakeで静止したテーマのプロト(静的HTML/CSS)を、WordPressのテーマ化していく。
理解したことを順番に整理しておく。

WordPressがページを表示する仕組み

まずここを理解しないと始まらなかった。
静的サイトはHTMLファイルをそのままブラウザに返すだけだが、WordPressは違う。

ブラウザ → WP(PHP)がURLを解析
        → 対応するテンプレートファイルを選ぶ
        → データベースから記事を取得
        → HTMLを組み立てて返す

「事前にHTMLを書いておく」のではなく「PHPがその都度HTMLを組み立てる」。
この違いを最初に意識するかどうかで、その後の作業の見通しが変わった。

やったこと:9つのステップ

テーマ化の作業はこの流れで進めた。

  1. style.css にテーマ情報コメントを追記
  2. functions.php を作成
  3. header.php / footer.php に共通パーツを分割
  4. index.php で記事一覧ループを実装
  5. single.php で個別記事ページを実装
  6. sidebar.php を作成
  7. page.php で固定ページを実装
  8. archive.php でカテゴリー・タグ共通のアーカイブページを実装
  9. 404.php で「ページが見つからない」を実装

順番に理解したことを書く。

Step 1:style.css がテーマの身分証になる

WordPressは wp-content/themes/ の中のフォルダをテーマとして認識するが、そのために style.css の先頭に特定のコメントブロックが必要だと初めて知った。

/*
Theme Name: 理解をかたちに
Author: 菜の花
Version: 1.0
*/

これだけで管理画面の「外観 → テーマ」に表示される。
ファイルの中身より、このコメントがテーマの「名札」になっている。

Step 2:CSSの読み込みは functions.php に任せる

静的HTMLでは <link rel="stylesheet" href="style.css"> と直書きしていたが、
WordPressではこれをやらず、functions.php で登録する。

function rikai_enqueue_styles() {
    wp_enqueue_style('rikai-style', get_stylesheet_uri(), [], '1.0');
}
add_action('wp_enqueue_scripts', 'rikai_enqueue_styles');

なぜ直書きではダメかというと、WordPressはプラグインやテーマが出力するCSSを一元管理していて、wp_head() というフックがそれをまとめて <head> に出力する仕組みだからだ。
直書きすると、WPの管理から外れてしまう。

add_action という書き方は、「このタイミングでこの処理を走らせて」とWordPressに予約する仕組みで、「フック」と呼ばれる。
WordPressのコードはこのフックを使ってあちこちに処理を差し込む設計になっていた。

Step 3:header.php / footer.php に分割する

3つのHTMLファイルに重複して書いていた <header> と <footer> を、それぞれ1ファイルに切り出した。
各テンプレートからは1行で呼び出せる。

<?php get_header(); ?>
<!-- ページ固有のコンテンツ -->
<?php get_footer(); ?>

このとき重要だと知ったのが wp_head() と wp_footer() の存在だ。

// header.php の </head> 直前
<?php wp_head(); ?>

// footer.php の </body> 直前
<?php wp_footer(); ?>

プラグインが管理画面から有効化されると、必要なCSSやJSがこのフックに自動で差し込まれる。
逆に言えばこれを書いていないと、プラグインが動かないことがある。省略してはいけない。

Step 4:ループが記事一覧の核心

index.php で最も重要な概念がWordPressのループだ。

while (have_posts()) : the_post();
    // この中でタイトルや本文を出力する
endwhile;

have_posts() でデータベースに記事があるか確認し、the_post() で1件分のデータをセットして出力する。
それをループで繰り返す。
データベースアクセスの仕組みがここに凝縮されている感じがした。

もうひとつ工夫したのが、カテゴリーによる色分けだ。
静的HTMLでは card__thumb--green のようなクラスを手書きしていた。
PHPでは記事のカテゴリー名を取得して、対応するクラスを動的に出し分けた。

$color_map = ['技術メモ' => 'green', '制作ノート' => 'yellow', '学びと思考' => 'sand'];
$cats  = get_the_category();
$color = $color_map[$cats[0]->name] ?? 'green';

記事を増やしても色の管理をHTMLで気にしなくていい。
これが「動的に出力する」ことの実感だった。

注目記事は「スティッキー投稿(先頭固定)」というWordPressの機能に対応させた。
管理画面から記事をスティッキーに設定するだけで自動的に注目記事として表示される。

Step 5:single.php で個別記事の動的化

個別記事ページで一番「楽になった」と感じたのが本文の出力だ。

<div class="post__body">
    <?php the_content(); ?>
</div>

静的HTMLで長々と書いていた記事本文が、この1行に置き換わる。
ブロックエディタで書いた内容がそのまま出力される。

前後記事のナビゲーションも、タイトルを直書きしていた部分が関数1つになった。

$prev = get_previous_post();
$next = get_next_post();

投稿日順に自動で前後が決まる。
記事を追加するたびにHTMLを書き直さなくていい。

Step 6:sidebar.php でサイドバーを動的化

サイドバーにあった「最近の記事」「カテゴリー一覧」「タグ」はすべて直書きだったが、
それぞれWPの取得関数に置き換えた。

カテゴリーのアクティブ状態(今いるページのカテゴリーに色が付く)も、
WordPressが用意している判定関数で自動化できた。

is_home()          // トップページかどうか
is_category($slug) // このカテゴリーアーカイブページかどうか

静的HTMLではページごとに class="cat-list__link--active" を手動で書き分けていたが、これが不要になった。

Step 7:page.php で固定ページに対応

Aboutページ(固定ページ)用のテンプレートだ。
the_content() で冒頭の紹介文はエディタから編集できるようにして、デザインとして固定された部分(カテゴリー紹介・プロフィールカード・ブログ情報)はテンプレートに直書きのままにした。

固定ページを作成するには、まず管理画面でページを作ってから、メニューに追加する必要があった。
「ページが存在してからメニューに追加できる」という当たり前の順番を、実際に試して確認した。

Step 8:archive.php でカテゴリー・タグ共通のアーカイブページを実装

WordPressのテンプレート階層では、カテゴリーとタグは別物として扱われる。
カテゴリー・タグそれぞれの専用テンプレート(category.php / tag.php)が無い場合、共通の archive.php がフォールバック先になる仕組みだ。今回はそちらを使用する。

Step 9:404.php で「ページが見つからない」を実装

専用テンプレートが無いと index.php にフォールバックする仕組みは、404ページにも同じように影響する。
存在しないURLにアクセスしても専用テンプレートが無ければ、トップページのヒーローセクションやスティッキー投稿のロジックがそのまま出てきてしまうので404.php を新規に作成し、ヒーローセクションと同じ見た目のパーツを流用して、案内文とトップページへのリンクだけを置いたシンプルな構成にした。

<?php get_header(); ?>

<section class="hero">
  <div class="hero__accent"></div>
  <h1 class="hero__title">ページが見つかりませんでした</h1>
  <p class="hero__desc">お探しのページは移動または削除された可能性があります。</p>
</section>

<p class="section-label"><a href="<?php echo home_url('/'); ?>">← トップページへ戻る</a></p>

<?php get_footer(); ?>

一通り機能を実装し終えても、テンプレート階層の抜けは自分では気づきにくい。
「実際に全パターンのURLを踏んでみる」というひと手間が必要だと分かった。

できあがったテーマの構成

テーマフォルダ/
├── style.css       テーマ情報 + 共通スタイル
├── functions.php   CSS登録・メニュー登録・ヘルパー関数
├── header.php      共通ヘッダー
├── footer.php      共通フッター
├── sidebar.php     サイドバー
├── index.php       記事一覧(ループ)
├── archive.php     カテゴリー・タグ共通アーカイブ
├── single.php      個別記事
├── page.php        固定ページ
├── 404.php         ページが見つからない場合
├── post.css        記事ページ専用スタイル
└── about.css       固定ページ専用スタイル

やってみて分かったこと

一番の気づきは「HTMLを書かなくなった」ことだ。
管理画面で記事を1本投稿すれば、一覧・個別ページ・サイドバーの最近の記事・カテゴリー件数、すべてが自動で更新される。静的HTMLのとき手動で更新していた部分が、テーマさえ作ってしまえば不要になる。

もうひとつは、WordPressの「出力するHTMLはWPが決める」という設計だ。
wp_nav_menu() のように、関数に設定を渡すとHTMLを生成してくれる。
このHTMLの構造を理解してCSSを書く必要がある。

静的HTMLのときは「自分でHTMLを書いてCSSを当てる」だったが、テーマ開発は「WPが出すHTMLに対してCSSを書く」という逆順になる場面がある。
デザインが崩れたときはここを疑うと良い。

デザインプロトタイプがそのまま動くテーマになったのは、最初からWordPress化を前提にしてHTML/CSSを書いていたからだと思う。
クラス名やレイアウト構造を後から大幅に変える必要がなかった。
設計段階で先を考えておくことの意味を実感できた。