ループ処理をJade(Pug)mixinで部品化

2018年3月2日に加筆・修正をしました。

Jade(事情があって現在はPug)はHTMLをインデント記法で書けるテンプレートエンジンです。ファイルの拡張子は.pug(.jade)。gruntやgulp用のモジュールがあるので、それらをインストールして使うことが多いと思いますが、npm-scriptsでも使えるようです。

タグを記述する必要がなく変数が使えるほか、javascriptが書けるので通常のマークアップではできない処理ができます。ファイルの読み込みやmixin作成もできるので、コードの部品化に使えます。

今回はWordpressでWebサイト制作を行う場合について。

公式サイト

Pug

部品化の考え方

スニペットをまとめておいて呼ぶ方法もありますが、機能ごとに分けておいたのちに必要に応じて組み合わせて使用する方法を例として挙げます。

例1:メインループで投稿一覧を表示する

WordPressでループを処理する場合、下記のような工程を踏みます。

  1. 投稿があるかどうか判定して投稿がある場合はループ開始
  2. 必要な処理
  3. ループを終了
  4. ループの条件(クエリ)をリセット

では、このうちの1、3、4の工程をそれぞれ部品にしてみます。

部品化

1. loop_start.php / 投稿があるかどうか判定して投稿がある場合はループ開始

<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

3. loop_end.php / ループを終了

<?php endwhile; else: ?>
<p>申し訳ありません。投稿はまだありません。</p>
<?php endif; ?>

4. reset.php / ループの条件(クエリ)をリセット

<?php wp_reset_postdata(); ?>

サブループ用に作っておきます。

ファイル

部品化したコードを下記のような構造でファイル保存したとします。_mixin.jadeについては後述。

wpjade
    │
    ├ single.jade / 個別記事用ファイル。single.phpにコンパイル
    │
    └ templates
        └ php
            ├ _mixin.jade
            ├ loop_start.php
            ├ loop_end.php
            └ reset.php

使用例

部品化したコードを使って実際にループ処理をしてみます。

single.jade

include ./templates/php/loop_start.php
section
    h2: a(href!='<?php the_permalink(); ?>') <?php the_title(); ?>
    p <?php the_content(); ?>
include ./templates/php/loop_end.php

mixin化

ファイルの読み込み記述が面倒な場合は_mixin.jadeの内容を下記のようにして読み込めばコードの見通しが良くなります。

_mixin.jade

mixin loop
    include ./loop_start.php
mixin loop_end
    include ./loop_end.php
mixin reset
    include ./reset.php

single.jade / _mixin.jade使用時

include ./templates/php/_mixin
+loop
section
    h2: a(href!='<?php the_permalink(); ?>') <?php the_title(); ?>
    p <?php the_content(); ?>
+loop_end

例2:サブループ (WP_Query)で投稿一覧を表示する

同様の方法でサブループのクエリ設定も部品化してみると下記のようになります。カテゴリ表示もついでに。

set_wpquery.php

<?php
    $paged = get_query_var('paged') ? get_query_var('paged') : 1;
    $args = array(
        'post_type' => array($target_post), // 表示する投稿タイプ
        'paged' => $paged,
        'post_status' => 'publish',
        'posts_per_page' => $post_count, // 表示するページ数
        'order' => 'DESC' // 並び順
    );
    $my_query = new WP_Query($args);
?>

loop_start_sub.php

<?php if ($my_query->have_posts()) : while ( $my_query->have_posts() ) : $my_query->the_post(); ?>

get_cat.php

<?php
    $category = get_the_category();
    $cat_id = $category[0]->cat_ID;
    $cat_name = $category[0]->cat_name;
    $cat_slug = $category[0]->category_nicename;
    $cat_url = get_category_link( $cat_id );
?>

_mixin.jade

//- 改造: loop用mixinをまとめる
mixin loop(type = 'main')
    -if( type == 'main' )
        include ./loop_start.php
    -else if( type == 'sub' )
        include ./loop_start_sub.php
    -else if( type == 'end' )
        include ./loop_end.php
//- 追加
mixin set_wpquery
    include ./set_wpquery.php
mixin get_cat
    include ./get_cat.php

page-xxxx.jade / _mixin.jade使用時

include ./templates/php/_mixin
//- 取得する投稿タイプを指定 / 例は「投稿」
| <?php $target_post = 'post'; ?>
//- 取得する投稿数を指定
| <?php $post_count = 12; ?>
+set_wpquery
+loop('sub')
+get_cat
section
    h2: a(href!='<?php the_permalink(); ?>') <?php the_title(); ?>
    p <?php the_content(); ?>
    p: a(href!='<?php echo $cat_url; ?>') <?php echo $cat_name; ?>
+loop('end')
+reset

例3:同じカテゴリの投稿一覧を表示する(個別記事表示中)

所属カテゴリを1つとした場合の例です。ループ表示の記述が少し複雑になるので既存のmixinの使用ができない、もしくは部品化をおおまかにしたり細かくする必要が出てきます。例は「同じカテゴリの投稿がある場合にのみ一覧を表示、無い場合はasideまるごと表示しない」場合です。

set_wpquery_cat_same.php

<?php
    $args = array(
        'post_type' => array($target_post), // 投稿タイプ
        'post_status'    => 'publish’, // 公開状態
        'post__not_in' =>array( $post->ID ), // 現在のページを除外
        'category__in' => array($cat_id), // カテゴリIDが現在の$cat_idの全ての記事
        'posts_per_page' => $catlist_count, // 表示するページ数
        'order' => 'DESC' // 並び順
    );
    $my_query = new WP_Query($args);
?>

_mixin.jade

//- 追加
mixin set_wpquery_cat_same
    include ./set_wpquery_cat_same.php
//- さらに改造
mixin loop(type = 'main', part = 'all')
    -if( type == 'main' )
        -if( part == 'all' )
            include ./loop_start.php
    -else if( type == 'sub' )
        -if( part == 'all' )
            include ./loop_start_wpquery.php
        -else if( part == 'if' )
            | <?php if( $my_query->have_posts() ) : ?>
        -else if( part == 'endif' )
            | <?php endif; ?>
        -else if( part == 'while' )
            | <?php while ( $my_query->have_posts() ) : $my_query->the_post(); ?>
        -else if( part == 'endwhile' )
            | <?php endwhile; ?>
    -else if( type == 'end' )
        include ./loop_end.php

single.jade / _mixin.jade使用時

include ./templates/php/_mixin
article
    section
        +loop('main')
        +get_cat
        (メインループで必要な処理)
        +loop('end')
        +reset
//- 取得する投稿タイプを指定 / 例は「投稿」
| <?php $target_post = 'post'; ?>
//- 取得する投稿数を指定
| <?php $catlist_count = 12; ?>
+set_wpquery_cat_same
+loop('sub', 'if')
aside
    h3 同じのカテゴリの記事
    ul
        +loop('sub', 'while')
        li: a(href!='<?php the_permalink(); ?>') <?php the_title(); ?>
        +loop('sub', 'endwhile')
+loop('sub', 'endif')
+reset

ループ用mixinの現在の状況

当初、phpを読み込んでいたものを可能なものはmixin内に直接記述して可読性をあげることにしました。

さいごに

コードの部品化を始めたのはWebサイトのチーム制作がきっかけでした。コードの見通しを良くすることでWordpressに詳しくない人に、その仕組みをざっくり理解してもらったうえでコーディングを開始してもらい、途中で部品の中を見てもらえばいい、と考えたためです。コピペ・記述ミスも無くなるはずなので、ルール化さえしておけば比較的有効な手段なのかなぁと思いながら使ってます。