画像作りが、記事を書く足かせになっていた
このブログでは、アイキャッチ画像を設定していない記事に対して、タイトルを載せた画像を自動生成してOGP画像として使う仕組みを以前から入れていました。
記事の内容を書くことに比べたら、サムネイル用の画像を毎回作るのは正直かなり面倒な作業です。時間もかかりますし、何より「画像を作らないといけない」と思うと、記事を書く気力自体が削られていきます。ブログを書く方であれば、共感していただける方も多いんじゃないでしょうか。
ただ、この自動生成の仕組みは記事ページ上部のOGP画像にしか効いておらず、関連記事一覧やサイドバーのウィジェットなど、他のサムネイル表示箇所ではアイキャッチ未設定のまま灰色の空欄になっていました。せっかく仕組みがあるのに全箇所に効いていないのはもったいないと思い、今回まとめて手を入れることにしました。
もともとの自動生成の仕組みについては、こちらの記事で紹介しています。
今回はこれを全箇所に展開しようとした話です。
「1つの関数を直せば済むのでは」と思ったが、無理だった
このテーマ(SWELL)にはSWELL_Theme::get_thumbnail()という、アイキャッチ取得を一手に担っている共通関数があります。最初は「この関数さえ直せば、全部の表示箇所に一括で効くのでは」と考えました。実際にそうなれば、修正箇所は1つで済みます。
しかし調べてみると、これは不可能でした。get_thumbnail()は親テーマのfunctions.php内で直接定義されているクラスのメソッドで、フィルターフックが一切用意されていません。しかもこのクラス自体、SWELLのオートローダーが親テーマ固定で読み込む仕様になっているため、子テーマ側で丸ごと差し替えることもできませんでした。
「もっとシンプルにできたらいいのに」と思っていたところに、この壁にぶつかった格好です。1関数を直すだけでは無理だと分かった時点で、じゃあ他にどう手を打てるか、という方向に頭を切り替えました。
表示箇所ごとに個別対応した結果、穴だらけになった
そこで代わりに取った方法が、表示箇所ごとに個別対応する、というものでした。
- 投稿ループが進むたびに、NO IMAGE画像の参照先を動的にOGP自動生成画像へ差し替えるフック
- 前後の記事リンク・ピックアップバナー・内部ブログカードなど、個別の描画関数をそれぞれ上書き
一通り実装した時点では「これで全箇所に効くようになった」と思っていました。ところが後から見直してみると、思っていたより穴だらけでした。
- サムネイルが無い記事で、NO IMAGE画像とOGP自動生成画像が二重に表示されてしまう
- 特定のレイアウト(ビッグ型の一覧表示)だと、CSSの都合でOGP画像ごと非表示になってしまう
- 前後記事リンクやブログカードは「表示中の投稿」とは別の投稿を参照する処理なので、動的差し替えの仕組みが効かず、結局は関数ごとの個別対応が必要になる
やっていることは局所的には正しいのに、組み合わさると意図しない見た目になる。これを一つひとつ直していく形になり、コードもどんどん複雑になっていきました。
方針転換の決め手は「他の実装例」と「将来の負荷」
このタイミングで、「そもそもこの方向で正しいのか」と一歩引いて考え直すことにしました。決め手になったのは2つです。
1つは、同じようなことをしているプラグインを軽く調べてみたところ、多くが「表示のたびに動的生成する」のではなく、「実際に画像ファイルを生成してアイキャッチとして保存する」方式を採っていたことです。自分たちの実装だけが特殊なやり方をしている、というのは何か理由があるはずで、既存の実装例が同じ方向を向いているなら、それは素直に見習うべきだろうと思いました。
もう1つは、今のままの動的生成方式だと、アクセスが増えたときにサーバー側の負荷や表示速度に響いてきそうだったことです。今はまだアクセス数がそれほど多くないので実害はありませんが、同じ画像を毎回ゼロから生成し直すのは、素直に考えて無駄が多い設計です。
この2つが揃ったところで、「表示箇所ごとにフォールバックを増やしていく」というこれまでの方向性をやめて、「投稿を保存したタイミングで実際に画像ファイルを作り、アイキャッチとして設定してしまう」という方式に作り替えることにしました。
具体的には、save_postフックで以下のように処理しています。
- 公開済みの投稿を保存したとき、アイキャッチが未設定なら画像を生成し、
wp_upload_bitsでメディアライブラリに保存、set_post_thumbnailでアイキャッチに設定する - 生成した添付ファイルには専用のメタデータを付けておき、「これは自動生成したものだ」と後から判別できるようにする
- ユーザーが後から手動でアイキャッチを設定し直した場合は、そのメタデータが無いので上書きしない
- 自動生成した画像のままタイトルだけ変更された場合は、画像を作り直して古いファイルは削除する
一度この仕組みでアイキャッチが設定されれば、あとは普通のアイキャッチとして扱われるので、一覧表示だろうと関連記事だろうとog:imageだろうと、どこでも自動的に反映されます。表示箇所ごとに個別対応していたコードは、ほぼ全部消せました。
作り直してみて分かった、最初の実装の甘さ
正直なところ、最初に「表示箇所ごとの個別対応」を作り終えた時点では「これでOKだろう」と思っていました。しかし実際に一つひとつ調べ直してみると、二重表示のバグやレイアウト崩れなど、想像していた以上に穴がありました。
さらに、実ファイル生成方式に作り直したあとも、実際に本番環境で動かして初めて気づいた不具合がいくつかありました。生成した画像の角丸部分が、ローカルの開発環境では正しく透明になっているのに、本番サーバーでは白く塗りつぶされてしまう、という現象です。原因はサーバー側のGDライブラリのバージョン差にありました(この件は別記事で詳しく書く予定です)。
「動いているように見える」ことと「壊れていない」ことは、思っていたより距離があるんだなというのが、一連の作業を通しての実感です。
まとめ
- 「1つの関数を直せば全部解決する」と思っても、テーマやライブラリの構造上そもそも不可能なことがある。その場合は無理に押し通さず、別のアプローチを探す。
- 表示箇所ごとの個別対応は、一見動いていても組み合わさると穴が出やすい。実装が増えてきたら、そもそもの設計を見直すタイミングかもしれない。
- 自分たちの実装が特殊なやり方になっていないか、既存の類似実装を軽く調べてみるのは、方針を決める上で参考になる。
- 実際に手を動かして検証しないと見えてこない不具合は、想像以上に多い。


