Command Palette

Search for a command to run...

WordPress で Hreflang を追加する方法 (プラグインなし)

WordPress で Hreflang を追加する方法 (プラグインなし)

T
Toolz Team
|Aug 23, 2026|13 分読んでください

SEO ツール コレクションの一部

ほとんどのWordPressのhreflangアドバイスは、 " 多言語プラグインをインストールし、それはそれを処理します " プラグインがあなたの翻訳を所有しているとき、それは問題ありません それは私が最も頻繁にヒットした場合の間違った答えです: 2 つまたは3 つの言語バージョンを持つサイトは、別々のサブディレクトリとして構築され、別々のインストール、または手動で翻訳されたページのセット、誰も完全な翻訳フレームワークと4 ページのためのそのデータベーススキーマを望んでいません。

私は、翻訳が手書きでライブされているドキュメントサイトを含め、その形でWordPressプロパティを維持しています /de/ あんど /es/。 hreflang there はテーマ ファイルに 40 行あり、1 つの配列から読み取られ、一度もドリフトしていません。このガイドは、そのコードと、プラグインがテーマと一緒に hreflang を送信しているときに問題が発生する部分です。

の下にあります 完全なフレフラングガイド、 の 隣 Next.jsバージョン

tl;dr: WordPressは、それ自体でフレフランを発しません。 hook wp_headを指定し、ロケールマップ上でループし、 を含む完全な逆数集合を印刷する x-default グループ内のすべてのページで。 でURLを構築する home_url() またはハードコーディングではなくロケールごとのオリジンで、各ページ& #39; s の正規の自己参照を保持し、競合ブロックを既に発している SEO プラグインがないことを確認してください。 multi-site セットアップの場合、 get_sites() 地図を提供します。翻訳されたページを含む単一のサイトの場合は、ポストメタフィールドマッピングの対応物で十分です。

WordPress は単独で hreflang を追加しますか?

No. Core は、から正規リンク、ショートリンク、およびさまざまなフィード リンクと REST リンクを出力します wp_head、しかし、言語については何も交互に. get_locale() サイトがどの言語にあるのかを知っており、それを注釈に変えるコアの部分はありません。

プラグインがギャップを埋める Polylang と WPML は、管理する翻訳に対してフレフランを発し、ほとんどの SEO プラグインは、表示できる翻訳関係を設定するとフレフランを発します。すでにそれらのいずれかを使用しており、サイト全体をカバーしている場合は、それを使用してこの記事をスキップしてください。ハンドロールする理由は、翻訳がプラグインが知っている範囲の外に存在し、部分セットを発するプラグインは、何も発しないプラグインよりも悪いためです。

最小バージョン: 1 つの配列、1 つのフック

翻訳が既知の小さなURLプレフィックスのセットであるサイトの場合:

<?php
/**
 * Hreflang annotations for a hand-translated multilingual site.
 * Drop in the theme's functions.php or a small mu-plugin.
 */
function mysite_hreflang_map(): array {
    return [
        'en-US'     => 'https://example.com',
        'de-DE'     => 'https://example.com/de',
        'es-ES'     => 'https://example.com/es',
        'x-default' => 'https://example.com',
    ];
}

function mysite_print_hreflang(): void {
    $path = mysite_current_path(); // e.g. '/pricing/'
    foreach ( mysite_hreflang_map() as $hreflang => $origin ) {
        printf(
            '<link rel="alternate" hreflang="%s" href="%s" />' . "\n",
            esc_attr( $hreflang ),
            esc_url( untrailingslashit( $origin ) . $path )
        );
    }
}
add_action( 'wp_head', 'mysite_print_hreflang', 1 );

手書きのブロックでは通常正しくない 3 つのことが当てはまります。

すべてのページにフルセットを印刷します、page& #39; s自身の言語を含む。 reciprocityは構造的に満たされる:全く分岐がないので、エントリを省略できた分岐はない。

x-default は同じ配列の行です、従って同じループによって放出され、1 つのテンプレート上で忘れることはできません。

URL がエスケープされます. esc_url href で wp_head はオプションではなく、フレフラング値が通過します esc_attr 同じ理由で.

現在のパスを作成しています

