---
title: "Shopify Liquidとは？構文・テーマ構造とShopify CLIでの開発手順【2026年11月】"
url: "https://www.issoh.co.jp/tech/details/12315/"
published: 2026-06-01
updated: 2026-11-13
categories: ["CMS"]
publisher: "株式会社一創"
---

# Shopify Liquidとは？構文・テーマ構造とShopify CLIでの開発手順【2026年11月】

Shopify Liquidは、Shopifyのテーマを書くためのテンプレート言語です。`.liquid`ファイルにHTMLと一緒に書き、`{{ }}`で商品名や価格を出力し、`{% %}`で条件分岐や繰り返しを書きます。ShopifyのサーバーがストアのデータでHTMLを組み立てて返すため、ブラウザに届くのは普通のHTMLです。この記事では、構文の書き方と癖、オープンソース版Liquidとの違い、テーマの構造、Shopify CLIを使った開発とチェックの手順までを、2026年11月時点の版で確かめた内容で解説します。

## まとめ：Shopify Liquidテーマ開発の要点

- Liquidは**オブジェクト（`{{ }}`）・タグ（`{% %}`）・フィルター（`|`）**の3要素で書く。偽になるのは`nil`と`false`だけで、空文字も`0`も真になる。空かどうかは`blank`と比べる。
- Liquid自体はオープンソースだが、`money`や`{% section %}`はShopify版にしか無い。テーマのコードはOSS版の処理系では再現できない。
- 2026年1月13日から、Shopifyはすべてのテーマに厳格な構文解析を適用している。`{% assign x = false or true %}`や`render`の引数へのフィルターは構文エラーになる。
- 開発はShopify CLI（2026年11月時点で5.0.1・Node.js 22.12以上）の`shopify theme dev`で`127.0.0.1:9292`にプレビューを立てて進める。`theme init`の既定の雛形Skeletonは開発者プレビューのタグを使うので、通常のストアではHorizonかDawnを指定する。
- Theme Checkはerrorがあれば終了コード1を返す。CLI 5.0で`-o json`の出力形式が変わったので、4.x向けに書いたCIのスクリプトは直す必要がある。
- テーマエディタとアプリで運用するストアはLiquidテーマで足りる。Hydrogenは2026-10版でReact以外のフレームワークにも対応したが、選ぶ条件は「テーマの枠に収まらないUIを継続して開発できるか」のまま。

以下、Liquidの位置づけ、構文、厳格な構文解析、テーマ構造、開発環境、実装例、品質チェック、表示速度、Hydrogenとの選び分けの順に解説します。

## Liquidとは：Shopifyが公開するテンプレート言語とShopify版の違い

Liquidは、Shopifyが作りオープンソースで公開しているテンプレート言語です。商品ページのテンプレートを1つ書けば、商品ごとに名前や価格が入れ替わったページが生成されます。変数や条件分岐はありますが、汎用のプログラミング言語ではなく、データを表示するための言語です。

### オープンソース版LiquidとShopifyテーマのLiquidの違い

