FacebookのOG画像が「カビのように」消えないとき:ページビルダー製Shopifyページの落とし穴
FacebookのOG画像が「カビのように」消えないとき
ページビルダーで作ったShopifyの固定ページ。FacebookにシェアしたときのOG画像(サムネイル)を新しいものに差し替えたのに、何度シェアデバッガーで再スクレイピングしても古い画像のまま残り続ける——。
この「画像だけがカビのようにしつこく残る」現象には、いくつもの落とし穴が積み重なっている。実際に丸ごとハマって抜け出した記録を、原因の層ごとに一般化して残しておく。
結論を先に
ページビルダー製のページは、テーマの標準レイアウト(layout/theme.liquid)を通らないことがある。専用レイアウトで描画されている場合、theme.liquid をいくら編集しても公開ページには一切反映されない。真の注入先は、そのページのテンプレートJSONが指す "layout" の方だ。
症状
- シェアデバッガーで「もう一度スクレイピング」しても、OG画像が旧クリエイティブのまま。
- ページ上の画像自体は差し替え済み。ブラウザの「ソースを表示」では新URLが見えることもある。
- なのにFacebookだけが古い画像を握って離さない。
原因は1つではなく、3層に積み重なっていた
層1:OGタグが二重に出力されていた
テーマ本体が新しいURLのOG画像を出力する一方で、ページビルダーのアプリ埋め込みが独自のOGタグで古いURLを出力していた。HTMLの中に og:image が2回出ている状態だ。
クローラーは複数の og:image があるとき、最後に出現したものを採用する傾向が強い。ページビルダーのタグがテーマより後に出ていたため、古いURLが勝っていた。さらに og:image(メイン)と og:image:secure_url が別々のファイルを指す矛盾まで起きていた。
教訓:OGの不一致を見たら、まずテーマとページビルダーの二重出力を疑う。そして「最後勝ち」を意識する。
層2:「同じURL・中身だけ差し替え」というキャッシュの罠
古い画像のURLはそのままに、そのURLの中身(ファイル実体)だけを新しい画像に差し替えていた。これはFacebookには効かない。
Facebookは画像をURL単位でキャッシュする。一度そのURLで取得したバイト列を保持するので、URL文字列が変わらない限り再取得しない。中身を入れ替えても、表示は古いまま固まる。
教訓:画像差し替えはURLごと変える。同一URLの中身差し替えはキャッシュに勝てない。ファイル名やクエリ(
?v=...)を含め、文字列として新しいURLにすること。
層3:テーマ編集が描画に乗らない(これが決定打)
ここが一番の沼だった。theme.liquid の <head> に正しいOGタグを足しても、公開ソースに何も出てこない。試しに無害なHTMLコメントを入れても、それすら出ない。
調べると、このページはページビルダーの専用レイアウト(theme.gempages.blank のような名前)で描画されていた。ページのテンプレートJSONに、こう書かれている:
{
"layout": "theme.gempages.blank"
}
つまり layout/theme.liquid ではなく、layout/theme.gempages.blank.liquid を使っていた。標準レイアウトを編集しても、このページには永遠に届かない。
教訓:ページビルダー製ページは
theme.liquidを通らないことがある。テンプレートJSONの"layout"を必ず確認し、真の注入先レイアウトを直す。
切り分けの手順(再現できる順番)
- 公開HTMLを匿名状態(ログアウト or 別経路)で取得して
og:imageを確認する。ログイン中の「ソースを表示」と、クローラーが見るHTMLは食い違うことがある。クローラーが見るのは匿名状態の方だ。 og:image(メイン)とog:image:secure_urlが別URLを指していないかを見る。指していたら二重出力のサイン。- テーマに無害なHTMLコメントを一行入れ、公開ソースに出るか確認する。出てこなければ「編集しているテーマ ≠ そのページの描画レイアウト」が確定する。
- 該当ページのテンプレートJSON(
templates/page.*.json)の"layout"を確認し、真の注入先レイアウトファイルを特定する。
解決:レイアウトの </head> 直前で上書き再出力
真の注入先である専用レイアウトファイルの </head> 直前に、そのページ限定で正しいOGタグを再出力する。
{%- if page.handle == 'your-page-handle' -%}
<meta property="og:image" content="https://example.com/.../new-image.jpg?v=...">
<meta property="og:image:secure_url" content="https://example.com/.../new-image.jpg?v=...">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="628">
<meta property="og:image:alt" content="(画像の説明)">
{%- endif -%}
効く理由とポイント:
</head>の直前に置くので、content_for_header由来のテーマ/ページビルダー双方のOGタグより確実に後に出る。クローラーは最後の値(新URL)を採る。- URLは
https://で統一する。テーマによってはメインのog:imageがhttp://のことがあるが、Facebookはhttps版を好む。 - ページ限定の条件(
page.handle)は必須。専用レイアウトはビルダー製の全ページ共通であることが多く、条件を外すと他のページ全部に同じ画像が出てしまう。 - 確認は必ず、プレビュー用パラメータ(
?key=...など)の付かない素のURLをシークレットウィンドウで。
やってはいけない/効かない手
- JSでDOMからタグを消す:無効。クローラーは生HTMLしか読まず、JavaScriptを実行しない。消すなら出力段階(サーバーが返すHTML)で対処する。
- ビルダーのタグ文字列を探して削除:多くの場合、そのタグはレイアウトファイル上に文字列として存在しない(
content_for_headerが動的生成している)。削除対象がコードに無いので、上書きが正解になる。
恒久運用での注意
ページビルダーが生成するテンプレートJSONや専用レイアウトは「自動生成(auto-generated)。更新で上書きされる可能性あり」と明記されていることがある。ビルダーの大型アップデートや再公開のあとに、足したOGタグが消えていないか定期的に確認しておくと安全だ。
総じて、この手の「OG画像が更新されない」問題は、Facebookが意地悪なのではなく、こちらが出しているHTMLが本当に新しい値になっているかという一点に尽きる。匿名で生ソースを取り、出現順を見て、本当の描画経路を突き止める。順番に潰せば必ず勝てる。