LaravelベースのWordPressテーマフレームワーク「Laraish」のご紹介

POSTED BY  
2017年1月19日

一言まとめ

WordPressのフレームワークはいろいろあるけど、MVCを取り入れたものがほとんどない。あってもフレームワーク自体がしょぼい。

それならフルスタックフレームワークのLaravelをWordPressで使いましょう!

仕事でよく企業様のコーポレートサイト制作にWordPressを利用しています。当然ですが、企業のHPですから、デザインは独自のものになります。なので、スクラッチから作成するのが常です。

スクラッチとは言っても、ゼロからではさすがにナンセンスですので、何かしらのフレームワークは使いたいものです。選択肢は実にたくさんあります。

ページビルダー機能を提供しているフレームワークもありますが、常にごりごりにカスタマイズする必要があるので、まだ仕事で使ったことがありません。個人的には機能がシンプルなものが一番合います。

ただ、最大の問題はそこではなく… ページビルダー機能がいいとか、シンプルがいいとか以前に、WordPressのテーマの作り方自体にあまり好感が持てません。そう、オーソドックスなMVC方式で作りたいのです!

そこで1つアイディアが浮かびました。「Laravel (PHP界隈で最も人気なフルスタックフレームワーク)をWordPressテーマの中でも使えるようにできないのか?」と。

そして作ったのが表題の「Laraish」です。

WordPressテーマの中で動くLaravel

Laravel はPHP用のWebアピリケーションフレームワークです。「美しいコード、洗練された文法、そして表現力の高さ」として知られています。一度使ってみれば確実に恋に落ちるやつですw

Laraish は そんな Laravel を WordPress でも使えるようにするテーマです。目的は、もっと楽に、もっと楽しく WordPress テーマを開発することです。

必要知識

Laravel をベースにしているので、当然 Laravel についての最小限の知識は必要です。初耳の方ならまずは公式サイトを覗いてみて、ちょっと触ってから戻ってきて下さい。

すでに Laravel をご存知である程度知識を持っているのであれば、すごく簡単に始められます。

オリジナルの Laravel とどこが違うの?

ほとんど差はないと言っても過言ではないです。WordPressでも動くよう、軽く調整したところはありますが、違いが気になる方はdiffしてみることをお勧めします。なので、基本的に Laravel でできることはすべてできると思って下さい。

インストール

Composer を使ってインストールします。composer create-project --prefer-dist laraish/laraish

注意:実行前に、MySQL と Webサーバーが起動中であることを確認して下さい。なぜなら、composer create-project コマンドでインストールが終わったあと、artisan コマンドが実行されます。artisan コマンドを実行するためには、実行時にWordPressが使っている MySQL と Webサーバーが動いている必要があります。

また、Mac でMAMPなどを使って環境構築しているのなら、ターミナルで参照しているPHPバイナリーがOSのPHPバイナリーではなく、MAMPなどのアプリが提供しているものにするために、$PATH環境変数を変えてあげる必要があります。

ルーティング

WordPress用のルートが指定できるように、オリジナルの UriValidator(Illuminate\Routing\Matching\UriValidator) を独自のものにすり替えています。

以下、使い方の例です

// "about" ページ
Route::any('page.about', [email protected]);

// "about" ページの子ページ "works"
Route::any('page.about.works', [email protected]);

// "about" ページの任意な子ページ
Route::any('page.about.*', [email protected]);

// "about" ページの任意な子孫ページ
Route::any('page.about.**', [email protected]);

// 共通の`prefix`のルートをまとめて指定
Route::group(['prefix' => 'page'], function () {

    Route::any('about.contact', function () {
        return 'Foo'; //  <page.about.contact> と等価
    });

    Route::any('service.*.price', function () {
        return 'Bar'; // <page.service.*.price> と等価
    });

});


// 注意 !
//
// 詳細度が高いルートは詳細度が低いルートの上(前)に置かなければならない。
// なぜなら、詳細度が低いルートが前に来ると、後の詳細度が高いルートが無視されるからです。
//
// 以下のルートは上のルートより詳細度が低いので、ここに置きましょう。

// すべてのページ
Route::any('page', [email protected]);

// フロントページ
Route::any('front_page', [email protected]); 

// アーカイブページ
Route::any('archive', [email protected]);

以下のことを覚えておきましょう。

  • ページとタクソノミーの階層は「ドット記法」で指定できます。
  • ウィルドカード(*)である 親/祖先 ページの 任意な 子/子孫ページを指定できます。
  • ルートが置かれる位置に気をつけて下さい。詳細度が高いルートは低いルートより上に置かなければならないです。

