shopifyはECに特化したCMSなので、ガチ固定の従来のホームページ制作のように直にHTMLソースにdescriptionをバチバチと入力する雰囲気ではありません。
googleスプレットシートにズラッと並んだtitleやdescriptionをとにかく早く仕込みたいです。
そういう要件はありますでしょうか。
検索しました。すると、
スニペットで以下のように/snippets/meta-tags.liquidファイルを作成。
{% render 'meta-tags' %}
で呼び出す方法がたくさん出てきます。
ではmeta-tags.liquidの中身はどういう内容なのでしょう。
管理画面から簡単にできないのでしょうか。
意外と時間がかかるかもです。
今はAIにも聞けます。
情けない話、AIと一緒に作成したコードはとても長く見ずらいものでした。
この共有ファイルは、shopifyに詳しい人が技術的リファクタリングをしてくれましたソースコードになります。
とても見やすく、デバッグ情報のHTMLコメント付き。
要件は以下です。
- theme.lquidにmeta-tags.liquidをrenderさせたい
- 言語切り替えに対応したい
theme.liquid
<!doctype html>
<html class="no-js" lang="{{ request.locale.iso_code }}">
<head>
{% render 'meta-tags' %}
</head>メタタグなので<head>内にmeta-tags.liquidを読み込みさせます。
meta-tags.liquid(snippets)
{%- liquid
assign og_title = page_title | default: shop.name
assign og_url = canonical_url | default: request.origin
assign og_type = 'website'
assign og_description = page_description | default: shop.description | default: shop.name
assign og_image = page_image;
# キーワードの設定
assign meta_keywords = ''
if request.page_type == 'product'
if product.tags != blank
assign meta_keywords = product.title | append: ', ' | append: product.tags | join: ', ' | append: ', astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
else
assign meta_keywords = product.title | append: ', astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
endif
elsif request.page_type == 'collection'
assign meta_keywords = collection.title | append: ', astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
elsif request.page_type == 'article'
if request.path contains '/blogs/feature/' or request.path contains 'feature'
assign meta_keywords = 'FEATURE, astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
elsif request.path contains '/blogs/news/' or request.path contains 'news'
assign meta_keywords = 'NEWS, astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
elsif article.blog.handle == 'feature'
assign meta_keywords = 'FEATURE, astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
elsif article.blog.handle == 'news'
assign meta_keywords = 'NEWS, astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
else
assign meta_keywords = article.tags | join: ', ' | append: ', astro,wave,アストロウェーブ,ASTROWAVE,氷河期世代,株'
endif
else
assign meta_keywords = 'astro,wave,アストロウェーブ,ASTROWAVE'
endif
# Descriptionの設定
assign meta_description = ''
if request.page_type == 'index'
assign meta_description = 'meta.default_description' | t
elsif request.page_type == 'collection'
if collection.handle contains 'all-items'
assign meta_description = 'meta.all_product_description' | t
elsif collection.handle contains 'new-arrivals'
assign meta_description = 'meta.new_arrivals_description' | t
elsif collection.handle contains 'all-jeans'
assign meta_description = 'meta.all_jeans_description' | t
else
# 一般的なコレクションページ(WOMEN'S TOPSなど)
assign meta_description = 'meta.general_collection_description' | t
endif
elsif request.page_type == 'product'
# デバッグ用変数
assign debug_metafield = product.metafields.custom.detail
assign debug_description = product.description
# アイテム詳細メタフィールドを優先して使用
if product.metafields.custom.detail != blank
# JSONリッチテキストからテキスト部分を抽出
assign detail_json = product.metafields.custom.detail
assign detail_text = ''
# "value"フィールドからテキストを抽出
assign value_parts = detail_json | split: '"value":"'
if value_parts.size > 1
for i in (1..value_parts.size)
assign part = value_parts[i] | split: '"' | first
if part != blank and part.size > 5
assign detail_text = detail_text | append: part | append: ' '
endif
endfor
endif
# 抽出したテキストをクリーンアップ
assign detail_text = detail_text | replace: '\n', ' ' | replace: '\\n', ' ' | strip
if detail_text != blank and detail_text.size > 20
assign meta_description = detail_text | truncate: 100
else
# メタフィールドからテキスト抽出に失敗した場合は商品説明を使用
if product.description != blank
assign meta_description = product.description | strip_html | truncate: 100
else
assign items_desc = 'meta.items_description' | t
assign meta_description = product.title | append: ' - ' | append: items_desc
endif
endif
elsif product.description != blank
assign meta_description = product.description | strip_html | truncate: 100
else
assign items_desc = 'meta.items_description' | t
assign meta_description = product.title | append: ' - ' | append: items_desc
endif
elsif request.page_type == 'cart' or request.path contains '/cart'
assign meta_description = 'meta.cart_description' | t
elsif request.page_type == 'customers/login'
assign meta_description = 'meta.login_description' | t
elsif request.page_type == 'customers/register'
assign meta_description = 'meta.register_description' | t
elsif request.page_type == 'customers/reset_password'
assign meta_description = 'meta.reset_password_description' | t
elsif request.page_type == 'customers/account'
assign meta_description = 'meta.account_description' | t
elsif request.page_type == 'customers/addresses'
assign meta_description = 'meta.addresses_description' | t
elsif request.page_type == 'customers/order'
assign meta_description = 'meta.order_description' | t
elsif request.page_type == 'page' and page.handle == 'contact'
assign meta_description = 'meta.contact_description' | t
elsif request.page_type == 'blog' and blog.handle == 'news'
assign meta_description = 'meta.news_description' | t
elsif request.page_type == 'article' and article.blog.handle == 'news'
if page_description != blank
assign meta_description = page_description
else
assign meta_description = ''
endif
elsif request.page_type == 'blog' and blog.handle == 'feature'
assign meta_description = 'meta.feature_description' | t
elsif request.page_type == 'article' and article.blog.handle == 'feature'
if page_description != blank
assign meta_description = page_description
else
assign meta_description = ''
endif
elsif request.page_type == 'article'
# その他の記事ページ(ブログハンドルが空の場合など)
if page_description != blank
assign meta_description = page_description
else
assign meta_description = ''
endif
elsif request.page_type == 'page' and page.handle contains 'store' and page.handle != 'store'
# 個別店舗ページの処理 - メタオブジェクトから動的に取得
assign store_description = ''
assign found_store = false
assign debug_info = ''
assign store_name_test = ''
# theme.liquidと同じ方法でアクセス
for store in shop.metaobjects.store.values
assign store_page_handle = 'store/' | append: store.system.handle
assign debug_info = debug_info | append: 'Checking: ' | append: store_page_handle | append: ' against ' | append: page.handle | append: '; '
if page.handle == store_page_handle
assign found_store = true
# 店舗名が取得できるかチェック(デバッグ用)
assign store_name_test = store.name.value
assign debug_info = debug_info | append: 'Found store: ' | append: store_name_test | append: '; '
# store-detail.liquidと同じ方法でアクセス
if store.seo_description.value != blank
assign store_description = store.seo_description.value
assign debug_info = debug_info | append: 'SEO description found: ' | append: store_description | append: '; '
else
assign debug_info = debug_info | append: 'SEO description empty or not found; '
endif
break
endif
endfor
# デバッグ情報をHTMLコメントとして出力
assign debug_output = '<!-- Store Debug: page.handle=' | append: page.handle | append: ', found_store=' | append: found_store | append: ', store_name=' | append: store_name_test | append: ', store_description=' | append: store_description | append: ', debug_info=' | append: debug_info | append: ' -->'
# メタオブジェクトにseo_descriptionがある場合は使用、なければデフォルト
if store_description != blank
assign meta_description = store_description
else
assign meta_description = 'meta.store_description' | t
endif
elsif template contains 'metaobject/store'
# メタオブジェクト店舗ページの処理 - 直接metaobjectからアクセス
if metaobject and metaobject.seo_description.value != blank
assign meta_description = metaobject.seo_description.value
else
assign meta_description = 'meta.store_description' | t
endif
elsif request.page_type == 'page' and page.handle == 'store'
assign meta_description = 'meta.store_description' | t
elsif request.page_type == 'page'
# 一般的なページの場合、管理画面で設定されたSEO descriptionを優先
if page_description != blank
assign meta_description = page_description
else
assign meta_description = shop.description | default: shop.name
endif
elsif request.page_type == 'search'
assign meta_description = 'meta.search_description' | t
elsif request.page_type == '404'
assign meta_description = 'meta.404_description' | t
elsif page_description != blank and page.handle contains 'store'
assign meta_description = 'meta.store_description' | t
elsif page_description != blank
assign meta_description = page_description
else
assign meta_description = shop.description | default: shop.name
endif
if request.page_type == 'product'
assign og_type = 'product'
elsif request.page_type == 'article'
assign og_type = 'article'
elsif request.page_type == 'password'
assign og_url = request.origin
elsif request.page_type == 'collection'
assign og_image = images['ogp.jpg']
endif
-%}
{% ### TITLE ### %}
{% if template == 'index' %}<title>{{ page_title }}</title>
{% elsif template == 'collection' %}<title>{{ collection.title }} | {{ shop.name }}</title>
{% elsif template == 'customers/login' %}<title>LOGIN | {{ shop.name }}</title>
{% elsif template == 'customers/register' %}<title>REGISTER | {{ shop.name }}</title>
{% elsif template == 'customers/account' %}<title>MY ACCOUNT | {{ shop.name }}</title>
{% elsif template == 'customers/addresses' %}<title>MY ACCOUNT | {{ shop.name }}</title>
{% elsif template == 'blog' %}<title>{{ blog.title }} | {{ shop.name }}</title>
{% elsif template == 'article' %}<title>{{ article.title }} | {{ shop.name }}</title>
{% elsif template == 'product' %}<title>{{ product.title }} | {{ shop.name }}</title>
{% elsif template contains 'page' %}<title>{{ page.title }} | {{ shop.name }}</title>
{% elsif template == 'search' %}<title>SEARCH | {{ shop.name }}</title>
{% elsif template == '404' %}<title>404 | {{ shop.name }}</title>
{% elsif template == 'metaobject/store' %}<title>{{ og_title | escape }} | {{ shop.name }}</title>
{% endif %}
{%- ### DESCRIPTION ### -%}
{% if meta_description != blank %}<meta name="description" content="{{ meta_description | escape }}">{% elsif request.page_type != 'article' %}<meta name="description" content="{{ shop.description | default: shop.name | escape }}">{% endif %}
{% if meta_keywords != blank %}<meta name="keywords" content="{{ meta_keywords | escape }}">{% endif %}
{% ### OG ### %}
<meta property="og:site_name" content="{{ shop.name }}">
<meta property="og:url" content="{{ og_url }}">
<meta property="og:title" content="{{ og_title | escape }}">
<meta property="og:type" content="{{ og_type }}">
{% if meta_description != blank %}<meta property="og:description" content="{{ meta_description | escape }}">{% elsif request.page_type != 'article' %}<meta property="og:description" content="{{ shop.description | default: shop.name | escape }}">{% endif %}
{% ### OG:IMAGE ### %}
{% if og_image %}<meta property="og:image" content="http:{{ og_image | image_url }}">
<meta property="og:image:secure_url" content="https:{{ og_image | image_url }}">
<meta property="og:image:width" content="{{ og_image.width }}">
<meta property="og:image:height" content="{{ og_image.height }}">{% endif %}
{% if request.page_type == 'product' %}<meta property="og:price:amount" content="{{ product.price | money_without_currency | strip_html }}">
<meta property="og:price:currency" content="{{ cart.currency.iso_code }}">{% endif %}
{% if settings.social_twitter_link != blank %}<meta name="twitter:site" content="{{ settings.social_twitter_link | split: 'x.com/' | last | prepend: '@' }}">{% endif %}
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ og_title | escape }}">
{% if meta_description != blank %}<meta name="twitter:description" content="{{ meta_description | escape }}">{% elsif request.page_type != 'article' %}<meta name="twitter:description" content="{{ shop.description | default: shop.name | escape }}">{% endif %}
テンプレートにあった記述、
{% if template ==や、<meta property=”og:や、{% if og_image %}など、丸ごと載せました。
SEOに必要なものがまとめられているファイルですね。
メモ:すぐ忘れそうな見てほしい内容は以下です。
・request.page_typeでURLの判断でmeta_descriptionを出し分けすることろ。
・商品メタフィールドからの説明抽出のエラーバンドリング。
・動的に作成したページのshop.metaobjects.store.valuesを引っ張ってくるところ。
特徴的な機能の抜粋
商品Description処理
# JSONリッチテキストからテキスト部分を抽出
assign detail_json = product.metafields.custom.detail
assign detail_text = ''
# "value"フィールドからテキストを抽出
assign value_parts = detail_json | split: '"value":"'
if value_parts.size > 1
for i in (1..value_parts.size)
assign part = value_parts[i] | split: '"' | first
if part != blank and part.size > 5
assign detail_text = detail_text | append: part | append: ' '
endif
endfor
endif# エラーハンドリング
# 抽出したテキストをクリーンアップ
assign detail_text = detail_text | replace: '\n', ' ' | replace: '\\n', ' ' | strip
if detail_text != blank and detail_text.size > 20
assign meta_description = detail_text | truncate: 100
else
# フォールバック処理
endif- JSONパース処理をLiquidで実装
- 文字列分割による値抽出
- ループ処理でテキスト結合
- フォールバック機能(メタフィールド→商品説明→デフォルト)
メタオブジェクト対応
for store in shop.metaobjects.store.values
assign store_page_handle = 'store/' | append: store.system.handle
if page.handle == store_page_handle
if store.seo_description.value != blank
assign store_description = store.seo_description.value# デバッグ情報をHTMLコメントとして出力
assign debug_output = '<!-- Store Debug: page.handle=' | append: page.handle | append: ', found_store=' | append: found_store | append: ', store_name=' | append: store_name_test | append: ', store_description=' | append: store_description | append: ', debug_info=' | append: debug_info | append: ' -->'- メタオブジェクトからの動的データ取得
- デバッグ情報の出力機能
- 複数店舗への対応
切り貼りして、再利用で効率を上げましょう。
解説はAIに放り込んでください。
言語切り替えに対応したい(jsonを追加する)
descriptionなどのテキストを言語切り替えに対応させたいです。
以下のローカルにあるjsonファイルを編集します。
/locales/ja.json ←日本語のテキストの登録用ファイル
/locales/en.default.json ←英語のテキストの登録用
meta-tags.liquidには、
'meta.◯◯◯' | t、のような記述があります。
↓ 例えば92行目
elsif request.page_type == 'cart' or request.path contains '/cart'
assign meta_description = 'meta.cart_description' | t
requestでcartページに適用させたい場合の状況の記述です。cart_descriptionが、キー(Key)でjsonのキー名の値(Value)を引っ張ってきます。
---
それぞれの言語のjsonファイルに"meta":のjsonを追加します。
↓日本語テキストのサンプル(ja.json)
"meta": {
"cart_description": "カートページです。",
"login_description":"ログインページです。"
}
/locales/ja.json ←日本語用のテキストの登録
},
"meta": {
"cart_description": "カートページです。",
"login_description": "ログインページです。",
"register_description": "会員登録ページです。",
"reset_password_description": "パスワードリセットページです。",
"account_description": "マイアカウントページです。",
"addresses_description": "住所管理ページです。",
"order_description": "注文履歴ページです。",
"contact_description": "お問い合わせページです。",
"news_description": "ニュース・お知らせページです。",
"feature_description": "特集記事ページです。",
"store_description": "店舗一覧ページです。",
"404_description": "お探しのページが見つかりません。",
"items_description": "商品詳細ページです。",
"all_product_description": "全商品一覧ページです。",
"new_arrivals_description": "新着商品一覧ページです。",
"all_jeans_description": "ジーンズ商品一覧ページです。",
"general_collection_description": "商品一覧ページです。",
"search_description": "検索結果ページです。",
"default_description": "公式オンラインストアです。"
}
}jsonファイルのお尻に”meta”を追記します。
/locales/en.default.json ←英語用のテキストの登録
},
"meta": {
"cart_description": "Shopping cart page.",
"login_description": "Login page.",
"register_description": "Member registration page.",
"reset_password_description": "Password reset page.",
"account_description": "My account page.",
"addresses_description": "Address management page.",
"order_description": "Order history page.",
"contact_description": "Contact page.",
"news_description": "News and announcements page.",
"feature_description": "Feature articles page.",
"store_description": "Store locations page.",
"404_description": "Page not found.",
"items_description": "Product details page.",
"all_product_description": "All products page.",
"new_arrivals_description": "New arrivals page.",
"all_jeans_description": "All jeans page.",
"general_collection_description": "Product collection page.",
"search_description": "Search results page.",
"default_description": "Official online store."
}
}英語のjsonファイルにも”meta”をお尻に追記しましょう。
以上です。
言語切り替えの対応はけっこう面倒ですね。
そう思います。。
【AI】イラストを描いてもらった
今回の記事のキャッチ画像で使わせてもらいます「Google ImageFX」で作成した画像です。誰でもgoogleアカウントでログインして使えます。
この記事にピッタリなイラストのための考えたリクエストは、
「電子空間を自在に走り廻る光る猫型ロボット。
目当ての明るい円形のソースコードに乗って飛び始めるシーン。
左に空間を浮遊する体がポリゴンの女性が驚いている表情をする。」です。


古いプログラムを探して電子空間でロボットと飛び回るイメージです。
星間旅路のメロディ
「宇宙の静けさに包まれながら、漂流する過去の音楽を捜し求め、銀河の奥底でその旋律に耳を傾ける。」
「この電波はどこの星からきたのだろうか。」
どこかで聞いたことがあるような。



