wp_optionsが勝手に文字コード変換してた話

きっかけは地味でした。ブランド名の表記を「Cat’s Hand」に統一する作業をしていたときに、地味に気になる挙動に遭遇しました。サイトの基本情報を管理しているblognameオプションを確認したら、アポストロフィが勝手にエンティティ化されていたのです。原因を追いかけたら、WordPress側の仕様と、テーマ側の参照先の両方に理由がありました。

🎥 この記事の内容は動画でも解説しています。

- YouTube
YouTube でお気に入りの動画や音楽を楽しみ、オリジナルのコンテンツをアップロードして友だちや家族、世界中の人たちと共有しましょう。

気づいたきっかけ

記事や固定ページの本文中に小文字で紛れ込んでいた「cat’s hand」表記を、正式な「Cat’s Hand」に直す作業のついでに、サイトの基本設定も確認しておこうと思い、WP-CLIでサイト名を見てみました。

結果は意外でした。wp option get blognameを実行すると、返ってきたのはCat's Handという文字列でした。管理画面の「設定→一般」を見る分には普通に「Cat’s Hand」と表示されているのに、DB上の生の値はHTMLエンティティ化されたアポストロフィを含んでいたことになります。

原因を調べたら、WordPress core の仕様だった

原因はcore の仕様でした。調べてみると、これはバグでも文字化けでもなく、WordPress core の意図した動作でした。blognameblogdescriptionのようなオプションは、保存時にsanitize_option()を経由し、その中でesc_html()がかけられる仕様になっています。

つまり、管理画面で「Cat’s Hand」と入力して保存した時点で、DBにはCat's Handというエンティティ化済みの文字列として保存されるのが正しい挙動ということです。表示側(bloginfo('name')など)では改めてエンティティがデコードされて表示されるため、管理画面や通常のテーマ出力では違和感なく「Cat’s Hand」に見えていた、というわけでした。

それだけでは終わらなかった

話はまだ終わりません。ここまでで「仕様なら仕方ない、表示は正しいし気にしなくていいか」と一旦納得しかけたのですが、サイトを一通り見て回ったところ、フッター付近のSNSフォローウィジェットだけ表記が違うことに気づきました。他の場所は「Cat’s Hand」なのに、そこだけ小文字寄りの表記のまま残っていたのです。

ここにも原因がありました。調べてみると、使っているCocoonテーマのSNSフォローウィジェットは、サイト名(blogname)ではなく投稿者(管理ユーザー)のdisplay_nameを参照して表示名を組み立てる仕様でした。blognameだけ直しても、こちらのウィジェットには反映されなかったのはこのためです。

wp user update 1 --display_name="Cat's Hand"のように投稿者情報側も合わせて直したところ、ようやくサイト全体で表記が揃いました。

他のオプションは大丈夫か、ついでに確認した

念のため範囲を広げました。ここまで来ると「他の設定も同じようにエンティティ化されていないか」が気になって、blogdescription(キャッチフレーズ)や、SEO系プラグインが持っているタイトル・ディスクリプションの設定も一緒に確認しました。結果はどちらも問題なく、アポストロフィやクォートを含まない文字列だったので今回は実害が出ていませんでしたが、もし引用符を含むキャッチフレーズを設定していたら、同じようにエンティティ化された生の値がどこかで表示崩れを起こしていた可能性はあります。「今回はたまたま実害がなかっただけ」というのは、頭の片隅に置いておこうと思いました。

この件から学んだこと

教訓はシンプルです。今回の件で改めて感じたのは、「表記を直す」といっても、直すべき場所が1箇所とは限らないということです。WordPressの基本設定(blogname)を直しただけで安心してしまうと、テーマ側が別の項目(今回で言えば投稿者のdisplay_name)を参照している箇所を見落とします。

教訓はもうひとつあります。また、DB上の生の値と画面に表示される値が一致しないケースがある、というのも意識しておいた方がよさそうです。今回のようにエンティティ化されているだけなら実害はありませんが、WP-CLIやSQLで直接値をいじる作業をするときは、「画面で見えている値」と「DBに保存されている値」が必ずしも同じ文字列ではない、という前提を持っておくと事故を防げます。

まとめ

アポストロフィひとつのことですが、追いかけてみると WordPress core の仕様(sanitize_option()によるエンティティ化)と、テーマ側の独自の参照先(投稿者のdisplay_name)という、2つの別々の理由が重なっていました。表記統一のような一見単純な作業ほど、こういう見落としが起きやすいのかもしれません。

この記事の内容を、YouTube Shortsでも紹介しています

この記事を書いた人

Web制作歴10年近く。WordPressのテーマカスタマイズやコーディングを中心に、副業・本業ともにweb制作に携わっています。このブログでは、実際に手を動かして分かったことを書いています。

Cat's Handをフォローする

この記事が参考になったら、応援クリックをお願いします

タイトルとURLをコピーしました