いやー、かなり弱っておりました。
クライアントさんから「新規記事を作ったけれど、そのパーマリンクにアクセスすると404になるんだけど」というリクエストが来まして。
そのサイト、「Custom Permalinks」というプラグインを使ってます。ちょっとこれまでにも小さな問題やnoticeを吐き出しまくる困ったちゃんだったので正直「またか」という気分だったのですが。
確かに「その記事だけ」パーマリンクがおかしく、404になってしまう。
ググってみても大体は.htaccessの問題で全てのシングルページが404になる、というお話ばかりで、どうにも糸口がつかめずにいたのです。
対症療法として気づいたのは、そのページのカスタムパーマリンクを一文字でも変えると、うまくつながるということ。
しかしそれでは、症状が出たときにクライアントさんが思ったようにパーマリンクを設定できないということで、できれば根本的に解決したかったのです。
で、あれでもないこれでもないと探していると…
管理画面のツールに「Custom Permalinks」という項目があるじゃないですか。
これ今までに見たことがなかったよ。
なんかヒントが無いかな―と思って調べていたら…あった。
Custom Permalinksを利用している記事一覧なのですが、同一タイトル・同一パーマリンクのものが2つ。ひとつはwebmagazineというカスタム投稿タイプ、ひとつはrevisionという謎の投稿タイプが当てられてます。
で、「Custom Permalinks revision 404」でググってみたら…これだ!
Custom Permalinks 404 Error – potentially caused by revisions
ななめ読みなんですけど、
- なんらかの不具合でrevisionにリダイレクトが設定されてしまい、記事へのリダイレクトとかぶってしまう。
- なのでこのパーマリンク自体が二重に設定されてしまっており、コンフリクトが起きているようだ
- 問題のある記事のリビジョンを全てプラグインを使って消したら問題は解決した
- でも毎回そんなことやってられっかよ
- プラグインのphpをゴニョゴニョしたら解決したよ!
というような内容でございました。
ということで、その手順。
wp-content/plugins/custom-permalinks/custom-permalinks.phpの145行目付近(もちろんバージョンによって異なります。当方のケースは0.7.16)にあるcustom_permalinks_request($query)なる関数の中にあるSQL文。
$sql = "SELECT $wpdb->posts.ID, $wpdb->postmeta.meta_value, $wpdb->posts.post_type FROM $wpdb->posts ". "LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id) WHERE ". " meta_key = 'custom_permalink' AND ". " meta_value != '' AND ". " ( LOWER(meta_value) = LEFT(LOWER('".mysql_real_escape_string($request_noslash)."'), LENGTH(meta_value)) OR ". " LOWER(meta_value) = LEFT(LOWER('".mysql_real_escape_string($request_noslash."/")."'), LENGTH(meta_value)) ) ". "ORDER BY LENGTH(meta_value) DESC LIMIT 1";
とありますね。これに一行挿入して
$sql = "SELECT $wpdb->posts.ID, $wpdb->postmeta.meta_value, $wpdb->posts.post_type FROM $wpdb->posts ". "LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id) WHERE ". " meta_key = 'custom_permalink' AND ". " meta_value != '' AND ". " post_type NOT IN ('revision') AND ". " ( LOWER(meta_value) = LEFT(LOWER('".mysql_real_escape_string($request_noslash)."'), LENGTH(meta_value)) OR ". " LOWER(meta_value) = LEFT(LOWER('".mysql_real_escape_string($request_noslash."/")."'), LENGTH(meta_value)) ) ". "ORDER BY LENGTH(meta_value) DESC LIMIT 1";
そう、適当なところに
" post_type NOT IN ('revision') AND ".
という一行のクエリを挿入してrevisionを無視して処理するようにしてあげると解決しちゃったのでした。
答えは英語であれ、そのものズバリのものがあったのに、そこに行き着くのに大変な苦労をした、そんなお話でした。
このブログ主の夫のほう。大阪を中心に活動するウェブデザイナー。水交デザインオフィス代表。JUSO Coworking運営。趣味でハウス・ディスコDJ / デレマスP。共著書『世界一わかりやすいWordPress 導入とサイト制作の教科書』発売中です。