WordPress:JSON-LD構造化データをプラグインなしで出力

WordPress:JSON-LD構造化データをプラグインなしで出力

テーマをゼロから作ってみる(11)です。現在は SEO 対策中で、今回は JSON-LD 構造化データをプラグインを使わずに出力します。「SEO 対策に必要なこと」リストの3番目です。4番はすでに終わっています。なお、この記事現在は、まだ Genesis Framework を使っている状態です。

01作成テーマのサイト構成

ブログサイトのテーマを前提にしています。このサイトもほぼ同じですが、目的としているサイトは次の映画のレビューサイトです。

現時点のサイト構成は、

  • ホームページ(個別ページ, front_page.php)
  • 投稿ページ(single.php)
  • ブログページ(個別ページ, index.php)
  • カテゴリーページ(index.php)

で、他に、おすすめ映画、よく読まれている記事、検索、お問い合わせの各ページを予定しています。

02JSON-LD 構造化データ出力コード

ホームページと投稿ページに JSON-LD でマークアップした構造化データを出力します。デモページがあります。

  • ゼロから作るWordPressテーマ(現在停止中)

ホームページ(front_page.php)

次の構造化データを出力します。@type はとりあえず WebSite にしていますが、Google 検索が対応していませんので、後々、映画カルーセル(Movie)にしてみようかと考えています。

<script type="application/ld+json">
{
    "@context": "http:\/\/schema.org",
    "@type": "WebSite",
    "name": "ゼロから作るWordPressテーマ",
    "url": "https:\/\/june.imuza.com\/",
    "inLanguage": "jp",
    "description": "映画のネタバレ レビューサイト、見てから読むレビューです",
    "author": {
        "@type": "Person",
        "name": "ausnichts",
        "sameAs": [
            "https:\/\/www.facebook.com\/imuzacom",
            "https:\/\/twitter.com\/ausnichts"
        ]
    },
    "image": "http:\/\/june.imuza.com\/wp-content\/uploads\/mi515.png"
}
</script>

投稿ページ(single.php)

出力するデータのタイプは、Article と BreadcrumbList(複数可)です。各値はデモ用のものです。

<script type="application/ld+json">
{
    "@context": "https:\/\/schema.org",
    "@type": "BlogPosting",
    "headline": "長文テキスト",
    "image": "https:\/\/june.imuza.com\/wp-content\/uploads\/2022\/12\/sobakasu.jpg",
    "datePublished": "2022-12-28T10:16:19+09:00",
    "dateModified": "2023-01-18T20:33:45+09:00",
    "description": "見出し1 親譲りの無鉄砲で小供の時から損ばかりしている。小学校に居る時分学校の二階から飛び降りて一週間ほど腰を抜かした事がある。なぜそんな無闇をしたと聞く人があるかも知れぬ。別段深い理由でもない。新築の二階から首を出して [&hellip;]",
    "author": {
        "@type": "Person",
        "name": "ausnichts",
        "sameAs": [
            "https:\/\/www.facebook.com\/imuzacom",
            "https:\/\/twitter.com\/ausnichts"
        ]
    }
}
</script>
<script type="application/ld+json">
[
    {
        "@context": "https:\/\/schema.org",
        "@type": "BreadcrumbList",
        "itemListElement": [
            {
                "@type": "ListItem",
                "position": 1,
                "name": "Home",
                "item": "https:\/\/june.imuza.com\/"
            },
            {
                "@type": "ListItem",
                "position": 2,
                "name": "あさひ",
                "item": "https:\/\/june.imuza.com\/category\/%e3%81%82%e3%81%95%e3%81%b2\/"
            },
            {
                "@type": "ListItem",
                "position": 3,
                "name": "長文テキスト",
                "item": "https:\/\/june.imuza.com\/long\/"
            }
        ]
    },
    {
        "@context": "https:\/\/schema.org",
        "@type": "BreadcrumbList",
        "itemListElement": [
            {
                "@type": "ListItem",
                "position": 1,
                "name": "Home",
                "item": "https:\/\/june.imuza.com\/"
            },
            {
                "@type": "ListItem",
                "position": 2,
                "name": "カテゴリー 1",
                "item": "https:\/\/june.imuza.com\/category\/%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc-1\/"
            },
            {
                "@type": "ListItem",
                "position": 3,
                "name": "カテゴリー 2",
                "item": "https:\/\/june.imuza.com\/category\/%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc-1\/%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc-2\/"
            },
            {
                "@type": "ListItem",
                "position": 4,
                "name": "長文テキスト",
                "item": "https:\/\/june.imuza.com\/long\/"
            }
        ]
    }
]
</script>

出力コード

