2026年5月20日

2026年5月20日

WordPressのhreflang設定方法(多言語対応)

はじめに

hreflang属性はWordPressで多言語サイトを運営する際に、各ページの言語と対象地域をGoogleに伝えるための属性です。設定を誤ると意図しない言語のページが検索結果に表示されたり、重複コンテンツと認識されたりします。

症状・原因

  • 日本語ページが英語圏の検索結果に表示される(またはその逆)
  • 英語版・日本語版の記事が重複コンテンツとみなされている
  • hreflangを設定したがSearch Consoleで「alternateページ(正規ページのhreflangなし)」エラーが出る
  • PolylangやWPMLのhreflang出力が正しいか確認したい

解決手順

ステップ1:hreflangの基本ルールを理解する

【hreflangの書き方】

<!-- 言語のみ指定 -->
<link rel="alternate" hreflang="ja" href="https://example.com/ja/post/">
<link rel="alternate" hreflang="en" href="https://example.com/en/post/">

<!-- 言語 + 地域指定 -->
<link rel="alternate" hreflang="en-US" href="https://example.com/en-us/post/">
<link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/post/">
<link rel="alternate" hreflang="zh-TW" href="https://example.com/zh-tw/post/">

<!-- どの言語にも該当しないユーザー向けのデフォルトページ -->
<link rel="alternate" hreflang="x-default" href="https://example.com/">

【必須ルール】
1. 自己参照必須: 各ページに自分自身のhreflangも含める
2. 相互参照必須: AページがBを指したら、BページもAを指す
3. 絶対URL使用: 相対URLは不可
4. カノニカルと一致: hreflangのURLとカノニカルURLが一致すること
5. x-defaultは通常トップページまたは言語選択ページに設定

ステップ2:Polylangプラグインのhreflang設定

// Polylangが自動でhreflangを出力する
// 設定 → Polylang → 言語タブで言語を追加するだけで有効

// Polylangのhreflang出力をカスタマイズする場合
add_filter('pll_hreflang_attributes', function(array $hreflangs): array {
    // x-defaultを追加
    if (!isset($hreflangs['x-default'])) {
        $hreflangs['x-default'] = home_url('/');
    }
    return $hreflangs;
});

// Polylangで翻訳ページが存在しない場合の処理
add_filter('pll_the_language_link', function(?string $url, string $slug): ?string {
    if (!$url) {
        // 翻訳がない場合は言語トップページへのリンク
        return pll_home_url($slug);
    }
    return $url;
}, 10, 2);

ステップ3:WPMLのhreflang設定

// WPMLも自動でhreflangを出力する
// WPML → 言語 → 言語ネゴシエーションを設定

// WPMLのhreflang出力を確認
add_action('wp_head', function(): void {
    if (defined('ICL_LANGUAGE_CODE')) {
        // WPMLが有効な場合、hreflangは自動で出力される
        // wpml_hreflang_output フィルターでカスタマイズ可能
    }
}, 99);

// WPMLで x-default を設定
add_filter('wpml_hreflang_output', function(string $output): string {
    $default_url = apply_filters('wpml_permalink', home_url('/'), 'en');
    $x_default   = '<link rel="alternate" hreflang="x-default" href="'
                   . esc_url($default_url) . '">' . PHP_EOL;
    return $x_default . $output;
});

ステップ4:プラグインなしで手動hreflangを実装する

// functions.php: 手動でhreflangを実装(プラグインなし)
// ※ 記事に対応する翻訳記事IDをカスタムフィールドで管理する場合

add_action('wp_head', function(): void {
    if (!is_singular()) return;

    global $post;

    // カスタムフィールドから対応翻訳記事を取得
    // 例: _translation_ja, _translation_en にIDを保存
    $translations = [
        'ja' => get_post_meta($post->ID, '_translation_ja', true),
        'en' => get_post_meta($post->ID, '_translation_en', true),
        'zh' => get_post_meta($post->ID, '_translation_zh', true),
    ];

    // 現在のページの言語を取得
    $current_lang = get_post_meta($post->ID, '_post_language', true) ?: 'ja';

    // 自己参照を含む hreflang 一覧を構築
    $hreflangs = [];

    // 自己参照
    $hreflangs[$current_lang] = get_permalink($post->ID);

    // 翻訳ページへのリンク
    foreach ($translations as $lang => $trans_id) {
        if ($trans_id && $lang !== $current_lang) {
            $trans_url = get_permalink((int)$trans_id);
            if ($trans_url) {
                $hreflangs[$lang] = $trans_url;
            }
        }
    }

    // x-default(日本語をデフォルトに設定)
    $hreflangs['x-default'] = $hreflangs['ja'] ?? get_permalink($post->ID);

    // 出力
    foreach ($hreflangs as $lang => $url) {
        echo '<link rel="alternate" hreflang="' . esc_attr($lang)
             . '" href="' . esc_url($url) . '">' . PHP_EOL;
    }
}, 5);

ステップ5:hreflangの設定ミスを診断する

# hreflangの出力を確認
curl -s https://example.com/ja/post/ | grep -i hreflang

# 相互参照の確認(英語ページが日本語ページを指しているか)
curl -s https://example.com/en/post/ | grep -i hreflang

# Search Console でのエラー確認
# Search Console → インデックス → カバレッジ
# 「alternateページ(正規ページのhreflangなし)」エラー
# → 相互参照が欠けている可能性

# hreflang バリデーターツール(ブラウザで)
# https://www.aleydasolis.com/en/international-seo-tools/hreflang-tags-generator/
// functions.php: hreflangのデバッグ情報を管理画面に表示
add_action('admin_notices', function(): void {
    if (!current_user_can('manage_options')) return;
    $screen = get_current_screen();
    if (!$screen || $screen->base !== 'post') return;

    global $post;
    if (!$post) return;

    $current_lang = get_post_meta($post->ID, '_post_language', true);
    $trans_ja     = get_post_meta($post->ID, '_translation_ja', true);
    $trans_en     = get_post_meta($post->ID, '_translation_en', true);

    if ($current_lang) {
        echo '<div class="notice notice-info"><p>';
        echo "hreflang設定: 言語={$current_lang}";
        if ($trans_ja) echo " / JA翻訳ID={$trans_ja}";
        if ($trans_en) echo " / EN翻訳ID={$trans_en}";
        echo '</p></div>';
    }
});

注意事項

  • hreflangで指定するすべてのURLは正しく到達可能(200 OK)である必要があります。404や301リダイレクトのURLを指定すると無効になります
  • hreflangはrel="canonical"と矛盾してはいけません。あるページのカノニカルがA、hreflangがBを指すような設定は無効です
  • Googleはx-hreflangをHTTPヘッダーまたはXMLサイトマップでも受け付けます。wp_headに出力できない場合(AMP等)はサイトマップ経由での実装を検討してください

まとめ

hreflangは①自己参照必須、②相互参照必須、③絶対URL使用、④カノニカルURLと一致、⑤x-defaultの設定、の5つのルールを守ることが重要です。Polylangはhreflangを自動出力するため最も簡単に実装できます。プラグインなしで実装する場合はwp_headフィルターで各言語の記事IDをカスタムフィールドで管理して出力します。Search Consoleの「alternateページ(正規ページのhreflangなし)」エラーは相互参照の欠如が原因のことがほとんどです。

お気軽にご相談ください

お見積りへ お問い合わせへ