道はケアが必要な部分です。道でなければならないからです 以内 完全なリクエスト URI ではなく、言語です。

function mysite_current_path(): string {
    $home = wp_parse_url( home_url(), PHP_URL_PATH ) ?: '';
    $req  = wp_parse_url( $_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH ) ?: '/';

    // Strip the language prefix this install is served under.
    if ( $home && str_starts_with( $req, $home ) ) {
        $req = substr( $req, strlen( $home ) );
    }
    return user_trailingslashit( '/' . ltrim( $req, '/' ) );
}

ドイツ語インストールが次の場所にある場合 example.com/de そして訪問者はオンです example.com/de/preise/、これが返ります /preise/、次に、各ロケール& #39; s の原点を接頭辞として付けられます。 trailing スラッシュの処理は、見た目よりも重要です: /preise あんど /preise/ は異なる URL であり、非正規形に注釈を向けることは です トレーリングスラッシュの不一致 これにより、完璧に見えるセットに対してリターンタグ エラーが発生します。 user_trailingslashit サイト&#39; のパーマリンク設定を尊重しているため、WordPress が提供する内容と一致します。

ここでの仮定は、翻訳されたURLは構造的に並列であるということです: /pricing/ へのマップ /de/pricing/。 あなたのドイツ語 slugs も翻訳されているなら、 /de/preise/、この関数は十分ではなく、次のセクションである明示的なマッピングが必要です。

slugs が異なる場合: ポストメタ マッピング

翻訳されたslugsはユーザーにとってもランキングにとっても優れており、パスを導き出すことができないことを意味します 代わりにカウンターパートを保存します:

/**
 * Meta key holds a JSON map: {"de-DE": 123, "es-ES": 456} of post IDs,
 * or absolute URLs for external installs.
 */
function mysite_alternates_for( int $post_id ): array {
    $raw = get_post_meta( $post_id, '_hreflang_alternates', true );
    $map = $raw ? json_decode( $raw, true ) : [];
    if ( ! is_array( $map ) ) {
        return [];
    }

    $out = [];
    foreach ( $map as $hreflang => $target ) {
        $url = is_numeric( $target ) ? get_permalink( (int) $target ) : $target;
        if ( $url ) {
            $out[ $hreflang ] = $url;
        }
    }
    return $out;
}

その後、 wp_head callback は現在の post&#39; を印刷する前にそのマップに独自のエントリをマージするため、セットは完全で自己参照になります:

function mysite_print_hreflang_mapped(): void {
    if ( ! is_singular() ) {
        return;
    }
    $post_id = get_queried_object_id();
    $alts    = mysite_alternates_for( $post_id );
    if ( count( $alts ) < 1 ) {
        return; // Nothing to declare: a one-entry cluster is not a cluster.
    }

    $alts[ mysite_hreflang_for_locale( get_locale() ) ] = get_permalink( $post_id );
    $alts['x-default'] = $alts['en-US'] ?? get_permalink( $post_id );

    foreach ( $alts as $hreflang => $url ) {
        printf(
            '<link rel="alternate" hreflang="%s" href="%s" />' . "\n",
            esc_attr( $hreflang ),
            esc_url( $url )
        );
    }
}

メンテナンスコストはメタを両側に記述しなければならないことです.カウンターパートピッカーを持つ管理UIは正直な解決策です; CSVからマップにポピュレーションするWP-CLIコマンドは高速なものです.1 方向の宣言はまさにその通りなので,あなたがしてはならないことは片側のみにポピュレーションすることです. 返品タグがありません 失敗.

マルチサイト: ネットワークからマップを導出します

各言語がマルチサイトネットワーク内のサイトである場合、マップはすでに存在します:

function mysite_network_hreflang_map(): array {
    $map = [];
    foreach ( get_sites( [ 'number' => 50 ] ) as $site ) {
        switch_to_blog( (int) $site->blog_id );
        $map[ mysite_hreflang_for_locale( get_locale() ) ] = home_url();
        restore_current_blog();
    }
    return $map;
}

