WordPressに301リダイレクトを設定するSimple 301 Redirectsというプラグインを導入しました。
PukiWikiで運用していた旧コンテンツをWordPressに引き継いだ後に、Google Search Consoleのクロールエラー対策&SEO対策です。
PukiWikiからのデータ移行については下記の記事をご覧ください。
WordPress用プラグイン Simple 301 Redirects
Simple 301 Redirectsというプラグインですが、phpファイル1つだけで構成されていて、管理画面もURLを設定するだけという名前の通り非常にシンプルです。
Google Search Consoleでクロールエラーが出ているURLをコピーしてRequest欄に貼り付け、リダイレクト先のURLをDestination欄に貼り付けて「変更を保存」ボタンをクリック。
しかし挙動を確認するまでもなく、Request欄に貼り付けたはずのURLが一部消えてしまいます。
どうやらURLエンコードされている部分が消失してしまっているようです。
ソースコードを追いかけてみると、保存する前にWordPressの関数sanitize_text_field
が呼ばれていました。
WordPress関数リファレンスを見ると、
オクテット(’%‘ に続く 2 桁の 16 進数)を除去します。
と明記されています。
これは日本語を含むURLの場合は致命的で、それ以外にも「/」を「%2F」にエンコードするような仕様でも困ったことになります。
プラグイン「Simple 301 Redirects」のカスタマイズ
セキュリティ的なリスクを承知の上で、wp-simple-301-redirects.phpの188行目と189行目にあるsanitize_text_field関数を削除しました。
wp-simple-301-redirects.php
変更前
for($i = 0; $i < sizeof($data['request']); ++$i) {
$request = trim( sanitize_text_field( $data['request'][$i] ) );
$destination = trim( sanitize_text_field( $data['destination'][$i] ) );
if ($request == '' && $destination == '') { continue; }
else { $redirects[$request] = $destination; }
}
変更後
for($i = 0; $i < sizeof($data['request']); ++$i) {
$request = trim( $data['request'][$i] );
$destination = trim( $data['destination'][$i] );
if ($request == '' && $destination == '') { continue; }
else { $redirects[$request] = $destination; }
}
管理画面にはそもそも私以外は入らないのと、登録するURLに怪しいコマンドが入っていないかを確認するというのが前提です。
これで無事に保存できるようになりました。
念のためデータベースのwp_optionsテーブルを確認してみましたが、正常に書き込まれています。
もう一つ問題が浮上。
「301リダイレクト」登録したのに「404 not found」が返ってくる
まあ一筋縄ではいかないとは思っていました。
wp-simple-301-redirects.php
変更前
}
elseif(urldecode($userrequest) == rtrim($storedrequest,'/')) {
// simple comparison redirect
$do_redirect = $destination;
}
変更後
}
elseif(urldecode($userrequest) == urldecode(rtrim($storedrequest,'/'))) {
// simple comparison redirect
$do_redirect = $destination;
}
242行目で「リクエストされたURL」と「保存されているURL」を比較していますので、ここに細工しました。
URLエンコードしたURLを登録した場合、比較する時にはURLデコードしなければ一致しませんね。
これで良しと思ってしばらく運用していたのですが、上記設定ではGoogle Search Console対策しか考えておらず、「https://example.com/日本語/?q=日本語」といったURLエンコードされていない日本語の入ったURLを考慮していませんでした。
ブラウザから送られてくる文字コードはUTF-8でエンコードされるのが主流になりつつありますが、登録するURLが別の文字コードでエンコードされていたり(PukiWikiは通常EUC-JPを吐き出します)、このSimple 301 Redirectsというプラグインは最近では珍しくEUCで書かれています。
先ほどと同じく242行目を修正します。
wp-simple-301-redirects.php
変更前
}
elseif(urldecode($userrequest) == rtrim($storedrequest,'/')) {
// simple comparison redirect
$do_redirect = $destination;
}
変更後
}
elseif(mb_convert_encoding(urldecode($userrequest), "UTF-8","auto") == mb_convert_encoding(urldecode(rtrim($storedrequest,'/')), "UTF-8","auto")) {
// simple comparison redirect
$do_redirect = $destination;
}
比較対象の文字コードを揃えます。
EUC-JPで揃えても良いのですが、昔perl時代にEUCだと一部の文字が正常に表示されなかった記憶があるのでUTF-8にしました。
これで以下の全てに対応できます。
- 未エンコード
/日本語/?q=日本語 - EUC-JPでエンコード
%2f%c6%fc%cb%dc%b8%ec%2f%3fq%3d%c6%fc%cb%dc%b8%ec - UTF-8でエンコード
%2f%e6%97%a5%e6%9c%ac%e8%aa%9e%2f%3fq%3d%e6%97%a5%e6%9c%ac%e8%aa%9e