2018.10.14

Laravelエンジニアが考えたWordPressテーマ開発環境


この記事では、普段 Laravel を使って開発しているエンジニアが WordPress テーマを作成する際にできるだけ違和感のない環境を作成する方法を紹介します。

いつも View まわりで使っている技術を取り入れようということで、テンプレートエンジンに Blade を、Sass コンパイルに Laravel Mix を使用します。

準備

WordPress

インストール

Codex に書かれている通りですが…。

$ wget http://wordpress.org/latest.tar.gz
$ tar -xzvf latest.tar.gz
$ rm -f latest.tar.gz

テーマディレクトリ作成

テーマの名前はもちろん任意です。

$ cd wordpress/wp-content/themes
$ mkdir mytheme

Composer

インストール

PHP パッケージマネージャ Composer を使って Blade ライブラリをインストールするので、まずは Composer 自体をマシンにインストールします。

$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('SHA384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"
$ mv composer.phar /usr/local/bin/composer

初期化

composer init コマンドでパッケージ管理のための設定ファイルを生成します。

$ composer init

Package name (<vendor>/<name>) [masahiro.harada/mytheme]:
Description []:
Author [Masahiro Harada <******@***.com>, n to skip]:
Minimum Stability []:
Package Type (e.g. library, project, metapackage, composer-plugin) []:
License []:
Would you like to define your dependencies (require) interactively [yes]? no
Would you like to define your dev dependencies (require-dev) interactively [yes]? no
Do you confirm generation [yes]?

「Would you like to define〜」と聞かれる2行以外は何も入力せずエンターでOKです。

Bladeテンプレート

今回はテンプレートエンジンとして Blade を使用します。そもそもは Laravel フレームワークの一部ですが、切り離して独立したライブラリにしたバージョンを使います。

なぜテンプレートエンジン?

初めて WordPress に触れて簡単なテーマを自作しようと思い、同梱されているテーマのソースコードを調べてみるとなんとも居心地が悪いです 🙃

たとえばヘッダー部品のファイルを見ると…

<html>
    <head>
        <meta ...>
        <?php wp_head(); ?>
    </head>
    <body>
        <header id="...">
            <?php // ... ?>
        </header>
        <div class="site-content-contain">
            <div id="content" class="site-content">

途中で終わっています。タグの対応関係が正しいかとか、ワケ分からなくなりそうです。

あと制御構文がとにかく見づらい!

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
    <!-- ここに記事一件分を出力するコードを書く -->
<?php endwhile; else : ?>
    <p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>
<?php endif; ?>

このような記述の分かりにくさはテンプレートエンジンを使えば解消できます。

Bladeの機能

簡単に Blade でできることを紹介します。

変数出力

波カッコ2つで変数の値を出力します。

<h1>{{ bloginfo('name') }}</h1>

こちらと同じ意味です。

<h1><?php echo bloginfo('name'); ?></h1>

制御構文

アットマーク @ をつけたキーワードで読みやすい制御構文を表現できます。

<!-- 条件分岐 -->
@if ($var === true)
  <p>Hello</p>
@else
  <p>Goodbye</p>
@endif

<!-- 繰り返し -->
@foreach ($posts as $post)
  <li>{{ $post->title }}</li>
@endforeach

上記はこちらと同じ意味です。

<!-- 条件分岐 -->
<?php if ($var === true) : ?>
  <p>Hello</p>
<?php else : ?>
  <p>Goodbye</p>
<?php endif; ?>

<!-- 繰り返し -->
<?php foreach ($posts as $post) : ?>
  <li>{{ $post->title }}</li>
<?php endforeach; ?>

やっていることは同じですが、php タグを省略できるだけでかなり読みやすくなると思います。

レイアウト

レイアウトとは、各ページの HTML で共通の外枠のことです。WordPress というか PHP には標準でそのような機能がないので途中で終わるヘッダー部品などが出てきてしまいます。

レイアウトファイルはこのような内容になります。

レイアウト
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>ブログの名前</title>
</head>
<body>
    <main>
      @yield('content')
    </main>
</body>
</html>

テンプレートから HTML を作成するときに @yield('セクション名') の部分にページごとのコンテンツが挿入されます。ページごとのテンプレートは以下のようになるでしょう。

ページ
@extends('layout')

@section('content')
  <h1>コンテンツだよ</h1>
@endsection

まず @extends('レイアウトファイル名') でどのレイアウトを使うか指定します。そして @section('セクション名')@endsection の間に差し込みたい内容を記述します。

以下の HTML が最終的に生成されます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>ブログの名前</title>
</head>
<body>
    <main>
        <h1>コンテンツだよ</h1>
    </main>
</body>
</html>

インクルード

インクルードは部品化したテンプレートファイルを読み込む機能です。

<body>
    @include('header')
</body>

@include('テンプレート名') と記述すると、テンプレート名.blade.php というファイルが探し出され(Blade テンプレートの拡張子は .blade.php です)…

header.blade.php
<header>ヘッダーだよ</header>

結果的にこのような HTML が出来上がります。

<body>
    <header>ヘッダーだよ</header>
</body>

とりあえずこれくらいの機能が分かれば便利に使えると思います。より詳しい Blade の機能や書き方についてはマニュアルを参照してください。

インストール

さて、インストール手順を紹介していきましょう。といっても Composer で一発です。

$ composer require jenssegers/blade

インストールが成功すると vendor というディレクトリが作成されていて、その中にインストールしたライブラリが配置されています。覗いてみると Blade 以外のライブラリも入っていますが、Blade が動作するために必要なライブラリなので問題ありません。

次に viewscache というディレクトリを作成してください。どちらもテンプレートエンジンのために必要です。

$ mkdir views cache

views は Blade テンプレートファイルを格納する場所で、cache はテンプレートファイルから変換された普通の PHP ファイルをキャッシュとして格納する場所です。

Git で管理する場合は、cache ディレクトリの下に作成された PHP ファイルを無視するために .gitignore ファイルを置きましょう。

$ touch cache/.gitignore
cache/.gitignore
*
!.gitignore

functions.php

準備が整いましたのでまずは functions.php を作成しましょう。

Blade テンプレートをふつうの PHP ファイルに変換する関数を記載します。functions.php に書いておけば、あとで index や single など各種ページでこの関数を使いまわすことができます。

functions.php
<?php

require_once(__DIR__ . '/vendor/autoload.php');

use Jenssegers\Blade\Blade;

/**
 * Bladeテンプレートをレンダリングする
 */
if (!function_exists('render_blade')) {
    function render_blade($template_name)
    {
        $blade = new Blade(__DIR__ . '/views', __DIR__ . '/cache');

        return $blade->make($template_name);
    }
}

レイアウト

次にレイアウトファイルです。

views/layout.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>{{ bloginfo('name') }}</title>
    <link rel="stylesheet" href="{{ get_template_directory_uri() }}/style.css">
</head>
<body>
    @include('share.header')
    <main>
      @yield('content')
    </main>
    @include('share.footer')
</body>
</html>

ヘッダーとフッターは部品化してインクルードします。

共通パーツ

他のファイルからインクルードされるパーツです。

こちらがヘッダー。

views/header.blade.php
<header>
  <nav>
    <a href="/">{{ bloginfo('name') }}</a>
  </nav>
</header>

そしてフッターです。

views/footer.blade.php
<footer>
  This is a footer.
</footer>

indexページ

ここから各ページの作成です。固定ページや 404 などいろいろ種類はあるようですが、今回は index と single のみ作成します。他のページも同じ手順で作成できるはずです。

index.php

index.php にはテンプレートをレンダリング(HTML に変換)する処理のみを記載します。

index.php
<?php

echo render_blade('index');

functions.php に定義した関数を呼び出します。引数はテンプレートの名前だったので、views/引数.blade.php というファイルがレンダリングされます。

テンプレート

ふだん index.php に書く内容はテンプレートに記述します。ふつうに php タグも使えます。echo する必要がある場合は {{}} で、関数を実行すればいいだけの場合は php タグのままという使い分けになるでしょう。

views/index.blade.php
@extends('layout')

@section('content')
    <div class="container">
        <ul>
            @if (have_posts())
                @while (have_posts())
                    <?php the_post(); ?>
                    <li>
                        <a href="{{ the_permalink() }}">{{ the_title() }}</a>
                    </li>
                @endwhile
            @endif
        </ul>
    </div>
@endsection

テンプレートファイルも結局は機能が追加された PHP ファイルなので、index.php などに書いていた内容はそのままテンプレートにも書くことができます。

singleページ

single も index ページと同様です。

single.php

single.php
<?php

echo render_blade('single');

テンプレート

views/single.blade.php
@extends('layout')

@section('content')
    <div class="container">
        @if (have_posts())
            @while (have_posts())
                <?php the_post(); ?>
                <article>
                    <h1>{{ the_title() }}</h1>
                    <div class="content">
                        {{ the_content() }}
                    </div>
                </article>
            @endwhile
        @endif
    </div>
@endsection

index ページと single ページだけを紹介しましたし、中身もスカスカですが、あとは完成図に応じて記述を増やしていけば OK です。

続いて Sass のコンパイル方法を紹介します。

Laravel Mix

Sass のコンパイルには Laravel エンジニアにはおなじみの Laravel Mix を使用します。Laravel に標準で同梱されていて、簡単な設定で Sass や ES2015 のコンパイルができる便利なライブラリです。Webpack の設定を自動生成してくれるライブラリという理解でいいのではないでしょうか。Laravel のドキュメントにも説明があるのでそちらも参照してください。

インストールと設定

インストール

インストールは npm で行います。npm がなければ Node.js をダウンロードしましょう。npm も一緒についてきます。

$ npm init -y
$ npm i -D laravel-mix

webpack.mix.js

インストールできたら設定ファイルを作成します。

$ touch webpack.mix.js

Sass コンパイルのために sass メソッドを使います。第一引数がコンパイル元で第二引数がコンパイル先です。

webpack.mix.js
let mix = require('laravel-mix');

mix
  .sass('src/sass/style.scss', './style.css')
  .options({
      processCssUrls: false
   });

options メソッドでコンパイル時の設定を指定します。例えば上記の processCssUrls の記述はマニュアルにもある通り、Webpack が Sass ファイル中の url() の画像パスを書き換えないようにするための指定です。

package.json

package.json にコンパイル実行のための以下のスクリプトを追加します。

package.json
{
  "scripts": {
    "dev": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "hot": "NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  },
}

Sassでスタイルシートを作成

設定が完了したのでスタイルシートを書きましょう!

$ mkdir -p src/sass
$ touch src/sass/styles.scss

WordPress のテーマなので Styles にはコメントが必要ですね。

src/sass/styles.scss
/*!
Theme Name: MyTheme
Author: Masahiro Harada
Description: My Theme
*/

body {
  h1 {
    color: red;
  }
}

注意していただきたいのは、一行目の末尾の ! です。このビックリマークがなければ本番ビルドした際にコメントは除去されてしまいます。ファイルサイズを減らすために必要な機能なのですが、style.css の冒頭のコメントだけはないとテーマとして認識されないので、! をつけています。

スタイルシートができたら以下のコマンドでコンパイルができます。

// 開発用ビルド
$ npm run dev

// 監視モード(ファイルが変更されたら自動的に開発ビルドが走る)
$ npm run watch

// 本番用ビルド(ミニファイされる)
$ npm run production

開発中は npm run watch で、本番にリリースする直前に production コマンドを実行するような手順になるでしょう。

今回は Sass のコンパイルのみ紹介しましたが、ES2015 や Vue のトランスパイルも可能です。


いかがだったでしょうか。最近になって初めて WordPress に触れてみて、特定の用途では便利そうな反面、コードはかなーりレガシーだなと感じたので、Laravel フレームワークで使われる便利なツール(テンプレートエンジン Blade と Laravel Mix)を WordPress でも使う方法を紹介しました。