2026年8月18日

2026年8月18日

WordPressにスキーママークアップを実装してSEOを強化する方法

はじめに

スキーママークアップ(構造化データ)を実装することで、Google検索結果にリッチスニペット(評価星・FAQ・パンくずリストなど)が表示され、クリック率(CTR)の向上が期待できます。JSON-LDフォーマットでの実装がGoogleの推奨方式です。

症状・原因

スキーママークアップが必要なケース:

  • 検索結果でリッチリザルトを表示させたい
  • FAQ・How-to等の特殊なリッチスニペットを取得したい
  • 商品ページの価格・在庫・評価を構造化データで伝えたい
  • ローカルビジネス情報をGoogleマップと連携させたい

解決手順

ステップ1:基本的なArticleスキーマを実装する

// functions.php

add_action('wp_head', 'output_article_schema');
function output_article_schema(): void {
    if (!is_single()) return;
    
    $post = get_post();
    if (!$post) return;
    
    $author      = get_the_author_meta('display_name', $post->post_author);
    $published   = get_the_date('c', $post);
    $modified    = get_the_modified_date('c', $post);
    $description = get_the_excerpt($post) ?: wp_trim_words(strip_tags($post->post_content), 30);
    $image       = get_the_post_thumbnail_url($post, 'large');
    
    $schema = [
        '@context'         => 'https://schema.org',
        '@type'            => 'Article',
        'headline'         => get_the_title($post),
        'description'      => $description,
        'datePublished'    => $published,
        'dateModified'     => $modified,
        'author'           => [
            '@type' => 'Person',
            'name'  => $author,
            'url'   => get_author_posts_url($post->post_author),
        ],
        'publisher' => [
            '@type' => 'Organization',
            'name'  => get_bloginfo('name'),
            'logo'  => [
                '@type' => 'ImageObject',
                'url'   => get_site_icon_url(512) ?: '',
            ],
        ],
        'mainEntityOfPage' => [
            '@type' => 'WebPage',
            '@id'   => get_permalink($post),
        ],
    ];
    
    if ($image) {
        $schema['image'] = ['@type' => 'ImageObject', 'url' => $image];
    }
    
    // JSON-LDとして出力(HTMLエスケープなし)
    printf(
        '<script type="application/ld+json">%s</script>' . PHP_EOL,
        wp_json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
    );
}

ステップ2:FAQPageスキーマを実装する

// FAQページのスキーマ(Gutenbergのよくある質問ブロックと連動)
add_action('wp_head', 'output_faq_schema');
function output_faq_schema(): void {
    if (!is_singular()) return;
    
    $post = get_post();
    
    // カスタムフィールドからFAQデータを取得
    $faqs = get_post_meta($post->ID, '_faq_items', true);
    
    if (empty($faqs) || !is_array($faqs)) {
        // 本文からdetails/summaryタグを自動抽出
        preg_match_all(
            '/<summary[^>]*>(.*?)<\/summary>\s*<(?:div|p)[^>]*>(.*?)<\/(?:div|p)>/is',
            $post->post_content,
            $matches
        );
        if (empty($matches[1])) return;
        
        foreach ($matches[1] as $i => $question) {
            $faqs[] = [
                'question' => strip_tags($question),
                'answer'   => strip_tags($matches[2][$i] ?? ''),
            ];
        }
    }
    
    if (empty($faqs)) return;
    
    $schema = [
        '@context'   => 'https://schema.org',
        '@type'      => 'FAQPage',
        'mainEntity' => array_map(function($faq) {
            return [
                '@type'          => 'Question',
                'name'           => $faq['question'],
                'acceptedAnswer' => [
                    '@type' => 'Answer',
                    'text'  => $faq['answer'],
                ],
            ];
        }, $faqs),
    ];
    
    printf(
        '<script type="application/ld+json">%s</script>' . PHP_EOL,
        wp_json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
    );
}

ステップ3:BreadcrumbListスキーマを実装する

// パンくずリストのスキーマ
add_action('wp_head', 'output_breadcrumb_schema');
function output_breadcrumb_schema(): void {
    $items = [];
    $pos   = 1;
    
    // ホーム
    $items[] = [
        '@type'    => 'ListItem',
        'position' => $pos++,
        'name'     => 'ホーム',
        'item'     => home_url('/'),
    ];
    
    if (is_singular('post')) {
        $cat = get_the_category();
        if ($cat) {
            $items[] = [
                '@type'    => 'ListItem',
                'position' => $pos++,
                'name'     => $cat[0]->name,
                'item'     => get_category_link($cat[0]->term_id),
            ];
        }
        $items[] = [
            '@type'    => 'ListItem',
            'position' => $pos++,
            'name'     => get_the_title(),
            'item'     => get_permalink(),
        ];
    } elseif (is_category()) {
        $items[] = [
            '@type'    => 'ListItem',
            'position' => $pos++,
            'name'     => single_cat_title('', false),
            'item'     => get_category_link(get_queried_object_id()),
        ];
    }
    
    if (count($items) <= 1) return; // ホームのみなら出力しない
    
    $schema = [
        '@context'        => 'https://schema.org',
        '@type'           => 'BreadcrumbList',
        'itemListElement' => $items,
    ];
    
    printf(
        '<script type="application/ld+json">%s</script>' . PHP_EOL,
        wp_json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
    );
}

ステップ4:Productスキーマを実装する

// 商品ページのスキーマ
add_action('wp_head', 'output_product_schema');
function output_product_schema(): void {
    if (!is_singular('product')) return;
    
    $post  = get_post();
    $price = get_post_meta($post->ID, '_product_price', true);
    $stock = get_post_meta($post->ID, '_product_stock', true);
    $sku   = get_post_meta($post->ID, '_product_sku', true);
    
    $schema = [
        '@context'    => 'https://schema.org',
        '@type'       => 'Product',
        'name'        => get_the_title($post),
        'description' => get_the_excerpt($post),
        'image'       => get_the_post_thumbnail_url($post, 'large') ?: '',
        'sku'         => $sku ?: '',
        'brand'       => [
            '@type' => 'Brand',
            'name'  => get_bloginfo('name'),
        ],
    ];
    
    if ($price) {
        $schema['offers'] = [
            '@type'         => 'Offer',
            'price'         => (float)$price,
            'priceCurrency' => 'JPY',
            'availability'  => ($stock > 0)
                ? 'https://schema.org/InStock'
                : 'https://schema.org/OutOfStock',
            'url'           => get_permalink($post),
        ];
    }
    
    printf(
        '<script type="application/ld+json">%s</script>' . PHP_EOL,
        wp_json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
    );
}

ステップ5:Google Rich Results Testで確認する

# WP-CLIで特定ページのスキーマを確認
wp eval "
add_action('wp_head', function() {}, 99999);
\$post = get_post(123);
setup_postdata(\$post);
do_action('wp_head');
"

# curlでJSON-LDを抽出して確認
curl -s https://example.com/post/123 | \
  grep -A 50 'application/ld+json' | \
  head -60

# Google Rich Results Test APIを使う
curl -s "https://searchconsole.googleapis.com/v1/urlTestingTools/mobileFriendlyTest:run" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/post/123"}'

注意事項

  • スキーマのデータは実際に表示されているコンテンツと一致させてください(ガイドライン違反になります)
  • JSON_UNESCAPED_UNICODEを使わないと日本語が 形式になります
  • 複数のスキーマが必要な場合は配列形式で1つの