hreflangは、同じ内容の言語別ページを対応付けるために使います。
URLのパスが同じという理由だけで翻訳ページを推測せず、確認したURLの組を登録します。
旧版の毎アクセス時のHEAD確認と、ページごとに区別されないJSON-LDは撤去しました。
設置前に対応表を作る
日本語・英語それぞれの正規URL、公開状態、インデックス可能な状態、翻訳内容を確認します。
200を返すだけでは翻訳の存在やcanonical・noindexの状態は判断できません。
リダイレクト先や別内容のページは登録しません。
確認済みURLだけを出力する
子テーマfunctions.phpなどへ追加し、groupsの例示ドメインを実際の対応URLへ置き換えます。
既存PHP内では開始タグを追加しません。
日本語側と英語側の両方へ同じ組を登録してください。
多言語プラグインがすでに出力している場合は重複追加しません。
function waza_hreflang_group_html($current, $groups) {
$matches = array_values(array_filter($groups, function ($group) use ($current) {
return is_array($group) && in_array($current, $group, true);
}));
// 同じURLが複数の組にある場合は、曖昧な対応を出力しない。
if (count($matches) !== 1) return '';
foreach ($matches as $group) {
$html = '';
foreach ($group as $lang => $url) {
if (!preg_match('/^[a-z]{2,3}(?:-[A-Za-z]{2}|-[0-9]{3})?$/D', $lang)) return '';
if (!is_string($url) || wp_parse_url($url, PHP_URL_SCHEME) !== 'https' || !wp_parse_url($url, PHP_URL_HOST)) return '';
$html .= '<link rel="alternate" hreflang="' . esc_attr($lang) . '" href="' . esc_url($url) . '">' . "\n";
}
return $html;
}
return '';
}
function waza_output_mapped_hreflang() {
if (is_admin() || !is_singular() || is_preview() || is_feed() || is_404()) return;
$post_id = get_queried_object_id();
if (get_post_status($post_id) !== 'publish' || post_password_required($post_id)) return;
// インデックス可能な翻訳済みページだけを、両サイトに同じ組で登録する。
$groups = array(
array('ja' => 'https://example.com/about/', 'en' => 'https://en.example.com/company/'),
);
echo waza_hreflang_group_html(get_permalink($post_id), $groups);
}
add_action('wp_head', 'waza_output_mapped_hreflang', 5);
この例は投稿・固定ページなどの公開済み個別ページに限定し、一覧・検索・404・プレビュー・フィードを対象にしません。
対応表にないページでは何も出力しません。
投稿パスが言語ごとに異なっていても、URLを明示すれば対応付けられます。
対応表の重複と出力対象を切り分ける
| 状況 | この例の出力 |
|---|---|
| 公開済みの個別ページが1つの組に存在 | その組の自分自身と翻訳先 |
| 対応表にないURL | 出力しない |
| 同じURLが複数の組に存在 | 出力しない。重複した組を修正する |
| プレビュー・パスワード保護・検索結果 | 出力しない |
タグが出ない場合は、対応表内の各URLがHTTPS形式でホスト名を含むことと、各言語コードが掲載コードの正規表現に合うことも確認します。
一致した組に1件でもこの検査を通らない値があると、このコードはその組全体を出力しません。
現在のページとの照合はURL文字列の完全一致なので、末尾のスラッシュやクエリを含め、get_permalinkが返すURLと対応表をそろえます。
掲載コードの言語コード検査は、Googleが扱うすべての形式には対応していません。
たとえばGoogleが扱うzh-Hantはこの正規表現を通らず、逆にes-419は正規表現を通ってもGoogleでは未対応です。
形式を追加するときは、下記のGoogle公式資料で言語・地域・文字体系の指定を確認し、コードの検査条件と両言語の出力を検証してください。
旧処理は、同じURLを複数の組へ登録すると先頭の組だけを使用していました。
今回のコードは一致する組が1つであることを確認してから出力します。
タグが消えた場合は、対象URLが対応表にないか、複数の組に重複していないかを確認してください。
WordPressの実際のwp_headで、対応する2投稿には同じ2本のタグが出ること、未登録・プレビュー・パスワード保護・検索結果には出ないことを確認しました。
検証用URLはHTTPS形式へ置き換えており、実サイトへのHTTPS接続や翻訳内容を検証したものではありません。
noindex・canonical・相互リンクを確認
このコードはSEOプラグインごとのnoindex設定を自動判定しません。
noindexに変更したページは対応表から外します。
公開URLのHTMLソースで自分自身と翻訳先の両方があり、相手側にも戻りの指定があること、canonicalと矛盾しないことを確認します。
SEOプラグイン更新後も確認してください。
x-defaultは言語選択ページなどの目的に応じて設計するため、この例には含めません。
JSON-LDの翻訳関係を付けてもhreflangの代わりにはなりません。
地域コードや複数の対応グループを増やす場合は、1つのURLが複数組へ重複しないようにします。
戻し方と検証範囲
今回の関数とフック登録を取り除けば出力は止まります。
対応表の重複拒否とWordPressの出力条件は検証環境で確認しました。
実際の多言語サイトの相互タグ・canonical・noindexと、検索エンジンでの認識は未検証です。
対象サイトで両言語の公開HTMLを照合してください。
基準:Google公式の言語別ページの指定(2026年10月4日確認)。
Bogoを使う場合は標準のhreflangと重ねない
Bogo 3.9.3で関連付けた日本語・英語の公開投稿には、Bogo自身がwp_headから両言語のalternateタグを出します。
この対応表のコードも追加すると、同じ言語のタグを重複させるため、まず既存の出力を確認します。
今回の例をBogoと一緒に設置する手順ではありません。
2026年10月4日、隔離WordPressの別PHPリクエストで、関連付けた2投稿を指すjaとen-USのタグを確認しました。
URLのlangクエリも含めて照合します。
これはPHP出力の確認で、実HTTPS応答や検索エンジンでの認識を確認したものではありません。
Bogoの翻訳作成後の確認も参照し、翻訳先のcanonicalが元言語のURLを指していないか調べます。



