検索しても見つからないURL ― 五年前の設計が残っていた場所
サイトマップを作り直すたびに、もう存在しないURLが混ざる。
そんな状態がしばらく続いていました。クローラーを走らせると、四年も前に廃止したはずの製品ページのパスが、毎回きちんと拾われてくる。
/materia/fortuna15/... という形の、旧い階層です。今のサイトには、そんなページはありません。
まずは素直に探しました
最初に疑ったのは、記事の本文です。どこかの記事に古いリンクを書いたまま忘れているのだろう、と。
見つかりません。
次にメニュー、モジュール、テンプレートの設定。どれも空振りでした。
そこで最後の手段として、データベース全体を検索しました。phpMyAdminには、全テーブルをまたいで文字列を探す機能があります。ここに引っかからなければ、少なくともデータベースの中には無いということになる。
結果はゼロ件でした。
これで困りました。データベースに無い。記事にもメニューにも無い。それなのに、クローラーは毎回そのURLを見つけてくる。
どこかに在ることは間違いないのです。ただ、私の探し方では見つからない。
理由は、スラッシュ一文字でした
答えを先に書きます。
その値は、JSONの形式でデータベースに保存されていました。そしてJSONでは、スラッシュが `\/` という形にエスケープされて記録されることがあります。
つまり、データベースの中に実際に入っていた文字列は、こうでした。
materia\/fortuna15\/
私が検索窓に打ち込んでいたのは `materia/fortuna15` です。バックスラッシュが入っていない。だから一致しない。
存在しているのに、検索では出てこない。そういう状態でした。
これはJoomlaに限った話ではありません。カスタムフィールドやプラグインの設定値をJSONで保存する仕組みなら、どのCMSでも起こり得ます。データベース検索で見つからないからといって、無いとは限らないのです。
犯人は、二〇二一年の私でした
見つけ方を変えて、データベースのダンプを取り出し、中を辿っていきました。
出所は、二〇二一年三月に公開した一本の記事でした。素材の単品ページに一覧を差し込むために作った、サブフォーム型のカスタムフィールドです。
六ミリ、十五ミリ、二十一ミリの三つの幅に、それぞれ五十三色分のリンクが入っていました。三本で百五十九件。
さらに厄介なことに、多言語化のために英語の翻訳テーブルにも同じものが入っていました。こちらも百五十九件。合わせて三百十八件のリンクが、五年前の階層を指したまま残っていたわけです。
サイトは何度も作り替えました。URLの構造も変えました。表示は今の形になっています。
それでも、フィールドの中に書き込んだ絶対パスだけは、誰にも触られないまま生き残っていました。
画面のどこにも出てこないので、気付きようがありません。気付かせてくれたのは、クローラーだけでした。
置換する前に、危ないところがありました
直す作業自体は単純です。古いパスを新しいパスに置き換えるだけ。
ただ、ここで一つ、危ないことに気付きました。
英語の翻訳テーブルには、本文中にmaterialという英単語が使われている行がありました。もし`materia`という文字列だけを指定して一括置換していたら、このmaterialも巻き込んで壊していたはずです。
一括置換は、短い文字列で指定するほど危険が増します。今回であれば、パス全体を指定するのが正解でした。
materia\/fortuna15\/ → perla\/15mm-width\/
エスケープされた形のまま、丸ごと置き換える。こうすれば、英単語のmaterialには触れません。
作業は三段階で進めました。まず置換前にSELECTで件数を数える。次にUPDATEを実行する。最後にもう一度SELECTで、古い方がゼロになり、新しい方が想定どおりの件数になっているかを確かめる。
結果は、古いパスがゼロ件、新しいパスが五十三件ずつ三本。英語側も同じで、巻き込まれかけたmaterialは無傷でした。
設計の話として
これは作業の話に見えて、設計の話だと思っています。
二〇二一年の私は、フィールドの中にリンクを直接書き込みました。その時は、それが一番早かったからです。実際、動きました。
問題は、その値が画面から見えない場所に沈んだことです。記事の本文なら編集画面で目に入ります。メニューなら管理画面に並びます。けれどサブフォームの中に入れた百五十九本のリンクは、開いて一つずつ確認しない限り、二度と目に触れません。
リンクをどこに持たせるか。これは見た目の話ではなく、後から直せるかどうかの話です。
今なら、記事IDを指定する形にするか、少なくとも相対的な指定にしておくでしょう。そうすれば、URLの構造を変えた時に道連れにならずに済みます。
サイトを作り替えるとき、私たちは見えているものを直します。見えていないものは、直しようがありません。
だから、作る時点で「これは後から見えるか」を考えておく必要があるのだと思います。
最後に、実務的なまとめ
- データベース全体検索でヒットしないからといって、存在しないとは限らない
- JSONで保存された値は、スラッシュが `\/` にエスケープされている場合がある
- 見つからない時は、ダンプを取り出して中を直接見るのが早い
- 一括置換は、短い文字列を指定するほど危険。パス全体など、長く一意な形で指定する
- 置換の前後にSELECTを挟んで件数を確認する
見つからないものを探して時間を溶かした一日でしたが、原因が分かってしまえば、なんということはありません。同じところで止まっている方の役に立てば幸いです。