WEB制作、マーケティングに関する情報をお届けします。ホームページ制作会社、テラのブログ

WordPressでJSON-LD(パンくずリスト)を生成する方法

タグ:

構造化データはWebサイトのテキスト情報にタグ付けをすることでGoogle などの検索エンジンに認識されやすくする機能です。
構造化データのメリットは以下のようなものがあります。

  • 検索エンジンに認識されやすくなる
  • 検索結果がリッチリザルトに表示される場合がある

リッチリザルトはGoogleなどで検索された際に視覚的に表示されるカードのようなものです。
例えば以下のようなものです。

リッチリザルトのイメージ

リッチリザルトに表示されること自体にはSEO対策が優位に働くことはありませんが、このように視覚的に存在を知らせることができるため、クリック率が上がりユーザーをWebサイトへと呼び込みやすくなります。

マークアップできる構造化データの形式は大きく3つあります。

  • JSON-LD
  • microdata
  • RDFa

よく使われるものとしてはGoogleが推奨するJSON-LDでしょう。

構造化マップはさまざまなものをマークアップできます。例えばWebサイトの階層(パンくずリスト)、ブログコンテンツ、商品、口コミ、レシピ情報などです。
ここでは網羅できないほど膨大にあるため、Google検索セントラル | 機能ガイド|全ての構造化データ機能をご覧ください。
今回はどこのサイトにも共通するパンくずリストをWordPressで出力するためのコードを紹介します。

コードの紹介

header.phpのhead内に以下のコードを挿入してください。
アクションフックを使う場合は関数を作成してfunctions.phpに記載、『add_action(‘wp_head’, ‘関数名’);』で実行させてください。
各値は自動取得されるようになっていますがサイトの設定に合わせて変更する必要があります。

<?php
if ( is_home() || is_front_page() ) {
    // トップページの場合
    $breadcrumbs = [
        [
            '@type' => 'ListItem',
            'position' => 1,
            'item' => [
                '@id' => get_home_url(),
                'name' => get_bloginfo('name')
            ]
        ]
    ];
} else {
    // トップページのパンくず
    $breadcrumbs = [
        [
            '@type' => 'ListItem',
            'position' => 1,
            'item' => [
                '@id' => get_home_url(),
                'name' => get_bloginfo('name')
            ]
        ]
    ];

    $position = 2;

    if (is_page()) {
        // 固定ページの場合
        $ancestors = array_reverse(get_post_ancestors(get_the_ID()));
        foreach ($ancestors as $ancestor) {
            $breadcrumbs[] = [
                '@type' => 'ListItem',
                'position' => $position,
                'item' => [
                    '@id' => get_permalink($ancestor),
                    'name' => get_the_title($ancestor)
                ]
            ];
            $position++;
        }
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_permalink(),
                'name' => get_the_title()
            ]
        ];
    } elseif (is_category()) {
        // カテゴリページの場合
        $category = get_queried_object();
        if ($category->parent != 0) {
            $ancestors = array_reverse(get_ancestors($category->term_id, 'category'));
            foreach ($ancestors as $ancestor) {
                $parent = get_term($ancestor, 'category');
                $breadcrumbs[] = [
                    '@type' => 'ListItem',
                    'position' => $position,
                    'item' => [
                        '@id' => get_category_link($parent->term_id),
                        'name' => $parent->name
                    ]
                ];
                $position++;
            }
        }
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_category_link($category->term_id),
                'name' => $category->name
            ]
        ];
    } elseif (is_tag()) {
        // タグページの場合
        $tag = get_queried_object();
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_tag_link($tag->term_id),
                'name' => $tag->name
            ]
        ];
    } elseif (is_single()) {
        // 投稿ページの場合
        $category = get_the_category();
        if (!empty($category)) {
            $category = $category[0];
            if ($category->parent != 0) {
                $ancestors = array_reverse(get_ancestors($category->term_id, 'category'));
                foreach ($ancestors as $ancestor) {
                    $parent = get_term($ancestor, 'category');
                    $breadcrumbs[] = [
                        '@type' => 'ListItem',
                        'position' => $position,
                        'item' => [
                            '@id' => get_category_link($parent->term_id),
                            'name' => $parent->name
                        ]
                    ];
                    $position++;
                }
            }
            $breadcrumbs[] = [
                '@type' => 'ListItem',
                'position' => $position,
                'item' => [
                    '@id' => get_category_link($category->term_id),
                    'name' => $category->name
                ]
            ];
            $position++;
        }
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_permalink(),
                'name' => get_the_title()
            ]
        ];
    } elseif (is_post_type_archive()) {
        // カスタム投稿タイプアーカイブページの場合
        $post_type = get_post_type_object(get_post_type());
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_post_type_archive_link($post_type->name),
                'name' => $post_type->label
            ]
        ];
    } elseif (is_tax()) {
        // カスタムタクソノミーページの場合
        $term = get_queried_object();
        if ($term->parent != 0) {
            $ancestors = array_reverse(get_ancestors($term->term_id, $term->taxonomy));
            foreach ($ancestors as $ancestor) {
                $parent = get_term($ancestor, $term->taxonomy);
                $breadcrumbs[] = [
                    '@type' => 'ListItem',
                    'position' => $position,
                    'item' => [
                        '@id' => get_term_link($parent->term_id, $term->taxonomy),
                        'name' => $parent->name
                    ]
                ];
                $position++;
            }
        }
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_term_link($term->term_id, $term->taxonomy),
                'name' => $term->name
            ]
        ];
    }
}

