[PHP]Googleの構造化データ（パンくず）の対応を一括で簡単に

##はじめに
近年のWebサイトでは必須となったパンくずリストですが、Webエンジニアの皆さんならSEO対策の一貫として構造化マークアップを行うケースが少なくないと思います。しかし、HTMLを生成するコードとJSONを生成するコードが別々にあると、管理が二重になってしまって煩わしい…。そしてコードが長くなって読みにくい！

また、WordPressのテンプレートなどでは、microdataによって構造化マークアップを行っているものもありますが、GoogleはJSON-LD形式での構造化マークアップを推奨しています。

ということで、以下の2つのポイントを抑えつつ、Googleの構造化データに対応したパンくずリストの生成ができるようなメソッドを作っていきたいと思います。

- JSON-LD形式でマークアップする
- 一括でHTMLとJSONのマークアップができるようにする

## まずは結論から
以下のクラスを追記します。WordPressなら`functions.php`とかに書くのが良いでしょう。


```php:functions.php

class breadcrumb
{
    public function __construct()
    {
        $this->json = [
            '@context'          => 'https://schema.org',
            '@type'             => 'BreadcrumbList',
            'itemListElement'   => []
        ];

        $this->class = "breadcrumb";
        $this->items = [];
        $this->position = 1;
    }

    public function append(string $name, string $link)
    {
        array_push($this->json['itemListElement'], [
            '@type'     => 'ListItem',
            'position'  => $this->position,
            'name'      => $name,
            'item'      => $link
        ]);

        $this->items[] = ["name" => $name, "url" => $link];
        $this->position++;
    }

    public function generator()
    {
        $_ = function ($str) {
            return $str;
        };

        //HTMLの出力
        echo "
        <section class='{$this->class}'>
            <ul class='{$this->class}__list'>
                {$_(implode(array_map(function ($v) {return "<li class='{$this->class}__item'><a class='{$this->class}__link' href='{$v['url']}'>{$v['name']}</a></li>";}, $this->items)))}
            </ul>
        </section>";

        //JSONの出力
        echo "
        <script type='application/ld+json'>
            {$_(json_encode($this->json, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES))}
        </script>";
    }
}
```

次に、実際にパンくずを出力するファイルで、下記のようにしてパンくずを生成します。

```php
$pan = new breadcrumb();
$pan->append("HOME", "http://example.com/");
$pan->append("会社概要", "http://example.com/company/");
$pan->generator();
```
※引数のタイプヒンティングはPHPのバージョンによってうまく動作しない可能性がありますので、必要に応じて適宜削除してください。（確かPHP5系だと動かない？）
※構造化データの仕様上`append()`は絶対URLを指定してあげてください。

##使い方
まずはインスタンスを生成

```php
$pan = new breadcrumb(); //()はなくても大丈夫
```
次に、表示したいものを`append()`を使って追加していく。第一引数に表示名（テキストノード）、第二引数にurl（hrefの中）を指定してください。

```php
$pan->append("HOME", "https://example.com");
.
.
.
```

最後に、全て追加し終わったらジェネレートする

```php
$pan->generator();
```

これでパンくずが生成されます。class名はBEM形式にしていますので、必要に応じて変更してください。

##何をしているのか解説
簡単にいうと、インスタンスを生成して、必要な情報を`append()`関数によって追加していっているだけです。パンくずリストも構造化データもある程度フォーマットが決まったものなので、ループや`array_map()`によって処理しやすいです。

- JSON-LDは処理しやすい配列形式で作ってしまってjson_encodeによって出力
- HTMLは中身だけ作ってclass内変数を保持して`generator()`関数で整形して出力

##WordPressで使う場合
`append()`関数の引数は文字列さえ変えれば良いので、WordPressの関数と組み合わせて使うこともできます。例えば投稿ページだと下記のような感じ。

```php:single.php
$pan = new breadcrumb();
$pan->append("HOME", home_url());
$category = get_the_category();
foreach($category as $cat){
    $pan->append($cat->name, get_category_link($cat->term_id));
}
$pan->append(get_the_title(), get_permalink());
$pan->generator();
```

こうすることで、`HOME > 親カテゴリ名 > 子カテゴリ名 > 投稿名`といった形式で出力することが可能です。