phpMyAdminだけが救いの手だった件【WordPress】

管理しているクライアントさんのサイトについて、こんなメールが届きました。

スマホでヘッダーメニューを一度タップすると、文字がほとんど見えなくなります。
ページを閉じても戻りません。他のスマホでも同じでした。

確認すると、たしかにスマホのトップページだけで起きます。PCでは問題なし。
ここから半日がかりの犯人探しが始まりました。

目次

症状:タップしたメニューだけが消える

  • スマホ表示のトップページだけで起きる
  • 一度タップしたメニュー項目の文字が、背景と同じ色になって見えなくなる
  • ページを開き直しても戻らない

「一度タップすると」「開き直しても戻らない」。この2つがヒントでした。
ブラウザには 訪問済みのリンク を記録する仕組みがあり、CSSの :visited で色を変えられます。訪問履歴が残る限り、色も戻りません。

原因1:たった1行の a:visited

検証ツール(DevTools)でメニューの文字を調べると、こんなCSSが効いていました。

a:visited { color: inherit; }

「訪問済みのリンクは、親要素の文字色を使う」という指定です。
メニューの文字色は親から受け継ぐと背景と同じ色になるため、タップした瞬間に文字が消えていました。

検証ツールでこの行のチェックを外すと、文字が戻ります。原因は確定です。

ところが、どこにも書いていない

テーマの開発元に問い合わせると、「この行を削除すれば直ります」との回答。
ところが、どこを探しても見つかりません。

  • 外観 → カスタマイズ → 追加CSS
  • 子テーマの style.css
  • コードスニペット系プラグイン

どこにもないのです。

データベースを全文検索して見つけた

最終手段として、phpMyAdmin でデータベース全体を検索しました。検索語はCSSの近くにあったクラス名 calendar です。

注意: phpMyAdminの「構造」タブにある「フィルタ」はテーブル名の絞り込みです。データの中身を探すときは「検索」タブを使います(私は一度間違えました)。

見つかった場所は wp_postmeta テーブル、つまり 固定ページごとのカスタムCSS欄 でした。
テーマには、ページ単位でCSSやJavaScriptを追加できる機能があります。トップページの月別カレンダー用に、以前の自分がそこへ書いていたのです。

ところがテーマがバージョンアップして、個別ページに書き込んだCSS を非表示にしない仕様になっていたのでした。
ようやく表示方法を見つけました。

.calendar a:link  { color: #fff; }
.calendar a:hover { color: #ccc; }
a:visited { color: inherit; }   /* ← .monthcalendar を付け忘れ */

前の2行には .calendar が付いているのに、3行目だけinherit。
そのためカレンダーだけでなく、サイト全体のリンク に効いていました。トップページだけで起きたのは、そのページ専用のCSSだったからです。

それにしてもCSSがphpMyAdminで探さないと見つからないという経験は初めてでした。

.calendar a:visited { color: #fff; }

ついでに、同じブロックにあったこの記述も直しました。

/* 修正前:td が単独指定になり、全ページの表に効いてしまう */
.calendarth, td { ... }

/* 修正後 */
.calendar th, .monthcalendar td { ... }

これでメニューの文字は消えなくなりました。めでたし……とはいきませんでした。

原因2:今度はカレンダーが消えた

CSSを直したあと、同じ場所のJavaScriptも少し整えて保存しました。
すると、エラーになってしまいました。

JavaScriptを元に戻しても直りません。キャッシュを消しても、シークレットウィンドウでもダメです。

Consoleを見ると、こんなエラーが出ていました。

Uncaught SyntaxError: Unexpected token ')'

実際にページに出力されているスクリプトを確認して、ようやく理由がわかりました。

// 保存したコード
const display = () => {
  for (let num = 0; num < 6; num++) {

// 実際に出力されていたコード
const display = () => {
  for (let num = 0; num < 6; num++) {

保存した瞬間に、記号がHTML用の文字に変換されていた のです。

書いたもの保存後
=>=&gt;
<&lt;
&&&amp;&amp;
'&#039;(一部だけ)
`(バッククォート)削除

さらに if (page <= 0) { … } の < から次の > までがHTMLタグとみなされ、間のコードが丸ごと消えていました。これではJavaScriptとして動くはずがありません。

なぜこうなったのか

今回、JavaScriptはブロックエディターの 「カスタムフィールド」パネル から保存していました。
カスタムフィールドは本来、短い文字や数値を保存するための機能です。セキュリティ上の理由で、< や > を含む値はHTMLとして無害化されることがあります。

CSSは同じ方法で保存しても無事でした。JavaScriptには < や => が多いので、まともに影響を受けたのだと思います。

解決:phpMyAdminで直接書き換える

変換を避けるため、phpMyAdminで該当の値を直接書き換えました。

SELECT meta_id, meta_value
FROM wp_postmeta
WHERE post_id = 119
  AND meta_key = '(JS用のキー名)';

表示された行を「編集」し、meta_value を正しいコードに置き換えて「実行」。
これで月タブが復活しました。

注意: phpMyAdminでの直接編集はやり直しがききません。事前にバックアップを取り、書き換えるのは目的の1行だけにしましょう。

今回の教訓

  1. :visited などの汎用的なセレクタには、必ず範囲を絞るクラスを付ける。
    1行の付け忘れが、何年も後にサイト全体へ影響しました。
  2. CSSやJSをなるべく個別ページに書かない、または「どこに書いたか」を記録しておく。
    個別ページに CSS が書けるか書けないかはテーマの仕様によるので、テーマに依存する形になります。
    なるべく個別ページには記述しない方が安全だなと思いました。
    また書いた場所がわからないと、原因がわかっても直せません。今回はデータベース検索で見つけました。
  3. カスタムフィールド欄からJavaScriptを保存しない。
    見た目は保存できていても、中身が変わっていることがあります。テーマやプラグインの専用の入力欄から保存しましょう。

今後このJavaScriptは、自作プラグインに移してGitで管理する予定です。
「どこに書いたっけ?」を二度と繰り返さないために。

同じように「CSSが原因なのは確実なのに、どこにも見当たらない」「JavaScriptが突然壊れた」と困っている方の参考になれば幸いです。

目次