function get_imz_jsonld_data(){
    // author, logoイメージ 設定
    $author = array(
        '@type'  => 'Person',
        'name'   => 'ausnichts',
        'sameAs' => array(
            'https://www.facebook.com/imuzacom',
            'https://twitter.com/ausnichts'
        )
    );
    $logo = wp_upload_dir()['baseurl'] . '/mi515.png';

    // description をカスタムフィールまたは本文から取得
    $post_ID = get_the_ID();
    $description = get_post_meta($post_ID, '_imz_description', true);
    if(!$description && is_single()){
        $excerpt = get_the_excerpt();
        $description = mb_strstr($excerpt, '{', true); // 特殊、通常は文字数
        if(!$description) $description = $excerpt;
    }
    // json-ld データを入れる配列
    $jsonld       = array();

    // トップページ
    if ( is_front_page() ) {
        // WebSite
        $jsonld['home'] = array(
            '@context'   => 'http://schema.org',
            '@type'      => 'WebSite',
            'name'       => get_bloginfo( 'name' ),
            'url'        => home_url( '/' ),
            'inLanguage' => 'jp',
            'description'=> $description,
            'author'     => $author,
            'image'      => $logo
        );
    }

	// 記事ページ
    if ( is_single() ) {
        // カテゴリー階層を取得して配列に入れる
        $get_category_tree = function($id) use (&$get_category_tree, &$category_tree){
            if($id != 0){
                $category = get_category($id);
                $name = $category->cat_name;
                $url = get_category_link($id);
                $category_tree[] = [$id, $name, $url];
                $parent_id = $category->category_parent;
                $get_category_tree($parent_id);
            }
            return array_reverse($category_tree);
        };
        // サムネイル画像を取得
        if ( has_post_thumbnail() ) {
            $image = get_the_post_thumbnail_url($post_ID, 'full');
        }else{
            $image = wp_upload_dir()['baseurl'] . '/dummy.jpg';
        }
        // BlogPosting
        $jsonld['blog_posting'] = array(
            '@context'         => 'https://schema.org',
            '@type'            => 'BlogPosting',
            'headline'         => get_the_title(),
            'image'            => $image,
            'datePublished'    => get_the_time( 'c' ),
            'dateModified'     => get_the_modified_time( 'c' ),
            'description'      => $description,
            'author'           => $author
        );
        // BreadcrumbList
        $categories = get_the_category($post_ID);
        foreach($categories as $category){
            $category_tree = array();
            $id = $category->cat_ID;
            $category_tree = $get_category_tree($id);

            $array = array();
            $array[] =  array(
                '@type'    => 'ListItem',
                'position' => 1,
                'name'     => 'Home',
                'item'     => home_url( '/' ),
            );
            $index = 2;
            foreach($category_tree as $category){
                $array[] =  array(
                    '@type'    => 'ListItem',
                    'position' => $index,
                    'name'     => $category[1],
                    'item'     => $category[2],
                );
                $index++;
            }
            $array[] = array(
                '@type'    => 'ListItem',
                'position' => $index,
                'name'     => get_the_title(),
                'item'     => get_the_permalink(),
            );https://imuza.com/?s=%E3%83%86%E3%83%BC%E3%83%9E%E3%82%92%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B

            $jsonld['breadcrumb'][] = [
                '@context'        => 'https://schema.org',
                '@type'           => 'BreadcrumbList',
                'itemListElement' => $array,
            ];
        }
    }
    // head タグ内に出力
    foreach ( $jsonld as $data ) {
        echo '<script type="application/ld+json">' . PHP_EOL;
        echo json_encode( $data, JSON_UNESCAPED_UNICODE  | JSON_PRETTY_PRINT ) . PHP_EOL;
        echo '</script>' . PHP_EOL;
    }
}
add_action( 'wp_head', 'get_imz_jsonld_data' );

パンくずリストは表示用にもほぼ同じことをやっていますので一部を関数にするなり何か方法を考えなくてはいけません。パンくずリストの表示用は次の記事です。

03構造化データテスト、リッチリザルト

構造化データをテストするには、「リッチリザルトテスト」と「スキーマ マークアップ検証ツール」の2つがあります。次のサイトにそれぞれへのリンクがあります。

「リッチリザルト」とは「Google 検索がサポートする構造化データ マークアップ」のことで、Google 検索で表示される情報が増えてクリックされやすくなるものです。

Google は、構造化データを使用してページのコンテンツを認識し、そのコンテンツを「リッチリザルト」と呼ばれる情報が豊富な検索結果に表示します。サイトが検索でリッチリザルトの一つとして表示されるようにするには、サイトに構造化データを実装する方法を説明しているガイドを実践してください。

Google 検索がサポートする構造化データ マークアップ

作成中のテーマの場合ですと、Article(BlogPosting)、パンくずリスト、映画カルーセル(Movie)あたりを熟読する必要がありそうです。