WordPressでカノニカルURLと現在のURLが違うときにカノニカルURLに301リダイレクトさせる方法
このページに来た人はやりたいことがはっきりしているはずなので説明よりもまず、結論から。
functions.phpに↓を書いてください。
add_action( 'template_redirect', 'canonical_redirect' );
function canonical_redirect(
) {
$canonical = null;
if( is_home() || is_front_page() ) {
$canonical = home_url();
} elseif ( is_category() ) {
$canonical = get_category_link( get_query_var('cat') );
} else if(is_tag()){
$canonical = get_tag_link(get_queried_object()->term_id);
} elseif ( is_search() ) {
$canonical = get_search_link();
} elseif ( is_page() || is_single() ) {
$canonical = get_permalink();
} else{
$canonical = home_url();
}
//現在のURLがcanonicalと違う場合はcanonical URLに飛ばす。
$current_url = "https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
if ($canonical !== $current_url) {
header("Location: $canonical", true, 301);
exit;
}
}
このコードにより、いま表示しているページのURLとそのページに設定されているカノニカルURLが違う場合に、今のURLがカノニカルURLに変わります(リダイレクトします)。
まずは、とりあえずこれを自分のWordPressのfunctions.phpにコピペして、期待した動作をするか見てください。
大体の場合はこれだけで実現するはず。
どんな処理をしているの?
以下のような処理をしています。
表示したページのカノニカルURLを作成。
作成したカノニカルURLと現在のURLを比べて、同じかどうかを判断する。
違うならカノニカルURLに移動する。(中身は同じなので見ている人にとっては何も変わらない)
以上の処理を「canonical_redirect」という命令1つで実行できるようにする。
「canonical_redirect」を、ページを表示させる前の準備の1つ、「template_redirect」の処理をするタイミングで実行する。
このリダイレクトに何の意味があるの?
↓のように末尾にスラッシュがあるかないかの違いだけのURLは、普通は同じページを意味します。
- http://aiueo.com/kakikukeko
- http://aiueo.com/kakikukeko/
ところが、Google Analyticsでは別のページとしてPVなどが集計されます。
上の画像は表示回数の多い順に表示していますが、/start/firelighter/ページはスラッシュあり・なしで同じページなので、実際はこの2つを合計した数が正しい表示回数です。
別々に集計されてしまうことで、サイト内でよく見られているページを見誤ってしまう可能性があります。
(上の表で言えば、/start/firelighter/ページは1位が正しい分析です)
そうならないために、どちらか1つに統一した方がいいのです。
コードの解説
上記のコードが何をしているのか解説します。
- ページを表示する前に裏側で準備しているときに
- そのページのカノニカルURLと表示しようとしているURLを比べて
- 一致していなかったらカノニカルURLの方に移動させる
という処理をしています。
「1」が「template_redirect」という部分です。
「2」が「$canonical !== $current_url」の部分です。
「3」が「header(“Location: $canonical”, true, 301);」の部分です。
template_redirectとは
コードの最初の「add_action( ‘template_redirect’, ‘canonical_redirect’ );」とは「template_redirectのときに実行しなさい」という命令です。
なぜそのタイミングなのかを説明します。
WordPressはページを表示するまでの数秒間の間に、裏側でいろんな準備をしています。
ざっくり言うと以下のように19個の処理をしています。
- after_setup_theme
- set_current_user
- registered_post_type
- registered_taxonomy
- init
- customize_register
- wp_loaded
- parse_request
- send_headers
- parse_query
- pre_get_posts
- the_posts
- wp
- admin_bar_init
- template_redirect
- wp_enqueue_scripts
- wp_print_scripts
- wp_head
- wp_footer
テーマを自分で編集したことがある人なら、最後のwp_headやwp_footerは聞いたことがあるかもしれません。
それがページを表示する前に実行される最後の処理で、実はその他にもいろんな処理があった、ということだけイメージできればOKです。各処理の内容を理解する必要はありません。
で、この中の15番目「template_redirect」のところで、今回のリダイレクトさせるか、させないかの判断をしている、ということです。
ページ表示したあとにリダイレクトさせるのが普通じゃないの?
なんでそんな中途半端なタイミングで…ページ表示させたあとにリダイレクトさせればいいんじゃないの?と思われるかもしれません。
ページ表示させたあとに「このページは5秒後にリダイレクトします」みたいな注釈が出て勝手にページが移動させられる体験をしたことがある人は多いと思います。
一般的にリダイレクトというとあのイメージが強いです。
あれはJavaScriptというプログラムを使って実現しています。
あの方法でも一応リダイレクトはできます。
が、「このリダイレクトはエラーじゃなくてサイト管理者が意図的にリダイレクトさせてますよ」という意思表示ができないという問題があります。
リダイレクトと一口に言ってもいろんな種類があるのです。(覚えなくていいです。自分もここに書くまで301と302しか知りませんでした。)
301 リダイレクト | 今後ずっと旧URLを新URLに変えたいニュアンスが含まれる。そのページへのユーザーの評価は新URLに反映される。 |
302 リダイレクト | 一時的に新URLに変えるが、そのうち旧URLに戻すときに使う。そのページへのユーザーの評価は旧URLに反映される。 |
303 リダイレクト | POSTリクエストをGETリクエストに切り替えるために使用。フォーム送信後にユーザーを別のページにリダイレクトさせる場合などに使用。 |
307 リダイレクト | 一時的なリダイレクト。HTTP/1.1 で追加。一時的にURLを別のものに変更したい場合に使用。307はHTTPメソッド(GET POSTなど)を維持。リダイレクト後のリクエストが同じメソッドで行われることを保証。 |
308 リダイレクト | 恒久的なリダイレクト。HTTP/1.1 で追加。URLが完全に変更され、元のURLがもう使用されない場合に使用。308はHTTPメソッド(GET POSTなど)を維持。リダイレクト後のリクエストが同じメソッドで行われることを保証。 |
JavaScriptのリダイレクトはこの区別がありません。
そのため、検索エンジンはどっちが真のURLか判断できません。
100万人から見られるページはすごく価値のあるページですが、正しいURLがどっちかわからず、結果どっちのURLも価値のないページと判断されてしまうおそれがあります。
なので、どっちのURLが「真」のURLなのかを伝えるためにPHPで命令する必要があるのです。
PHPでリダイレクトさせるheader()という命令があるので、これを使うわけですが、この命令は、ページが表示されたあとは使えないという制約があります。
「ページが表示されたあと」というのは厳密には間違いで、「何かが出力されたあと」という方が正確です。
ここでは理解しやすさを優先して前者のような表現にしています。
さっきの19の処理は大きく「今から表示させるページのデータ整理」と「ページデータ表示」の処理に分けられます。
リダイレクトさせるheader()の命令はページを表示させる前に終わらせる必要があります。
じゃあ、一番最初に持ってくればいいかというとそれもダメです。
早すぎると「データの整理」が終わってないので、そのページのカノニカルURLが何なのかがわからなくなります。
リダイレクトの実行はできますが、実行するための条件である「そのページのカノニカルURLと表示しようとしているURLを比べて」の判断ができないので、結果、実行されない、ということになります。
なので、「データ整理」と「データ表示」の間でリダイレクトの処理を入れる必要があるのです。
ということで冒頭のコードになります。