Liquidの処理系は複数あり、同じ「Liquid」でも使えるタグとフィルターが違います。[shopify.devのLiquid reference](https://shopify.dev/docs/api/liquid)は、オープンソース版を拡張し、Shopifyのストアに固有のタグ・フィルター・オブジェクトを加えたものだと説明しています。

| 処理系              | 2026年11月時点の版        | 主な用途          |
| ---------------- | ------------------- | ------------- |
| Liquid（Ruby gem） | 5.14.0（2026-09-17）  | OSS本体・Rubyアプリ |
| Jekyll           | 4.4.1（Liquid 4系に依存） | 静的サイト生成       |
| LiquidJS         | 10.30.1（2026-10-28） | Node.js・ブラウザ  |
| Shopify版         | 版番号なし（サーバー側）        | テーマ・テーマアプリ拡張  |

違いを確かめるため、Ruby gemのLiquid 5.14.0でShopifyのテーマにありがちな2行を動かしました。`{{ 1980 | money }}`は、既定ではエラーにならず`1980`がそのまま出力され、`strict_filters: true`を付けると`Liquid::UndefinedFilter`（undefined filter money）になりました。`{% section "header" %}`は「Unknown tag ‘section’」の構文エラーです。

つまり、OSS版で通ったからといってShopifyで同じ表示になるとは限らず、その逆も同じです。JekyllやLiquidJSの解説記事にある書き方を、Shopifyのテーマに持ち込むときはshopify.devのリファレンスで存在を確かめてください。テーマのコードを手元で動かすなら、OSS版ではなく後述のShopify CLIの`shopify theme dev`を使います。

### テーマ以外でLiquidを書く場所：通知メール・Flow・カスタムLiquid

Shopifyでは、テーマ以外にも通知メールのテンプレート、[Shopify Flow](/tech/details/18949/)、Order Printer、納品書（Packing slip）のテンプレートでLiquidを書きます。shopify.devは、これらは**少しずつ違う版のLiquid**で、Liquid referenceの対象外だと明記しています。通知メールで使える変数はShopifyヘルプセンターの変数一覧で引き、テーマ用のオブジェクトが使える前提で書かないでください。

テーマの中でも、コードエディタを開かずにテーマエディタの「カスタムLiquid」セクションやブロックへ直接Liquidを書けます。メタフィールドの表示を1か所だけ足す程度ならこちらで済みます。カスタムLiquidやカスタムCSSで直せる範囲は[Shopifyテーマのカスタマイズ手順：テーマエディタ・カスタムCSS・コード編集の範囲と更新対策](/tech/details/18945/)で解説しています。

## Shopify Liquidの構文：オブジェクト・タグ・フィルター

| 要素     | 記法      | 例                                     | 役割                |
| ------ | ------- | ------------------------------------- | ----------------- |
| オブジェクト | `{{ }}` | `{{ product.title }}`                 | データを出力            |
| タグ     | `{% %}` | `{% if %}` `{% for %}` `{% render %}` | 条件分岐・繰り返し・部品の読み込み |
| フィルター  | `\|`    | `{{ product.price \| money }}`        | 出力する値の加工          |

商品ページで在庫の有無により表示を切り替える例です。`{%-`と`-%}`のようにハイフンを付けると、タグの前後の空白と改行が出力から取り除かれます。Liquid 5.14.0で`<p>`の中に`if`を改行付きで書くと、ハイフン無しでは`<p>`の後に空行が2つ残り、ハイフン付きでは`<p>X</p>`と1行に詰まりました。

```
{%- if product.available -%}
  <p>{{ product.title | escape }}：{{ product.price | money }}</p>
{%- else -%}
  <p>{{ product.title | escape }}は現在売り切れです</p>
{%- endif -%}
```

### 変数の作成：assign・capture・liquidタグ

変数は`assign`で値を、`capture`で開始タグと終了タグの間に出力した文字列を代入します。タグが何行も続くときは`{% liquid %}`で囲むと、各行の`{% %}`を省けます。`liquid`タグの中では1行に1タグを書き、出力には`echo`を使います。

```
{% assign sale_label = 'セール中' %}
{% capture greeting %}{{ customer.first_name }}さん、こんにちは{% endcapture %}

{% liquid
  assign tags = 'new,sale,limited' | split: ','
  for tag in tags
    echo tag | upcase
  endfor
%}
```

`capture`は文字列を組み立ててから1回で出力したいとき、たとえば`alt`属性や`data-`属性の値を条件で組み替えるときに使います。Liquid 5.14.0で上の`liquid`タグを実行すると`NEWSALELIMITED`と出力されます。

### 条件分岐と繰り返し：if・unless・case・for

条件分岐は`if`・`elsif`・`else`、条件を反転する`unless`、値で分ける`case`・`when`の3通りです。繰り返しの`for`には`limit`（件数）・`offset`（開始位置）・`reversed`（逆順）を付けられ、`(1..5)`のような範囲も回せます。ループ内では`forloop.index`（1始まりの回数）や`forloop.last`（最後の回か）が使えます。

```
{% for i in (1..5) offset: 1 limit: 3 %}
  {{- forloop.index }}:{{ i }}{% unless forloop.last %},{% endunless -%}
{% endfor %}
{%- comment -%} 出力: 1:2,2:3,3:4 {%- endcomment -%}
```

`for`は1ページあたり50回で打ち切られます。50件を超える配列を全件たどるなら`{% paginate %}`で分割します（1ページ1〜250件、たどれるのは25,000件目まで）。

### 真偽値と演算子の癖：空文字はtrue・演算子は右から評価

Liquidで偽になるのは`nil`と`false`だけです。空文字・`0`・空の配列はすべて真として扱われます。設定項目が未入力かどうかを`{% if settings.title %}`で判定すると、空文字が入っていても真になり、空の見出しタグが出力されます。存在しないハンドルで引いたオブジェクト（EmptyDrop）も真になるため、こちらは`empty`と比べます。

```
{%- comment -%} 誤り：空文字でも真になる {%- endcomment -%}
{% if section.settings.heading %}<h2>{{ section.settings.heading }}</h2>{% endif %}

{%- comment -%} 正しい：blankと比べる {%- endcomment -%}
{% if section.settings.heading != blank %}<h2>{{ section.settings.heading }}</h2>{% endif %}
```

もう1つの癖が演算子の評価順です。`and`と`or`を混ぜると右から順に評価され、括弧で順序を変えることもできません。`{% if true or false and false %}`は、右から`false and false`を先に評価するため真になります（Liquid 5.14.0で確認）。左から読むと偽になる式なので、3つ以上の条件は`if`を入れ子にして書く方が読み違えません。

### 主要オブジェクトと使えるテンプレートの範囲

オブジェクトの参照方法は3通りあります。どのLiquidファイルからでも使える**グローバルオブジェクト**、特定のテンプレートとそのセクション・ブロックの中でだけ使える**テンプレート固有のオブジェクト**、ほかのオブジェクトのプロパティとして返る**親経由のオブジェクト**です。

| オブジェクト                   | 参照できる場所             | よく使う値                      |
| ------------------------ | ------------------- | -------------------------- |
| `shop` `settings` `cart` | どこでも（グローバル）         | ストア名・テーマ設定・カート             |
| `product`                | 商品テンプレート            | `title` `price` `variants` |
| `collection`             | コレクションテンプレート        | `products` `filters`       |
| `article`                | 親の`blog`経由・記事テンプレート | `title` `content`          |

トップページのセクションに`{{ product.title }}`と書いても何も出ないのは、`product`が商品テンプレートでしか値を持たないためです。トップページで特定の商品を出すなら、セクションの設定に`product`型の項目を作ってマーチャントに選ばせるか、`all_products['handle']`で引きます。どのテンプレートで使えるかは、各オブジェクトのリファレンス末尾の「Templates using」に載っています。

### Liquidの制約とJavaScript・アプリへの処理分担

- **外部APIを呼べない**：HTTPリクエストを送るタグは無い。外部の口コミや在庫は、JavaScriptかアプリ側で取得する。
- **関数を定義できない**：処理の共通化はsnippetを`{% render %}`で読み込んで行う。snippetの外で作成したローカル変数は直接参照できないので、必要な値は引数で渡す。グローバルオブジェクトや、呼び出し位置で利用できるproduct・sectionなどのオブジェクトは参照できる。
- **`{% include %}`は非推奨**：公式に非推奨（Deprecated）とされている。古いテーマに残っていたら、外側の変数への依存とsnippet内の代入を確認し、必要な値を引数で渡す形に直してから`{% render %}`へ置き換える。

## 2026年1月から適用された厳格なLiquid構文解析

Shopifyは[2026年1月13日から、すべてのテーマに厳格な構文解析を適用](https://shopify.dev/changelog/liquid-is-getting-faster-and-ready-to-evolve)しています。以前の構文解析は、正しそうに見えるがLiquidが対応していない書き方を受け付け、誤った結果で評価していました。基準を満たさないファイルはShopifyが自動で書き換え、変更内容を説明するコメントを残します。テーマストアとアプリストアへの新規申請では、すでに厳格な構文解析を通るコードが必須です。

移行ガイドが代表例に挙げている2つの書き方を、Liquid 5.14.0の各モードで実行した結果です。

| 書き方                                          | 従来（lax）       | strict | strict2 |
| -------------------------------------------- | ------------- | ------ | ------- |
| `{% assign x = false or true %}`             | エラーなし・xはfalse | 構文エラー  | 構文エラー   |
| `{% render 'image', alt: title \| escape %}` | エラーなし         | エラーなし  | 構文エラー   |

1行目は、従来の解析だと`x`が`false`になり、続く`{% if x %}`の中身が黙って表示されなくなります。エラーが出ないぶん気付きにくい不具合で、厳格な解析ではこれが構文エラーとして表に出ます。直し方は、論理式を`assign`せずに`if`の条件へ直接書くことです。`render`の引数にフィルターを使っていたら、先に`assign`で変数に入れてから渡します。

```
{%- comment -%} 修正前：構文エラー {%- endcomment -%}
{% render 'image', image: image, alt: image.alt | escape %}

{%- comment -%} 修正後 {%- endcomment -%}
{% assign alt_text = image.alt | escape %}
{% render 'image', image: image, alt: alt_text %}
```

自動書き換えに任せず、手元で先に見つけたい場合はTheme Checkを使います。Shopify CLI 5.0.1の`shopify theme check`に上の2行を含むsnippetを渡すと、1行目はLiquidHTMLSyntaxError、`render`の行はUnsupportedFilterArgumentsとLiquidSyntaxErrorのerrorになり、終了コードは1でした。古いテーマを引き継いだら、改修の前に一度通しておくと安全です。

## Online Store 2.0のテーマ構造とディレクトリの役割

現在のShopifyテーマは、2021年に発表されたOnline Store 2.0の構造が前提です。JSONテンプレートによって、ほぼすべてのページでマーチャントがテーマエディタからセクションを追加・並べ替えできます。アプリブロックやダイナミックソースの多くはJSONテンプレートが前提です。

| ディレクトリ    | 置くもの                     | 押さえる点                            |
| --------- | ------------------------ | -------------------------------- |
| assets    | 画像・CSS・JavaScript        | `.css.liquid`でsettingsとフィルターが使える |
| blocks    | テーマブロック                  | 複数のセクションで再利用できる                  |
| config    | settings\_schema.json ほか | テーマ設定の定義と保存値                     |
| layout    | theme.liquid             | アップロードに必須な唯一のファイル                |
| locales   | 翻訳用JSON                  | ストアとエディタの多言語化                    |
| sections  | セクション・セクショングループ          | ヘッダー・フッターはグループで管理                |
| snippets  | 再利用する部品                  | テーマエディタには表示されない                  |
| templates | JSON・Liquidテンプレート        | サブフォルダはcustomersとmetaobjectのみ    |

一覧にないサブディレクトリはサポートされません。独自に`components/`のようなフォルダを切る設計は、Shopifyのテーマとしては通りません。

### JSONテンプレートとLiquidテンプレートの使い分け

JSONテンプレートは、表示するセクションとその設定値を`sections`と`order`に並べたデータファイルです。[上限は1テンプレートにつきセクション25個、各セクションのブロック50個](https://shopify.dev/docs/storefronts/themes/architecture/templates/json-templates)で、1テーマに置けるJSONテンプレートは1,000個までです。拡張子を除くファイル名が同じテンプレートをJSONとLiquidの両方で持つことはできず、`product.liquid`があると`product.json`は作れません。

判断基準は、マーチャントがそのページをエディタで組み替えるかどうかです。組み替えるページはJSONテンプレートにします。Liquidテンプレートに`{% section %}`で直接書いたセクションは静的に描画され、マーチャントは削除も並べ替えもできず、アプリブロックも置けません。

### セクションブロックとテーマブロックの違い

ブロックは公式に3種類あり、テーマ側で定義するのがセクションブロックとテーマブロック、アプリが提供するのがアプリブロックです。**セクションブロック**はセクションの`{% schema %}`内で定義し、そのセクションの中でしか使えません。**テーマブロック**は`blocks/`ディレクトリにLiquidファイルとして置き、複数のセクションで再利用でき、ブロックの中にブロックを入れ子にできます。1テーマに置けるテーマブロックは300個までで、どこからも参照されていないファイルも数に入ります。

セクションでテーマブロックを受け付けるには、スキーマの`blocks`に`{"type": "@theme"}`を書き、本文で`{% content_for 'blocks' %}`を呼びます。1つのセクションで両方の方式は混ぜられないため、既存のセクションブロックを残したまま一部だけテーマブロックに移す段階移行は、セクション単位で行います。

### 開発者プレビューの`{% block %}`・`{% partial %}`タグとSkeletonテーマ

2026年7月21日、Shopifyは開発者プレビュー「Liquid July ’26」として、テーマブロックをテンプレートから直接呼び出す`{% block %}`タグと、ページの一部だけをJavaScriptから再描画できる`{% partial %}`タグを[発表](https://shopify.dev/changelog/developer-preview-liquid-block-and-partial-tags)しました。`{% block %}`は`{% render %}`と同じように、ブロック名と名前付き引数を渡し、開始タグと終了タグの間に本文を書けます。ブロック側では本文を`{{ content }}`で出力します。

`shopify theme init`の雛形であるSkeletonテーマは、2026年10月1日のコミット（リリース候補rc-v2.0.0の取り込み）でこの書き方に移っています。`sections/`ディレクトリがなく、テンプレートは12本すべてが`.liquid`で、ページをブロックの入れ子だけで組みます。

```
<body>
  {% block 'container', tag: 'div' %}
    {% block 'header' -%}{%- endblock %}
  {% endblock %}

  <main>
    {{ content_for_layout }}
  </main>
</body>
```

試すには、開発ストアを新規作成するときに機能プレビュー「Liquid July ’26 changes」を選びます。2026年11月13日時点でも[機能プレビューの一覧](https://shopify.dev/docs/apps/build/stores/feature-previews)に載ったままで、変更履歴に正式提供の告知はありません。既存のセクション・テーマ設定・JSONテンプレートも引き続き動きます。稼働中のストアの改修には使わず、検証用の開発ストアで試す段階です。DawnとHorizonはどちらもテンプレートがJSONのままです。

## Shopify CLIでテーマ開発環境を作る手順

管理画面のコードエディタにもTimeline（ファイル単位の差分確認と復元）がありますが、複数ファイルの変更をまとめてレビューする仕組みはありません。チームで開発する案件では、Shopify CLIで取得したテーマをGitで管理します。

### Shopify CLIのインストール要件

[Shopify CLIの要件](https://shopify.dev/docs/api/shopify-cli)は、Node.js 22.12以上、npm・Yarn 1.x・pnpmのいずれか、Git 2.28.0以上です。npm上の最新版は2026年11月4日公開の5.0.1でした。macOSならHomebrewでも入れられます。

```
npm install -g @shopify/cli@latest
shopify version

# Homebrewの場合
brew tap shopify/shopify
brew install shopify-cli
```

4.0以降のShopify CLIは自動で更新されますが、CI上・プロジェクトのローカルに入れた場合と、メジャーバージョンへの更新は対象外です。4.9.0から5.0へは自動で上がらず、起動時に「This is a major version」と確認を促す表示が出ます。

ストアへの接続には、テーマ権限を持つコラボレーターアカウントかスタッフアカウント、またはストアのオーナーアカウントでログインします。CIのように対話ログインできない環境では、Theme Accessアプリで発行したパスワードを`--password`で渡します。

### theme init・dev・pushの基本の流れ

```
# 雛形を取得（通常のストア向けはHorizonかDawnを --clone-url で指定）
shopify theme init my-theme --clone-url https://github.com/Shopify/horizon.git
# shopify theme init my-theme --clone-url https://github.com/Shopify/dawn.git

# ストアのデータでローカルプレビュー（http://127.0.0.1:9292）
cd my-theme
shopify theme dev --store my-store

# 既存テーマを改修する場合は、initの代わりに空の作業フォルダで公開中テーマを取り込む
# shopify theme pull --live --store my-store

# 非公開テーマとしてアップロードし、レビューに回す
shopify theme push --unpublished --theme "staging-2026-11"
```

`--clone-url`を省くと既定のSkeletonテーマ（GitHubのmainブランチ）が入ります。前章のとおり現在のSkeletonは開発者プレビューの`{% block %}`タグでページを組んでいるため、使うのは機能プレビュー「Liquid July ’26 changes」を有効にした開発ストアに限ってください。

`shopify theme dev`は、ストアに非表示の開発用テーマを作ってローカルの変更を同期します。CSSとセクションの変更はホットリロードされ、それ以外のファイルはページ全体を再読み込みします。開発用テーマはストアのテーマ数の上限に数えられず、7日間操作がないと削除されます。`shopify auth logout`でも消えるため、関係者に見せるプレビューは`theme push --unpublished`で通常の非公開テーマとして残してください。チェックアウトのカスタマイズは`127.0.0.1:9292`ではプレビューできません。

テーマエディタでマーチャントが変更したJSONと、ローカルのJSONがぶつかることがあります。`--theme-editor-sync`を付けると同期し、衝突時の扱いは`--reconciliation-strategy`で`keep-local`・`keep-remote`・`abort`から選べます。

### 土台テーマの選び方：Skeleton・Dawn・Horizon

| テーマ      | 2026年11月時点          | ブロックの方式                    | 向く用途            |
| -------- | ------------------- | -------------------------- | --------------- |
| Skeleton | 2026-10-01更新        | テーマブロック5個・sectionsなし       | プレビュー用の開発ストアで学習 |
| Dawn     | v16.1.1（2026-11-02） | セクションブロック（sections 48ファイル） | 既存Dawn系ストアの改修   |
| Horizon  | 4.5.0               | テーマブロック95個・sections 43ファイル | 新規ストアの本格テーマ     |

数はいずれも2026年11月13日に取得した各リポジトリのコミット（[Skeleton a7a655e](https://github.com/Shopify/skeleton-theme/tree/a7a655e79b21e68316c228dc7e437b0b32550888)・[Dawn 3e9ee22](https://github.com/Shopify/dawn/tree/3e9ee2281dc40e1eda9d5fd3ca64719d0a36b47d)・[Horizon c531fd5](https://github.com/Shopify/horizon/tree/c531fd5bb8904e7f871c308b15c64a7cb0de8e20)）で数えたものです。Dawnには`blocks/`ディレクトリがなく、ブロックはすべてセクション内で定義されています。テーマブロックを前提に作るならHorizonを土台にした方が、入れ子のブロック設計をそのまま参考にできます。

Dawnを使い続ける場合は、v16.0.0で旧来の顧客アカウント用テンプレートとセクションが削除された点に注意してください。旧顧客アカウントのままのストアは、新しい顧客アカウントへ切り替えるまでv16系を公開できません。

## セクションの実装例：schema・blocks・presets

コレクションの商品を指定件数だけ並べるセクションを例に、スキーマの書き方を示します。商品カードは後述のLiquidDocの例を`snippets/product-card.liquid`として保存したものを呼んでいます。このファイルはSkeletonテーマに`sections/`を足して置き、`shopify theme check`で指摘0件になることを確かめています。

```
{%- comment -%} sections/featured-products.liquid {%- endcomment -%}
<div class="featured-products">
  {% if section.settings.heading != blank %}
    <h2>{{ section.settings.heading | escape }}</h2>
  {% endif %}
  <div class="featured-products__grid">
    {% for product in section.settings.collection.products limit: section.settings.products_to_show %}
      {% render 'product-card', product: product %}
    {% endfor %}
  </div>
  {% for block in section.blocks %}
    {% case block.type %}
      {% when '@app' %}
        {% render block %}
      {% when 'note' %}
        <div {{ block.shopify_attributes }}>{{ block.settings.text }}</div>
    {% endcase %}
  {% endfor %}
</div>

{% schema %}
{
  "name": "Featured products",
  "settings": [
    { "type": "text", "id": "heading", "label": "Heading", "default": "Featured products" },
    { "type": "collection", "id": "collection", "label": "Collection" },
    { "type": "range", "id": "products_to_show", "label": "Products to show", "min": 2, "max": 12, "step": 1, "default": 4 }
  ],
  "blocks": [
    { "type": "@app" },
    {
      "type": "note",
      "name": "Note",
      "limit": 3,
      "settings": [{ "type": "richtext", "id": "text", "label": "Text" }]
    }
  ],
  "presets": [{ "name": "Featured products" }]
}
{% endschema %}
```

- **`presets`が無いとエディタから追加できない**：プリセットの無いセクションは、JSONテンプレートやセクショングループに直接記述するか、Liquidから静的に描画する。
- **`@app`に`limit`を付けるとエラー**：アプリブロックの受け口には件数制限を書けない。制限したい自前の`note`ブロックだけに`limit: 3`を付けている。
- **`block.shopify_attributes`を出力する**：テーマエディタのJavaScript APIがブロックを識別するためのdata属性。エディタの外では何も出力されないので、本番のHTMLは汚れない。
- **固定件数の一覧は`limit`だけで書く**：`paginate`で囲むとURLの`page`パラメータに反応してしまう。理由は表示速度の章で説明する。

このセクションをページに置くJSONテンプレートは次のとおりです。`templates/page.featured.json`として保存すると、固定ページの代替テンプレートとして選べます。保存しただけでは商品は並ばないので、テーマエディタでこのテンプレートを開き、「Featured products」の「Collection」に商品を含むコレクションを設定します。

```
{
  "sections": {
    "featured": {
      "type": "featured-products",
      "settings": { "heading": "おすすめ商品", "products_to_show": 4 }
    }
  },
  "order": ["featured"]
}
```

素材や産地のように商品ごとに違う情報はメタフィールドに持たせます。テーマエディタのダイナミックソースを使えば、マーチャントがセクションの設定項目にメタフィールドを接続できるので、Liquidを書き換えずに商品ごとの表示を変えられます。

## Theme CheckとLiquidDocの実行結果

Theme Checkは、テーマのLiquidとJSONを検査するShopify公式のリンターです。以前はRuby製の単体ツールでしたが、現在はShopify CLIの`shopify theme check`とVS Code拡張のShopify Liquidに組み込まれています。以下は2026年11月13日にShopify CLI 5.0.1で実行した結果です。

### Theme Checkの検出例と終了コード

Skeletonテーマに、よくある書き方の誤りを4行だけ入れたsnippetを足して実行しました。

```
{% include 'meta-tags' %}
{% assign unused_price = product.price %}
<img src="{{ product.featured_image | image_url: width: 600 }}" alt="{{ product.title }}">
<script src="{{ 'card.js' | asset_url }}"></script>
```

| 検出されたチェック            | 重大度     | 対象                    |
| -------------------- | ------- | --------------------- |
| ImgWidthAndHeight    | error   | imgにwidth・heightが無い   |
| ParserBlockingScript | error   | scriptにdefer・asyncが無い |
| MissingAsset         | error   | assets/card.jsが存在しない  |
| DeprecatedTag        | warning | includeはrenderへ       |
| UnusedAssign         | warning | 使われない変数               |
| OrphanedSnippet      | warning | どこからも呼ばれないsnippet     |

集計は「27 files inspected with 6 total offenses found」（error 3件・warning 3件）で、手を加えていないSkeletonテーマは26ファイルで指摘0件です。終了コードは、errorがあると1、warningだけなら0です。`--fail-level warning`を付けると、warningだけでも1になります。

```
# errorでジョブを落とす（既定）
shopify theme check

# warningでも落とす・機械処理用にJSONで出す
shopify theme check --fail-level warning -o json

# 自動修正できるものを直す／設定ファイルを作る
shopify theme check --auto-correct
shopify theme check --init
```

### CLI 5.0で変わったJSON出力の形式

Shopify CLI 5.0.0は、[変更履歴](https://github.com/Shopify/cli/blob/main/packages/cli/CHANGELOG.md)でコマンド全体に型付きのJSON出力を入れたことを互換性のない変更として挙げています。同じsnippetを4.9.0と5.0.1の`-o json`で出すと、形が次のように違いました。

| 項目     | 4.9.0             | 5.0.1                       |
| ------ | ----------------- | --------------------------- |
| 最上位    | ファイルごとの配列         | 1つのオブジェクト                   |
| 指摘の一覧  | `[].offenses`     | `issues`                    |
| ファイルパス | `path`            | `filePath`                  |
| 行番号    | `start_row`（0始まり） | `startRow`（1始まり）            |
| 件数     | なし                | `errorCount` `warningCount` |

img行の行番号は4.9.0で2、5.0.1で3と出ました。`offenses`を数えてPRにコメントするようなCIのスクリプトは、5.0へ上げると空振りするか例外で止まります。新しい形式の定義は`--json-schema`で出力できます。

### LiquidDocによるrender引数の誤り検出

snippetの先頭に`{% doc %}`で引数を宣言しておくと、呼び出し側の書き間違いをTheme CheckとVS Code拡張が指摘します。宣言の書式はJSDocに似ています。

```
{% doc %}
  商品カード
  @param {product} product - 表示する商品
  @param {string} [loading] - 画像の読み込み方法（lazy または eager。省略時はimage_tagの既定）
{% enddoc %}
<div class="product-card">
  {%- if loading != blank -%}
    {{ product.featured_image | image_url: width: 600 | image_tag: loading: loading, alt: product.title }}
  {%- else -%}
    {{ product.featured_image | image_url: width: 600 | image_tag: alt: product.title }}
  {%- endif %}
  <p>{{ product.title | escape }}</p>
  <p>{{ product.price | money }}</p>
</div>
```

このsnippetを`{% render 'product-card', produt: product %}`と1文字間違えて呼ぶと、MissingRenderSnippetArguments（必須の`product`が無い）とUnrecognizedRenderSnippetArguments（未知の`produt`）の2件が出ました。どちらもwarningなので、既定の`shopify theme check`は終了コード0で通ります。引数の誤りでCIを止めたいなら`--fail-level warning`が必要です。

## 表示速度を落とさないLiquid実装

Shopifyテーマストアに出すテーマには、商品・コレクション・ホームの3ページについて、デスクトップとモバイルの両方でLighthouseのパフォーマンススコア平均60以上という基準があります。自社ストア向けのテーマにこの基準はかかりませんが、最低限の目安になります。指標の意味は[Core Web Vitalsとは：LCP・INP・CLSの基準値とweb-vitals・CrUX APIでの測り方【2026年10月】](/tech/details/18645/)で解説しています。

- **LCP画像を遅延読み込みしない**：最初の画面に入る画像に`loading="lazy"`を付けると読み込みが遅れる。`image_tag`は`loading`を渡さなければ先頭3セクションの画像をeagerで読み込むので、一律に`lazy`を渡さない。ヒーロー画像はCSSの`background-image`ではなく`img`で出す。
- **画像は`image_tag`で出す**：`image_url`と組み合わせると`srcset`と`width`・`height`が自動で付き、画像の寸法未指定によるレイアウトシフトを抑えられる。
- **scriptには`defer`**：解析を止めるscriptはTheme CheckのParserBlockingScriptでerrorになる。
- **アプリの読み込みを点検する**：描画を止めるアプリのスクリプトを外すか遅らせ、アプリブロックには`min-height`で領域を確保する。

迷いやすいのが、`for`の`limit`が取得するデータ量まで減らすかどうかです。[パフォーマンスガイド](https://shopify.dev/docs/storefronts/themes/best-practices/performance)では、`collection.products`と`collections`については`limit`だけで取得件数も絞られ、それ以外の配列には`paginate`が必要とされています。`collection.products`は`limit`を付けないと既定の50件を丸ごと取得します。

おすすめ商品の1列やカルーセルのような固定件数の一覧を`paginate`で囲むのは避けてください。`paginate`はURLの`page`パラメータに反応するため、`?page=2`のときに別の商品が出たり何も出なかったりします。`paginate`タグのリファレンスには`limit`では取得量が減らないとする記述が残っていますが、固定件数の一覧についてはパフォーマンスガイドの方に従います。

操作への反応が遅い場合はINPの問題です。[INPとは？基準値200msと3区間の見方、遅い原因の特定・改善方法](/tech/details/7543/)で原因の切り分け方を、[Lighthouse CIの使い方｜lighthouserc・assertの判定とGitHub Actions連携【@lhci/cli 0.16.0】](/tech/details/7542/)でスコアをCIで監視する方法を扱っています。

## Liquidテーマ（Pure Liquid）とHydrogenの選び分け

Liquidだけでテーマを組む構成は、Pure Liquidと呼ばれることがあります。対になるのがShopify公式のヘッドレス向けツールキットHydrogenです。[2026年10月14日に正式提供されたHydrogen 2026-10](https://shopify.dev/changelog/hydrogen-2026-10-is-now-available)は、それまでのReact Router専用の構成から、フレームワークに依存しないライブラリに変わりました。カート・バリエーション選択・アナリティクス・ログインといったShopify固有の処理をHydrogenが受け持ち、ルーティングと描画は使っているフレームワークに任せます。

公式のテンプレートはReact Router 7（Oxygenへデプロイ）とNext.js 16（Vercel Shop・Vercelへデプロイ）の2つで、ReactとVueのバインディングが用意されています。Astro・SvelteKit・SolidStartはバインディング無しでコアを直接使います。2026-04以前のHydrogenは「Legacy Hydrogen」としてドキュメントが分けられました。

| 判断軸      | Liquidテーマ       | Hydrogen 2026-10           |
| -------- | --------------- | -------------------------- |
| ページの組み替え | テーマエディタで可能      | 開発者がコードで変更                 |
| アプリブロック  | そのまま使える         | テーマの仕組みのため対象外              |
| 必要なスキル   | HTML・CSS・Liquid | React・Vueなど＋Storefront API |
| ホスティング   | Shopifyが配信      | Oxygen・Vercelなどへデプロイ       |

商品ページや特集ページをマーケティング担当がエディタで更新し、レビューや定期購入をアプリストアのアプリでまかなうストアなら、Liquidテーマを選んでください。アプリブロックはテーマの仕組みなので、Hydrogenに移ると同じ機能をAPI連携で作り直すことになります。

Hydrogenが合うのは、すでにNext.jsなどで動いているサイトに商品とカートを足したい、外部CMSの記事と商品を同じ画面で混ぜたい、といったテーマの枠に収まらない要件があり、フロントエンドの開発者を継続して確保できる場合です。2026-10版で既存のフレームワークに後から組み込めるようになり、作り直しは前提でなくなりました。

避けたいのは、表示が遅いことを理由にHydrogenへ移す判断です。遅さの原因がアプリのスクリプトなら、Hydrogenに移しても同じタグを載せる限り速くはなりません。移行を決める前に、Lighthouseでどのスクリプトが時間を使っているかを確かめてください。どちらの構成でも、Shopifyのデータを外から扱う部分は[Shopify APIとは：Admin・Storefront・Webhookの使い分けとレート制限をコードで解説](/tech/details/18947/)が前提知識になります。ヘッドレス構成全般の比較は[ヘッドレスコマースとは？仕組み・従来型ECとの違いと主要基盤の比較、導入判断【2026年10月】](/column/details/1326/)、構築の工程と費用は[Shopify構築の進め方｜工程・費用と外注範囲の線引き](/column/details/17106/)、プランごとの機能差は[Shopify Plusとは｜通常プランとの機能差と移行する売上規模の線引き](/column/details/18085/)にまとめています。テーマ開発やHydrogenでの構築を外部に任せる場合は、[一宗のECサイト制作・Shopify構築](/service/web/shopify/)でも相談を受けています。

## よくある質問

### ShopifyのLiquidの難易度は高いですか？

構文は少なく、HTMLとCSSが書ければ`{{ }}`での出力や`{% if %}`での分岐はすぐに書けます。つまずきやすいのは、空文字が真になる真偽値の扱いと、テンプレートごとに使えるオブジェクトの把握、セクションのスキーマ設計です。関数定義や外部API呼び出しはできないため、複雑な処理はJavaScriptかアプリに任せます。

### LiquidとHTMLの違いは何ですか？

HTMLはブラウザが表示する文書の形式で、LiquidはそのHTMLを組み立てるためのテンプレート言語です。`.liquid`ファイルにはHTMLとLiquidのタグを混ぜて書き、Shopifyのサーバーが商品やコレクションのデータを差し込んだ結果のHTMLをブラウザへ返します。ブラウザにLiquidのコードは届きません。

### Shopify CLIを使うには何が必要ですか？

Node.js 22.12以上、npm・Yarn 1.x・pnpmのいずれか、Git 2.28.0以上です。`npm install -g @shopify/cli@latest`で入り、2026年11月時点の最新は5.0.1です。ストアに接続するには、テーマ権限のあるコラボレーターかスタッフのアカウント、またはTheme Accessのパスワードが要ります。

### Liquidのコードはどこで編集できますか？

Shopify管理画面のテーマのコード編集画面で直接編集でき、Timelineでファイルごとの差分確認と復元もできます。Gitでの履歴管理やチームでのレビューを行う開発では、`shopify theme pull`でローカルに取り込み、`shopify theme dev`でプレビューしながら編集し、`shopify theme push`で戻す流れが基本です。

### Dawnは今も使えますか？

使えます。2026年11月2日にv16.1.1が出ており、更新は続いています。ただしv16.0.0で旧来の顧客アカウント用テンプレートが削除されたため、旧顧客アカウントのストアは新しい顧客アカウントへ切り替えてから公開してください。テーマブロックを前提にした設計を学ぶなら、Horizonの方が参考になります。

## 関連記事

- [Shopifyテーマのカスタマイズ手順：テーマエディタ・カスタムCSS・コード編集の範囲と更新対策](/tech/details/18945/)
- [Shopify APIとは：Admin・Storefront・Webhookの使い分けとレート制限をコードで解説](/tech/details/18947/)
- [Shopify構築の進め方｜工程・費用と外注範囲の線引き](/column/details/17106/)
- [ヘッドレスコマースとは？仕組み・従来型ECとの違いと主要基盤の比較、導入判断【2026年10月】](/column/details/1326/)
- [Lighthouse CIの使い方｜lighthouserc・assertの判定とGitHub Actions連携【@lhci/cli 0.16.0】](/tech/details/7542/)

---

出典: [Shopify Liquidとは？構文・テーマ構造とShopify CLIでの開発手順【2026年11月】](<https://www.issoh.co.jp/tech/details/12315/>)（株式会社一創）