結果をトランジェント; にキャッシュします switch_to_blog に a wp_head あらゆる要求に引っ掛けることは、あらゆる規模のネットワーク上の実際のコストです。そして注意してください get_locale() アンダー switch_to_blog: site&#39; s の場合にのみ、切り替えられたサイトを反映します WPLANG オプションが設定されます。これは通常の場合ですが、定数によって構成されたネットワークでは保証されません。

どのアプローチがあなたのサイトに合いますか?

設定 近づく 努力
並列 slugs, ロケールが少ない 静的配列プラス導出パス 最低; 1 つの関数
slugs を翻訳しました ポストメタ対応マップ 適度;編集ワークフローが必要です
マルチサイト、言語ごとに 1 つのサイト から派生する get_sites()、 キャッシュ 低コード、キャッシュ規律が必要です
翻訳を管理する Polylang または WPML プラグイン&#39; s 出力を使用します X-default を発することを確認します
手動翻訳フィールドを備えた SEO プラグイン それを使用してから、レンダリングされたヘッドを確認してください 重複ブロックに注意してください

代わりにサイトマップにフレフラングを入れる

ページの頭がすでに混雑している場合、またはブロックが頭の残りの部分よりも長いほど十分なロケールがある場合は、サイトマップが代替手段です。 WordPress 5.5 以降が出荷されます コアサイトマップ、フィルターはフィルター可能ですが、フィルターは代替品を念頭に置いて設計されておらず、名前空間宣言もオンになっています <urlset> きれいに触れることができるコアではありません。

実用的なルートは、競合するのではなく、書き換えルールから提供されるスタンドアロンのサイトマップです wp_sitemaps:

add_action( 'init', function () {
    add_rewrite_rule( '^sitemap-i18n\.xml$', 'index.php?mysite_i18n_sitemap=1', 'top' );
} );

add_filter( 'query_vars', fn( $vars ) => array_merge( $vars, [ 'mysite_i18n_sitemap' ] ) );

add_action( 'template_redirect', function () {
    if ( ! get_query_var( 'mysite_i18n_sitemap' ) ) {
        return;
    }
    header( 'Content-Type: application/xml; charset=UTF-8' );

    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" ';
    echo 'xmlns:xhtml="http://www.w3.org/1999/xhtml">' . "\n";

    foreach ( mysite_translated_paths() as $path ) {
        echo "  <url>\n    <loc>" . esc_url( home_url( $path ) ) . "</loc>\n";
        foreach ( mysite_hreflang_map() as $hreflang => $origin ) {
            printf(
                '    <xhtml:link rel="alternate" hreflang="%s" href="%s"/>' . "\n",
                esc_attr( $hreflang ),
                esc_url( untrailingslashit( $origin ) . $path )
            );
        }
        echo "  </url>\n";
    }
    echo '</urlset>';
    exit;
} );

正しく理解するための 2 つのこと。 The xmlns:xhtml 宣言オン <urlset> が必須; それがなければ、代替エントリは無視され、ファイルは依然としてサイトマップとして検証されます。これは、再びサイレント失敗パターンです。そして、ルールを追加した後、すべてのリクエストではなくアクティベーション時に、ルールを 1 回フラッシュして書き直します。

これを行ったら、ヘッド出力を削除します。 両方を発光するのは、 実装方法の混合、これはあなたにドリフトする2 つのソースを与えます.

重複ブロック問題

これはWordPress特有の失敗で、コードを書く前に確認する価値のあるものです いくつかのプラグインがフレフランを発し、一度に複数のプラグインがアクティブになります 翻訳関係で構成されたSEOプラグイン、多言語プラグイン、新しいテーマ機能はすべてに喜んで印刷されます wp_head、そして結果は異なる内容とおそらく2 つの2 つまたは3 つのブロックです x-default エントリ.

Google&#39; 1 ページ内の矛盾した注釈の処理は、それらを信用しないことです。つまり、フレフランがなく、ブロックが 3 つになったサイトは、以前よりも状況が悪化する可能性があります。

プラグインの設定ではなく、レンダリングされた出力を確認してください:

curl -s https://example.com/de/preise/ | grep 'rel="alternate"' | grep hreflang

行を数えて、個別のコードを数えます。 1ロケールにつき1 エントリプラス1 x-default、そして何も繰り返されなかった。 away を設定できないセットをプラグインが発している場合、通常のエスケープハッチは からそのアクションを削除することです wp_head 上にあなたのものを追加するのではなく:

// Example shape: find the real hook and callback with `has_action`.
add_action( 'init', function () {
    remove_action( 'wp_head', 'some_plugin_hreflang_output', 10 );
} );

正規のタグ、そしてそれらを壊さないこと

WordPress 発し rel="canonical" 特異なビューをスルーします rel_canonical()、そしてそれはpost& #39; s自身のpermalink、ほしいと思う何を指す。 seoプラグインのほとんどはそれ自身の、またデフォルトで自己参照と取り替える。

からのルール フレフラング vs カノニカル applies unchanged: every page canonicalizes to itself, and hreflang describes the relationships between those self-canonical pages. wordpress風味の方法は、それを破るには、プラグイン設定は、翻訳された投稿を&quot; primary&quot; 言語バージョンに正規化、賢明な重複排除オプションのように読み、静かにインデックスからあなたの翻訳を削除する設定を提供している場合、言語を超えて正規化、オフにしてください。

結果の検証

2 つの兄弟ページを取得して、それらの注釈ブロックを比較します。これらは同一であり、標準が異なるだけである必要があります。次に、名前を付けたすべての URL がリダイレクトせずに 200 を返すことを確認します。これは、廃止されたロケールと変更されたパーマリンクが正しいセットが壊れたセットに腐る方法であるためです。

セットに貼り付けます フリーフレフランジジェネレータ コードを検証するには、ISO 形状に対して各値をチェックし、認識されないサブタグにフラグを立てます en-UK、重複をキャッチし、相対URLを拒否し、セットにフォールバックがない場合に警告します。 URLがまだ公開されていないクライアントサイトを記述している場合に問題となる、完全にブラウザで実行されます。 次に、Search Console& #39; s International Targeting reportを使用して進行中のチェックを行い、 フレフラング ツールガイド それに関するワークフローのために.

よくある質問

WordPressは自動的にフレフラングタグを追加しますか?

いいえ コアは、正規のリンクと様々なヘッドリンクを排出するが、言語について何も交互に. Hreflangはプラグインから、またはあなた自身のものから来ます wp_head 出力.

プラグインなしでWordPressにhreflangを追加するにはどうすればよいですか?

フック wp_head そしてaを印刷します <link rel="alternate" hreflang> コントロールするマップ内のすべてのロケールの行 x-default グループ内のすべてのページにエントリーします。 で値をエスケープします esc_attr あんど esc_url

WordPress テーマのフレフラング タグはどこに行きますか?

に引っ掛かった関数で wp_head、テーマではなく、小さなmuプラグインが理想的ですので、テーマを切り替えても、注釈が静かにドロップされることはありません。

翻訳したページが異なる slugs だったらどうでしょう?

何も導かない. postメタに対象となるpost IDやURLを格納し,レンダー時にマップを読み込む.両側にそれをpopulateするか,またはmissing returnタグを作成する.

Polylang と WPML は hreflang を扱いますか?

はい、彼らが管理する翻訳についてです。 出力には以下が含まれます x-default そして、競合するブロックを放出している 2 番目のプラグインはないということです。

なぜ1 ページに2 つのフレフラングブロックがあるのですか?

2 つのことが印刷されています wp_head:通常はSEOプラグインと多言語プラグイン、またはプラグインと独自の機能。 1ページの矛盾した注釈は信用されないので、レイヤー化せずに削除する。

各 WordPress 言語バージョンには独自の標準バージョンが必要ですか?

はい、自己参照です。翻訳された投稿を第一言語に正規化するプラグイン設定を使用しないでください。これにより、投稿がインデックスから削除され、フレフラング セットもキャンセルされます。

WordPress マルチサイト ネットワーク全体に hreflang を追加するにはどうすればよいですか?

ループ get_sites()、各ブログに切り替えてそのロケールを読みます home_url()を実行し、その結果のマップをトランジェントにキャッシュします。 running switch_to_blog あらゆるリクエストに応じて wp_head は、大規模なネットワークでは高価です.


Comments

0 comments

0/2000 characters

No comments yet. Be the first to share your thoughts!