$json_ld = [
    '@context' => 'http://schema.org',
    '@type' => 'BreadcrumbList',
    'itemListElement' => $breadcrumbs
];

echo '<script type="application/ld+json">' . json_encode($json_ld, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . '</script>';
//もしJSON-LDが出力されない場合はjson_encode()内に『 | JSON_INVALID_UTF8_SUBSTITUTE』を追加してください。
?>

コードを解説

トップページの場合の処理

『if ( is_home() || is_front_page() ) {}』でトップページと下層ページで処理を切り分けます。
トップページの場合は変数『$breadcrumbs』に専用の構造化マークアップを代入します。
『’@type’ => ‘ListItem’,』はパンくずリストを意味します。『postion』は階層、トップページなので1です。
『item』としてWebサイトのURLとサイト名を入力しますが、URLは『get_home_url()』、サイト名は『get_bloginfo(‘name’)』で取得しています。
それぞれWordPressに設定しているものがWeb上に掲載しているものと異なる場合は適宜修正してください。

if ( is_home() || is_front_page() ) {
    // トップページの場合
    $breadcrumbs = [
        [
            '@type' => 'ListItem',
            'position' => 1,
            'item' => [
                '@id' => get_home_url(),
                'name' => get_bloginfo('name')
            ]
        ]
    ];
}

トップページ以外の処理を書いていきます。

各値は自身のサイトに合わせて適宜修正してください。

トップページの情報を記載

まずは最上位であるトップページの情報を記載します。
説明はすでにしておりますので割愛します。

// トップページのパンくず
$breadcrumbs = [
    [
        '@type' => 'ListItem',
        'position' => 1,
        'item' => [
            '@id' => get_home_url(),
            'name' => get_bloginfo('name')
        ]
    ]
];
2階層以下を取得

構造化マップ内の『position』は階層の順番が必須になります。そのため、変数『$position』に『2』を代入しておきましょう。

$position = 2;
固定ページの場合の処理

固定ページについての処理を書いていきます。
『array_reverse(get_post_ancestors(get_the_ID()))』で固定ページの階層(親子)を全て取得します。
『foreach』で固定ページの情報を一つずつ取得していきますが階層が上から下へと降りていきますので変数『position』はループ毎にカウントアップさせています。

if (is_page()) {
    // 固定ページの場合
    $ancestors = array_reverse(get_post_ancestors(get_the_ID()));
    foreach ($ancestors as $ancestor) {
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_permalink($ancestor),
                'name' => get_the_title($ancestor)
            ]
        ];
        $position++;
    }
    $breadcrumbs[] = [
        '@type' => 'ListItem',
        'position' => $position,
        'item' => [
            '@id' => get_permalink(),
            'name' => get_the_title()
        ]
    ];
}
カテゴリページの場合の処理

固定ページについての処理を書いていきます。
『get_queried_object()』でカテゴリを取得します。
固定ページ同様に『foreach』で構造化マップを取得しています。

} elseif (is_category()) {
        // カテゴリページの場合
        $category = get_queried_object();
        if ($category->parent != 0) {
            $ancestors = array_reverse(get_ancestors($category->term_id, 'category'));
            foreach ($ancestors as $ancestor) {
                $parent = get_term($ancestor, 'category');
                $breadcrumbs[] = [
                    '@type' => 'ListItem',
                    'position' => $position,
                    'item' => [
                        '@id' => get_category_link($parent->term_id),
                        'name' => $parent->name
                    ]
                ];
                $position++;
            }
        }
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_category_link($category->term_id),
                'name' => $category->name
            ]
        ];
    }
タグページの場合の処理

固定ページについての処理を書いていきます。
『get_queried_object()』でタグを取得します。
固定ページ同様に『foreach』で構造化マップを取得しています。

} elseif (is_tag()) {
        // タグページの場合
        $tag = get_queried_object();
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_tag_link($tag->term_id),
                'name' => $tag->name
            ]
        ];
    }