さらに、URIで独自のルートを追加することもできます。

// この場合、Laravel のオリジナルな UriValidator を使用する.
Route::get('/my/endpoint', function () {
    return 'Magic!';
});

モデル

Laraish では、PostTerm のような、WordPress用のモデルが使えます。ただ、これは Laravel の Eloquent モデルのような ORM ではなく、あくまでもWordPressのAPIのラッパーで、よくありがちなロジックをカプセル化して、ビジネスロジックを簡略化するために存在しています。

Laraish\WpSupport\Modelにすべてのモデルが入っています。中では一番よく使われるモデルはPostですから、Laraish\WpSupport\Model\Postを継承したクラスをapp/Models/Post.phpに配置してあります。

サンプルを見てみましょう。

以下のルートがあるとします

Route::any('archive', 'Generic\[email protected]');

そして、以下はそのコントローラー app\Http\Controllers\Generic\Archive です。

<?php

namespace App\Http\Controllers\Generic;

use App\Http\Controllers\Controller;
use App\Models\Post;

class Archive extends Controller
{
    public function index()
    {
        $data = [
            'posts' => Post::queriedPosts() // 現在ページのすべての投稿を取得する
        ];

        return $this->view('generic.archive', $data);
    }
}

以下はビュー generic.archive です。

<main class="posts">
    @foreach($posts as $post)
        <section class="post">
            <a class="post" href="{{ $post->permalink }}">
                <img class="post__thumbnail" src="{{ $post->thumbnail->url }}" alt="{{ $post->title }}">
            </a>
            <time class="post__time" datetime="{{ $post->dateTime }}">{{ $post->date }}</time>
            <a class="post__category" href="{{ $post->category->url }}">{{ $post->category->name }}</a>
            <h1 class="post__title">{{ $post->title }}</h1>
        </section>
    @endforeach

    {{  $posts->getPagination() }}
</main>

上記サンプルコードにある通り、Post オブジェクトから記事にまつわる一般的なプロパティを取得することができます。

例えば、$post->permalink$post->title 。一見して Post オブジェクトのプロパティにアクセスしているように見えますが、実際は「プロパティにアクセス」ではなく、「メソッドを実行する」か、「キャッシュから値を返す」かの処理になっています。

例えば、初回の $post->permalink$post->permalink() を実行して、結果を保存し、次回からその保存した値(キャッシュ)を使うようにしています。もしキャッシュを使いたくない場合、$post->permalink()のように、明示的にメソッドをコールして下さい。

このように、初回の(存在しない)プロパティへのアクセスは、実質的には同名のメソッドを呼んで戻り値を返すようになっています。つまり、モデルに public なメソッドを追加することで、新しい「プロパティ」を作ることができます。

どういった「プロパティ」があるのかについては、Laraish\WpSupport\Model を覗いてみて下さい。

@loop blade ディレクティブ

WordPressの The Loop を簡略するために、@loopディレクティブが追加されています。

例:

@loop($posts as $post)
	{{ get_the_title() }}
@endloop

上記は以下にコンパイルされる

wpPost ); ?>
                
    


ここでは、$postPost オブジェクトでなければならないです。

通常、@foreach の代わりに、@loop を使うべきではありません。なぜなら不必要な処理が走って効率が悪いからです。contentexcerpt といった「The Loop」の中でしか取得できない値を取得したい時に使って下さい、それ以外の時はなるべく使わないように。

テーマのオプション

カスタム投稿タイプを登録したり、ナビゲーションメニューを設定したり… テーマのビジネスロジックを作り始めるまでの前準備って結構煩雑だったりします。しかもどれもこれも似たようなタスクばかりでつまらないです。Laraishでは、そういった単純作業は app/config/theme.php で設定することになっています。

基本的なオプションは数多く用意されています。 どんなオプションがあるのかは config/theme.php をご参考下さい。

独自のオプションを追加したい場合、App\Providers\ThemeOptionsProviderに静的メソッドを追加します。追加されたメソッドの名前がそのままオプションとなります。

アクション と フィルター

Laravel の イベントと同じく、アクションとフィルターもApp\Providers\EventServiceProviderに記述することで登録することができます。

pre_get_posts アクションを追加する例を以下に示します。アクション発生時に App\Listeners\MainQueryListenerhandleメソッドが呼び出されます。

namespace App\Providers;

