4月はなんとブログの記事を一つも書いていなかった。

サボってばかりいないで、WordPressのTipsでも書くか……

ということで、ネタ帳から最終更新日が去年の12月になってるこのネタを引っ張り出してきた。

……なんか以前にも同じようなこと書いたような。

ともかく、今回はWordPressページの <body> タグにクラスを追加する関数 body_class() を使い、ページ(記事)単位で自由にクラスを追加したり除去したりする方法を考えてみた。

body_class() とは

<body> タグに class="……" を追加するWordPressの関数だ。

解説ページも参照してくれ。

テーマファイルの中では(おそらく header.php において)以下のように使われている。

<body <?php body_class(); ?>>

これで、たとえばWordPressのインストール時に生成される「About」ページでは以下のような出力になる。

<body class="page page-id-2 page-template page-template-default">

赤字部分が body_class() で追加された部分

上の例は「固定ページ」のものだが、記事ページでいうと、この記事のひとつ前の記事ではこんな感じ。

<body class="single single-post postid-612 single-format-standard">

このように、現在どのようなページを表示しているかをクラスで判別できるようになり、CSSによるデザインに役立つ。

どのページにどんなクラスが追加されるかは、上記リンクのCodex日本語版にまとめられている。

この関数に引数を渡すことで、さらにクラスを追加することができる。

なお、追加されるクラスの一覧は関数 get_body_class() で配列として取得できる。

クラスを追加

上記の通り、 body_class() に引数を渡すとクラスをいくつでも追加できる。

受け付ける引数は一つだけだが、複数のクラスを追加するには空白区切りの文字列か、配列を渡す。

<?php
/* 空白区切りの文字列 */
body_class('class1 class2 class3');
/* 配列 */
body_class(array('class1', 'class2', 'class3'));
?>

class1, class2, class3 という三つのクラスを追加する例。

なお、内部処理ではクラスの一覧を配列で管理し、最終的に関数 join() を使って文字列に展開している。

このブログでは、様々な条件に応じてクラスを加除するために、まず get_body_class() でクラスの一覧を取得して、配列を自力で管理している。

さらに、カスタムフィールドによってページ(記事)毎に任意のクラスを追加することもできる。

例えば、「body-class」というカスタムフィールドを設定し、その値をそのままクラスとして追加するには以下のようにする。

<?php
/* カスタムフィールドを(多次元)配列で取得 */
$custom_fields = get_post_meta(get_the_ID(), '', false);
/* カスタムフィールドのキー「body-class」の配列をクラスに追加 */
if (isset($custom_fields['body-class']))
    $body_class = get_body_class($custom_fields['body-class']);
else
    $body_class = get_body_class();
?>
<!-- 配列を文字列に直して出力 -->
<body class="<?php echo join(' ', $body_class); ?>">

ところで、配列に別の配列の要素を追加したり、文字列要素を一つ追加するには次のように書くと簡単だ。

<?php
/* 配列を追加 */
$body_class += array('class4');
/* 文字列を追加 */
$body_class[] = 'class5';
?>

クラスを除去

ここからがこの記事の本題だ。

body_class() (または get_body_class() )によって標準で追加されるクラスから、特定のクラスを除去する方法を探していた。

ここでは、ページ(記事)に「body-class-x」というカスタムフィールドを設定し、その値に該当するクラスを除去する方法を説明する。

すなわち、 get_body_class() で取得した配列から、指定した文字列と一致する要素を除去すればよい。

$custom_fields$body_class は上の例と同じものである。

<?php
if (isset($custom_fields['body-class-x'])) {
    $body_class_x = $custom_fields['body-class-x'];
    foreach ($body_class_x as $value) {
        $key = array_search($value, $body_class);
        if ($key !== false)
            unset($body_class[$key]);
    }
}
$body_class = array_values(array_unique($body_class));
?>

4行目から8行目までのループで、カスタムフィールドのキー「body-class-x」の値を一つずつ $body_class の要素から探し、除去している。

10行目では $body_class の要素に重複があった場合に除去し、さらに除去によって抜けたインデックスを振り直している。

post_class() でも!

ここまでは <body> におけるページごとのクラスとカスタマイズを説明してきたが、メインループ内で使用される、記事ごとに各種のクラスを追加する関数 post_class() でも同様のカスタマイズが可能だ。

この関数は基本的にテーマファイルの index.php や single.php 、 page.php にて使われている。

この関数によって追加されるクラスには、記事ごとの属性が含まれているので、カスタマイズすることでCSSによるデザインをより高度に制御できるだろう。

こちらも、クラスの配列を get_post_class() で取得できる。

何に使うの?

で、今回のTipsはちょっと需要がなさそうな感じもしている。

デフォでもいろいろクラスを追加してくれるから、さらにクラスを追加する必要性もあんまりなさそう、という意味だ。

俺が使っているのは――

post_class() って、ブログのトップやカテゴリなどのアーカイブ系ページと、単一の記事ページで、どちらも同じようなクラスを吐くんだよね。

つまり post_class() だけで両者を見分けるのは難しい。

本文の抜粋しか表示しないアーカイブ系ページと、単一の記事ページでスタイルを少し変えようと思って、 body_class() のほうを見れば区別はできるんだけど、CSSのセレクターを増やすと「詳細度」が上がってルールの記述に影響が出てしまう。

そこで、単一の記事ページの post_class() に「post-single」というようなクラスを追加することによって、セレクターを増やさずに容易に区別できるようになる――

という、マイナー極まりない用途に使える(えっへん)

まとめ

今回は body_class() によって追加されるクラスを自在に制御する方法を紹介した。

というか、ネタは書こうと思った時にすぐ書かないと、この方法を考えたときのことを半分くらい忘れてしまってるよねっていう。

俺の悪い癖だ。

もっと気の利いた解説ができたかもしれないのに……

サボりがちなのをこれから徐々に修正していきたい。