こんにちは、@ttskch です。
前回の記事 で、WordPress のテーマディレクトリ内に Silex アプリを構築することによって 固定ページをファイルベースで管理する というテクニックをご紹介しました。
今回はその発展編で、テンプレートに Twig を使う方法をご紹介します。 これでさらに WordPress サイトの管理が捗りますね。
はじめに
前回の記事 を読んで、Silex ベースのテーマを構築するところまでは終わっている前提で説明しますので、まだの方は確認してみてください。
また、Twig 導入後のサンプルを GitHub に置いておきました ので、参考にしながら読み進めてみてください。
目次
- まずは Twig をインストール
- TwigServiceProvider の設定
- レンダリング処理の変更
- WordPress タグを Twig 関数化
- テンプレートを Twig で書きなおす
- 番外編:もう少し index.php のコードをスッキリさせたい
まずは Twig をインストール
まずは Twig 自体のインストールです。composer で twig/twig をインストールします。
$ php composer.phar require twig/twig ">=1.8,<2.0-dev"
TwigServiceProvider の設定
Silex のフロントコントローラにしてある、テーマディレクトリ直下の index.php に、TwigServiceProvider の設定を追記します。
<?php
$app = new Silex\Application();
// use twig.
$app->register(new Silex\Provider\TwigServiceProvider(), [
'twig.path' => __DIR__ . '/views',
]);
これで、$app['twig']
に \Twig_Environment
クラスのインスタンスがセットされた状態になります。テンプレートディレクトリのパスは、前回作った views ディレクトリを指定しています。
レンダリング処理の変更
Twig 導入前は、テンプレート PHP から HTML をレンダリングするためのユーティリティを自前で用意していましたが、ここからはレンダリング処理はサービスにお任せでよいので、処理を変更します。
WordPress ページ用の処理
<?php
// for authors.
$app->get('/archives/author/{route}', function ($route) use ($app) {
return $app['twig']->render('author.html.twig');
})->assert('route', '.*');
// for posts.
$app->get('/archives/{route}', function ($route) use ($app) {
return $app['twig']->render('single.html.twig');
})->assert('route', '.*');
// for categories.
$app->get('/category/{route}', function ($route) use ($app) {
return $app['twig']->render('category.html.twig');
})->assert('route', '.*');
// for tags.
$app->get('/tag/{route}', function ($route) use ($app) {
return $app['twig']->render('tag.html.twig');
})->assert('route', '.*');
全部を記載しましたが、前回から変わったのはレンダリング処理だけです。
$app['twig]->render()
に、レンダリングしたいテンプレートファイルのパス (views からの相対パス) を渡せば OK です。
静的ページ用の処理
<?php
// default.
$app->get('/{route}', function ($route) use ($app) {
$template = 'pages/' . trim($route, '/') . '.html.twig';
try {
return $app['twig']->render($template);
} catch (Twig_Error $e) {
$template = 'pages/' . trim($route, '/') . '/index.html.twig';
try {
return $app['twig']->render($template);
} catch (Twig_Error $e) {
return $app['twig']->render('404.html.twig');
}
}
})->assert('route', '.*');
ここもほとんど変わってないのですが、前回 ファイルがなければ 404 をレンダリング、という処理を書いていたところを、Twig_Error の例外が発生したら という条件に変更しています。
WordPress タグを Twig 関数化
これで単純に Twig を使えるようにはなりましたが、これだけだと、困ったことに Twig 内で WordPress タグが使えません (当たり前ですが)。
そこで、WordPress タグのうち必要なものを Twig 関数として使えるようにしておきましょう。 TwigEnvironment の拡張方法は、公式のドキュメント で言及されています。
WordPress タグを Twig 関数として追加したい場合なら、例えばこんな感じになるでしょう。
<?php
// use twig.
$app->register(new Silex\Provider\TwigServiceProvider(), [
'twig.path' => __DIR__ . '/views',
]);
// add twig functions.
$app['twig'] = $app->share($app->extend('twig', function ($twig, $app) {
$twig->addFunction('bloginfo', new \Twig_SimpleFunction('bloginfo', 'bloginfo'));
$twig->addFunction('home_url', new \Twig_SimpleFunction('home_url', 'home_url'));
return $twig;
}));
他にも必要なものはここで追加しておきましょう。
TwigExtension を追加する
同様に TwigExtension の追加も簡単にできます。例えば、truncate
フィルタとかはあとあと使いたくなりそう (長いタイトルを 30 文字ぐらいに丸めたりとか) なので、試しに Twig_Extensions_Extension_Text を導入してみましょう。
まずはパッケージのインストールが必要です。例によって composer でインストールします。
$ php composer.phar require twig/extensions "~1.0"
あとは、さっきの Twig 関数の追加とほぼ同じ方法で追加するだけです。
<?php
$app['twig'] = $app->share($app->extend('twig', function ($twig, $app) {
$twig->addExtension(new \Twig_Extensions_Extension_Text($app)); // added
$twig->addFunction('bloginfo', new \Twig_SimpleFunction('bloginfo', 'bloginfo'));
$twig->addFunction('home_url', new \Twig_SimpleFunction('home_url', 'home_url'));
return $twig;
}));
自作のフィルタや関数は Twig Extension を作ってまとめておくとメンテしやすいかもしれませんね。
テンプレートを Twig で書きなおす
ここまでで Twig の環境は準備万端整いましたので、実際にビューのテンプレートを Twig に書き換えてみましょう。
例えば 投稿表示テンプレート (single.php) ならこんな感じでしょう。
Before (single.php)
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<h2><?php the_title(); ?></h2>
<p>著者:<?php the_author_posts_link(); ?></p>
<p>カテゴリ:<?php the_category(); ?></p>
<p><?php the_tags(); ?></p>
<p><?php the_content(); ?></p>
<?php endwhile; endif; ?>
After (single.html.twig)
{% for post in get_posts() %}
{% if have_posts() %}
{{ the_post() }}
<h2>{{ the_title() }}</h2>
<p>著者:{{ the_author_posts_link() }}</p>
<p>カテゴリ:{{ the_category() }}</p>
<p>{{ the_tags() }}</p>
<p>{{ get_the_content() }}</p>
{% endif %}
{% endfor %}
他のテンプレートも同じような感じで Twig に置き換えていけば完成です。
繰り返しになりますが、実際に動作可能なサンプルを GitHub に置いてあります ので、参考にしてみてください。
番外編:もう少し index.php のコードをスッキリさせたい
見ての通り、このままだとかなりの数の WordPress タグを Twig 関数化する必要があります。 実際、サンプルコードの Twig 拡張定義箇所はこんな感じになっちゃってます。
<?php
// add twig functions.
$app['twig'] = $app->share($app->extend('twig', function ($twig, $app) {
$twig->addExtension(new \Twig_Extensions_Extension_Text($app));
$twig->addExtension(new \Twig_Extension_Sample($app));
$twig->addFunction('bloginfo', new \Twig_SimpleFunction('bloginfo', 'bloginfo'));
$twig->addFunction('query_posts', new \Twig_SimpleFunction('query_posts', 'query_posts'));
$twig->addFunction('wp_reset_query', new \Twig_SimpleFunction('wp_reset_query', 'wp_reset_query'));
$twig->addFunction('home_url', new \Twig_SimpleFunction('home_url', 'home_url'));
$twig->addFunction('get_posts', new \Twig_SimpleFunction('get_posts', 'get_posts'));
$twig->addFunction('have_posts', new \Twig_SimpleFunction('have_posts', 'have_posts'));
$twig->addFunction('the_post', new \Twig_SimpleFunction('the_post', 'the_post'));
$twig->addFunction('the_permalink', new \Twig_SimpleFunction('the_permalink', 'the_permalink'));
$twig->addFunction('the_title', new \Twig_SimpleFunction('the_title', 'the_title'));
$twig->addFunction('get_the_content', new \Twig_SimpleFunction('get_the_content', 'get_the_content'));
$twig->addFunction('the_author', new \Twig_SimpleFunction('the_author', 'the_author'));
$twig->addFunction('the_category', new \Twig_SimpleFunction('the_category', 'the_category'));
$twig->addFunction('the_tags', new \Twig_SimpleFunction('the_tags', 'the_tags'));
$twig->addFunction('single_cat_title', new \Twig_SimpleFunction('single_cat_title', 'single_cat_title'));
$twig->addFunction('single_tag_title', new \Twig_SimpleFunction('single_tag_title', 'single_tag_title'));
$twig->addFunction('the_author_posts_link', new \Twig_SimpleFunction('the_author_posts_link', 'the_author_posts_link'));
return $twig;
}));
ここで登録している WordPress タグのほとんどは投稿の情報を取得するためのものなので、投稿の情報を配列で返してくれるユーティリティとかを作っておいて、
<?php
// routing for categories.
$app->get('/category/{route}', function ($route) use ($app, $util) {
return $app['twig']->render('category.html.twig', [
'posts' => $util->getPosts('post_type=post&posts_per_page=10'),
]);
})->assert('route', '.*');
みたいな感じでビューに渡してあげるようにしておけば、ビュー側で WordPress タグが必要になるケースはかなり減るんじゃないかと思います。
余力のある人はチャレンジしてみてください :)