use Laraish\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * Register the WordPress actions
     * @var array
     */
    protected $action = [
            'pre_get_posts' => 'App\Listeners\MainQueryListener'
    ];

    /**
     * Register the WordPress filters
     * @var array
     */
    protected $filter = [];
}

ページネーション

ページネーションを生成する最も簡単な方法は Post オブジェクトの getPagination メソッドを使うことです。

use App\Models\Post;

$post = Post::queriedPosts();
{{ $posts->getPagination() }}

WordPressもページネーションを生成する関数を提供していますが、マークアップのカスタマイズ性がほぼないのが問題です。

getPagination()にオプションを渡すことで、viewファイルを指定するなど、幾つかの有用なオプションが用意されています。

例えば出力するページネーションをmenu式(select要素にする)にしたければ、$posts->getPagination(['type'=>'menu']) にします。

詳しくは laraish/pagination をご参照下さい。

オプション・ページ

WordPressのテーマを作る際に、最も泥臭い仕事の1つがオプション・ページを作ることでしょう…

WordPressのAPIを使って、実際にオプション・ページを作った人なら分かると思いますが、カオス以外の何物でもないのです…

Laraish はオプション・ページを作るためのクリンかつパワフルな API を提供します。

この機能を使うためには別途パッケージを追加する必要があります。
詳しくは laraish/options をご参照下さい。

View デバッガー

「このページってどのテンプレートファイルを使っているのか…?」と知りたくなる時がありますよね。そういったViewに関する基本的な情報は「View デバッガー」を使えばブラウザのコンソールから取得することができます。

App\Http\ControllersViewDebbuger trait を追加することで利用できます(デフォルトでは追加されています)。

ブラウザのコンソールを開けば以下のような情報が出力されます。

{
    "view_path": "/var/www/example/wp-content/themes/example/resources/views/singular/news.blade.php",
    "compiled_path": "/var/www/example/wp-content/themes/example/storage/framework/views/befa3e2a2cb93be21c6ebf30a60824a5d2a2ed11.php",
    "data": {
        "post": {}
    },
    "controller": "App\\Http\\Controllers\\Singular\\News"
}

また、.envファイルの中で、APP_ENV=productionが設定されている時、デバッグ情報は出力されないようになっています。

artisan の実行

インストールのほうでもちょっと触れましたが、artisan コマンドを実行するためには以下を注意して下さい。

  • MySQL サーバーと web サーバーが動いていること。
  • MacでMAMP或いは類似のアプリを使って環境構築をしているのなら、環境変数の$PATHを変える必要があるのかもしれません。例えば、php artisan key:generateを実行するとき、$PATHを変えなければphpはOSの内蔵版のPHPになるので、それをMAMP(或いは類似のアプリ)のPHPバイナリーにする必要があります。

まとめ

WordPressのテーマフレームワークっていろいろありますよね。

一般ユーザ向けのものだと、ページビルダー機能を提供しているフレームワークもありますが、「やはりMVCで作りたい」なら、Laraishを使いつつ、Visual Composer Unysonのようなページビルダープラグインを上手く利用するといいでしょう。

それと、Laravelをベースにしているので、パフォーマンスが心配な方もいるかもしれませんよね。結論から言いますと、環境にもよりますが、デフォルトのテーマより大体100ミリ秒前後の差が出ます。ただし、WordPressですから、結局キャッシュ系のプラグインか、サーバー側でページキャッシュを利用する場合が多いので、そんなに気にしなくても良いと思います!


Hi, 中国四川出身の王です。2008年に日本に渡り、大学卒業後Web制作会社勤務を経て、現在はフリーランスとしてゆるりと働いています。サイト制作の全般を担当しています。好きな生き物はプーティ(マイCat)です。趣味はアニメ鑑賞です。画家になるのが夢だったりします!

関連記事

AWSからエックスサーバーの「wpXクラウド」に乗り換えました(比較あり)
2017年2月3日
Web制作, WordPress
WordPressの「メディアライブラリ」のインポートが上手く行かない時の解決法
2016年11月22日
Web制作, WordPress
PHPの「遅延静的束縛 (Late Static Bindings)」機能、解読!
2016年10月31日
PHP, Web制作
PHPのアクセス権キーワード `private` と疑似変数 `$this` の落とし穴
2016年10月31日
PHP, Web制作
Cloudflareを使ってWordPressサイトをHTTPS化する時の流れとポイント
2016年10月25日
Web制作, WordPress
【CSS】img画像の縦横比を保ったままボックス内に収める方法
2016年8月25日
CSS, Web制作

Post a comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です