投稿ページの場合の処理

投稿ページの場合は『$category = get_the_category(); if (!empty($category)) {}』カテゴリを持っているかどうかを確認します。
カテゴリを持っている場合はカテゴリの下に投稿ページの階層が来るように設定します。
カテゴリの出力は上述した通りですので割愛します。
カテゴリの出力が終わったタイミングで『get_permalink()』、『get_the_title()』でURLとタイトルを取得して投稿ページの構造化マップを出力します。

elseif (is_single()) {
        // 投稿ページの場合
        $category = get_the_category();
        if (!empty($category)) {
            $category = $category[0];
            if ($category->parent != 0) {
                $ancestors = array_reverse(get_ancestors($category->term_id, 'category'));
                foreach ($ancestors as $ancestor) {
                    $parent = get_term($ancestor, 'category');
                    $breadcrumbs[] = [
                        '@type' => 'ListItem',
                        'position' => $position,
                        'item' => [
                            '@id' => get_category_link($parent->term_id),
                            'name' => $parent->name
                        ]
                    ];
                    $position++;
                }
            }
            $breadcrumbs[] = [
                '@type' => 'ListItem',
                'position' => $position,
                'item' => [
                    '@id' => get_category_link($category->term_id),
                    'name' => $category->name
                ]
            ];
            $position++;
        }
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_permalink(),
                'name' => get_the_title()
            ]
        ];
    }
カスタム投稿ページの場合の処理

こちらは階層にはしていませんが、必要であればカテゴリ情報を取得して階層化してください。
URLは『get_post_type_archive_link($post_type->name),』で取得、タイトルは『$post_type->label』で取得しています。

elseif (is_post_type_archive()) {
        // カスタム投稿タイプアーカイブページの場合
        $post_type = get_post_type_object(get_post_type());
        $breadcrumbs[] = [
            '@type' => 'ListItem',
            'position' => $position,
            'item' => [
                '@id' => get_post_type_archive_link($post_type->name),
                'name' => $post_type->label
            ]
        ];
    }
カスタムタクソノミーの場合

カテゴリの場合と処理はほとんど同じです。

elseif (is_tax()) {
       // カスタムタクソノミーページの場合
       $term = get_queried_object();
       if ($term->parent != 0) {
           $ancestors = array_reverse(get_ancestors($term->term_id, $term->taxonomy));
           foreach ($ancestors as $ancestor) {
               $parent = get_term($ancestor, $term->taxonomy);
               $breadcrumbs[] = [
                   '@type' => 'ListItem',
                   'position' => $position,
                   'item' => [
                       '@id' => get_term_link($parent->term_id, $term->taxonomy),
                       'name' => $parent->name
                   ]
               ];
               $position++;
           }
       }
       $breadcrumbs[] = [
           '@type' => 'ListItem',
           'position' => $position,
           'item' => [
               '@id' => get_term_link($term->term_id, $term->taxonomy),
               'name' => $term->name
           ]
       ];
   }

最後に出力

JSON-LDのパンくずリストのテンプレートになる部分を挿入して、上の処理で取得した値を『json_encode』でJSON形式にした文字列を返します。
この際、テキストを正しく表示させるために『json_encode($json_lg, 処理名 | 処理名 )』でオプション処理を行います。
『|』で複数のオプションを設定できます。それぞれのオプションの役割を説明します。

JSON_PRETTY_PRINT 文字列をスペースでインデントしてくれます。
これは入れなくても問題ありませんがインデントがないため、読みづらいため入れておいた方がいいでしょう。
JSON_UNESCAPED_UNICODE 日本語の文字化けを防いでくれます。
JSON_UNESCAPED_SLASHES 『/』をエスケープしないように指定できます。
これは入れなくても問題ありませんが、読みづらいため入れておいた方がいいでしょう。
$json_ld = [
    '@context' => 'http://schema.org',
    '@type' => 'BreadcrumbList',
    'itemListElement' => $breadcrumbs
];
echo '<script type="application/ld+json">' . json_encode($json_ld, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . '</script>';

上記でJSON-LDが表示されない場合は文字コードが問題になっているかもしれません。
json_encode()内に『 | JSON_INVALID_UTF8_SUBSTITUTE』を追加してみてください。

まとめ

以上、『WordPressでJSON-LD(パンくずリスト)を生成する方法』でした。
上記のページ情報などの値はWebサイトごとに異なりますので自身のWebサイトに合わせて表示を変更してください。

テラ合同会社(東京都)

テラは2014年に東京都でスタートアップしたホームページ制作会社です。ホームページ制作以外にも広告運用、マーケティング、ブランディング、印刷物など幅広い領域をサポートしています。
コーポレートサイトはこちらをご覧ください。