この記事の対象: Shopifyテーマを編集してオリジナルセクションを自作したい制作者
読了時間: 約12分
Shopify の Online Store 2.0 テーマでは、管理画面の「カスタマイズ」からドラッグ&ドロップでセクションを追加できます。既存セクションだけでは対応しきれないデザインが求められたとき、セクションを自作すれば、クライアント自身が管理画面から画像やテキストを差し替えられる仕組みを作れます。この記事では、sections/ フォルダにファイルを置き、{% schema %} で設定項目を定義し、カスタマイズ画面に表示するまでの手順をコード付きで解説します。
セクション自作の前提と準備

対応テーマの確認
セクションの自作は Online Store 2.0 対応テーマが前提です。2021年以降に公開された公式テーマ(Dawn など)はすべて対応しています。テーマが対応しているかどうかは、テーマのルートに templates/ フォルダがあり、中身が .json ファイルになっていることで判断できます。.liquid ファイルしかない場合は旧形式のテーマです。
開発環境
セクションファイルの編集には、次の2つの方法があります。
| 方法 | 向いているケース |
|---|---|
| Shopify管理画面 → 「テーマ」→「コードを編集」 | ファイル1〜2個の小規模な追加 |
| Shopify CLI でローカル開発 | 複数ファイルの編集、Git管理したい場合 |
Shopify CLI を使う場合は、ターミナルで shopify theme dev を実行すると、ローカルの変更がリアルタイムでプレビューされます。
shopify theme dev --store your-store-name.myshopify.com
your-store-name の部分を自分のストアのサブドメインに書き換えてください。
schemaの基本構成とセクションファイルの作り方

この流れを一つずつ見ていきます。
セクションファイルの配置場所
セクションファイルは、テーマの sections/ フォルダ直下に .liquid 拡張子で配置します。
テーマルート/
├── sections/
│ ├── custom-hero.liquid ← 今回作るファイル
│ ├── header.liquid
│ └── footer.liquid
└── templates/
ファイル名がそのままセクションの識別子になります。ハイフン区切りの英小文字で命名してください。
最小構成のセクションを作る
まず、もっともシンプルなセクションを作って動作を確認します。以下のコードを sections/custom-hero.liquid として保存してください。
<section class="custom-hero">
<h2>{{ section.settings.heading }}</h2>
<p>{{ section.settings.subheading }}</p>
</section>
{% schema %}
{
"name": "カスタムヒーロー",
"settings": [
{
"type": "text",
"id": "heading",
"label": "見出し",
"default": "ここに見出しが入ります"
},
{
"type": "text",
"id": "subheading",
"label": "サブ見出し",
"default": "補足テキストを入力してください"
}
],
"presets": [
{
"name": "カスタムヒーロー"
}
]
}
{% endschema %}
{% schema %} の中身はすべて JSON です。Liquid の構文は使えません。ポイントは3つあります。
name: カスタマイズ画面のサイドバーに表示されるセクション名settings: 管理画面に表示する入力フィールドの定義(配列)presets: これを書くと「セクションを追加」ボタンから選択できるようになる
presets を書き忘れると、カスタマイズ画面の追加一覧にセクションが出てこないので注意してください。
保存したら、管理画面で「オンラインストア」→「カスタマイズ」を開き、ページ内の「セクションを追加」をクリックします。一覧に「カスタムヒーロー」が表示されていれば成功です。
settingsの型と使い分け

settings 配列に定義するオブジェクトの type を変えると、管理画面に表示されるフィールドが変わります。ここでは実務でよく使う4つの型を紹介します。
text — テキスト入力
1行のテキスト入力欄です。見出しやボタンラベルなど、短いテキストに使います。
{
"type": "text",
"id": "button_label",
"label": "ボタンのラベル",
"default": "詳しく見る"
}
Liquid 側では {{ section.settings.button_label }} で出力します。複数行のテキストが必要なら、type を "richtext" または "textarea" に変えてください。richtext は太字やリンクを含む HTML を返し、textarea はプレーンテキストを返します。
image_picker — 画像選択
管理画面から画像をアップロード・選択できるフィールドです。
{
"type": "image_picker",
"id": "hero_image",
"label": "ヒーロー画像"
}
Liquid 側では image_url フィルターを通してURLを取得します。width パラメータで画像の横幅を指定できます。
{% if section.settings.hero_image %}
<img
src="{{ section.settings.hero_image | image_url: width: 1200 }}"
alt="{{ section.settings.hero_image.alt | escape }}"
width="1200"
height="{{ 1200 | divided_by: section.settings.hero_image.aspect_ratio | round }}"
loading="lazy"
>
{% endif %}
画像が未設定のケースを {% if %} で囲むのを忘れないでください。未設定のまま image_url を呼ぶとエラーになります。画像の最適化についてはWeb画像の最適化ガイド|AVIF・WebP対応と軽量化テクニックも参考にしてください。
range — スライダー
数値をスライダーで入力させるフィールドです。余白やカラム数など、数値で調整する項目に向いています。
{
"type": "range",
"id": "padding_top",
"label": "上の余白(px)",
"min": 0,
"max": 120,
"step": 4,
"default": 40,
"unit": "px"
}
min / max / step はすべて必須です。Liquid 側ではインラインスタイルとして出力するのが一般的です。
<section style="padding-top: {{ section.settings.padding_top }}px;">
color — カラーピッカー
管理画面にカラーピッカーを表示します。戻り値は #ff5500 のような16進数カラーコードです。
{
"type": "color",
"id": "bg_color",
"label": "背景色",
"default": "#ffffff"
}
<section style="background-color: {{ section.settings.bg_color }};">
色の設計をサイト全体で統一したい場合は、CSS変数(カスタムプロパティ)の実践的な使い方の手法と組み合わせると管理しやすくなります。
そのほかよく使う型
| type | 用途 | 戻り値 |
|---|---|---|
url |
リンク先の入力 | URL文字列 |
select |
ドロップダウン選択 | 選択肢の value 文字列 |
checkbox |
ON/OFF の切り替え | true / false |
video |
Shopifyにアップロードした動画 | video オブジェクト |
全型の一覧は Shopify公式ドキュメントの Input settings に記載されています。
blocksで繰り返し要素を作る

「特徴カード」「スタッフ紹介」「料金プラン」のように、同じ構造の要素をクライアントが好きな数だけ追加・並べ替えたい場面では、blocks を使います。
blocksの基本構造
{% schema %} の中に blocks 配列を追加します。各ブロックは type と name、そして独自の settings を持ちます。
"blocks": [
{
"type": "feature_card",
"name": "特徴カード",
"settings": [
{
"type": "text",
"id": "title",
"label": "カードの見出し",
"default": "特徴"
}
]
}
]
Liquid 側では section.blocks をループして出力します。
{% for block in section.blocks %}
<div {{ block.shopify_attributes }}>
<h3>{{ block.settings.title }}</h3>
</div>
{% endfor %}
{{ block.shopify_attributes }} は、カスタマイズ画面でブロックをクリックしたときにハイライト表示するための属性です。省略しても動きますが、編集体験が悪くなるので必ず付けてください。
実装例:特徴カードセクションの全コード
ここまでの要素を組み合わせた実用的なセクションの全コードです。sections/feature-cards.liquid として保存してください。
{{ 'feature-cards.css' | asset_url | stylesheet_tag }}
<section
class="feature-cards"
style="
padding-top: {{ section.settings.padding_top }}px;
padding-bottom: {{ section.settings.padding_bottom }}px;
background-color: {{ section.settings.bg_color }};
"
>
<div class="feature-cards__inner">
{% if section.settings.heading != blank %}
<h2 class="feature-cards__heading">{{ section.settings.heading }}</h2>
{% endif %}
{% if section.blocks.size > 0 %}
<div class="feature-cards__grid">
{% for block in section.blocks %}
<div class="feature-cards__item" {{ block.shopify_attributes }}>
{% if block.settings.image %}
<img
class="feature-cards__image"
src="{{ block.settings.image | image_url: width: 600 }}"
alt="{{ block.settings.image.alt | escape }}"
width="600"
height="{{ 600 | divided_by: block.settings.image.aspect_ratio | round }}"
loading="lazy"
>
{% endif %}
<h3 class="feature-cards__title">{{ block.settings.title }}</h3>
<p class="feature-cards__text">{{ block.settings.description }}</p>
</div>
{% endfor %}
</div>
{% endif %}
</div>
</section>
{% schema %}
{
"name": "特徴カード",
"settings": [
{
"type": "text",
"id": "heading",
"label": "セクション見出し",
"default": "私たちの強み"
},
{
"type": "color",
"id": "bg_color",
"label": "背景色",
"default": "#f8f8f8"
},
{
"type": "range",
"id": "padding_top",
"label": "上の余白",
"min": 0,
"max": 120,
"step": 4,
"default": 60,
"unit": "px"
},
{
"type": "range",
"id": "padding_bottom",
"label": "下の余白",
"min": 0,
"max": 120,
"step": 4,
"default": 60,
"unit": "px"
}
],
"blocks": [
{
"type": "card",
"name": "カード",
"settings": [
{
"type": "image_picker",
"id": "image",
"label": "画像"
},
{
"type": "text",
"id": "title",
"label": "見出し",
"default": "特徴のタイトル"
},
{
"type": "textarea",
"id": "description",
"label": "説明文",
"default": "ここに説明文が入ります。"
}
]
}
],
"max_blocks": 6,
"presets": [
{
"name": "特徴カード",
"blocks": [
{ "type": "card" },
{ "type": "card" },
{ "type": "card" }
]
}
]
}
{% endschema %}
max_blocks を指定すると、追加できるブロック数に上限を設けられます。レイアウトが崩れる数(この例では7個以上でグリッドが不自然になる)を防げます。
presets の中に blocks を書くと、セクション追加時にデフォルトで3つのカードが入った状態になります。
CSSファイル
上のセクションが読み込んでいる CSS です。assets/feature-cards.css として保存してください。
.feature-cards__inner {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.feature-cards__heading {
font-size: 1.75rem;
text-align: center;
margin-bottom: 2.5rem;
}
.feature-cards__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.feature-cards__item {
background: #fff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}
.feature-cards__image {
width: 100%;
height: auto;
display: block;
}
.feature-cards__title {
font-size: 1.125rem;
padding: 20px 20px 8px;
}
.feature-cards__text {
font-size: 0.9375rem;
padding: 0 20px 20px;
line-height: 1.7;
color: #555;
}
@media (max-width: 768px) {
.feature-cards__grid {
grid-template-columns: 1fr;
}
}
コンテンツ幅の max-width: 1200px は一例です。サイト全体のレイアウトと合わせて調整してください。幅の設計指針はWebデザインのコンテンツ幅|推奨値と設定の考え方にまとめています。
CSS Grid を使ったレスポンシブの組み方をもっと知りたい場合は、CSS Gridレイアウトの実践パターン集が参考になります。
複数タイプのブロックを1つのセクションに混在させる

実務では「テキストブロック」「画像ブロック」「ボタンブロック」のように、異なる種類の要素を1つのセクション内で自由に組み合わせたい場面があります。blocks に複数の type を定義し、Liquid 側で block.type を見て出力を分岐させます。
{% for block in section.blocks %}
{% case block.type %}
{% when 'heading' %}
<h2 {{ block.shopify_attributes }}>{{ block.settings.text }}</h2>
{% when 'text' %}
<div class="rich-text" {{ block.shopify_attributes }}>
{{ block.settings.body }}
</div>
{% when 'button' %}
<a
href="{{ block.settings.url }}"
class="btn"
{{ block.shopify_attributes }}
>
{{ block.settings.label }}
</a>
{% endcase %}
{% endfor %}
対応する schema の blocks は次のようになります。
"blocks": [
{
"type": "heading",
"name": "見出し",
"settings": [
{ "type": "text", "id": "text", "label": "見出しテキスト", "default": "見出し" }
]
},
{
"type": "text",
"name": "テキスト",
"settings": [
{ "type": "richtext", "id": "body", "label": "本文", "default": "<p>テキストを入力</p>" }
]
},
{
"type": "button",
"name": "ボタン",
"settings": [
{ "type": "text", "id": "label", "label": "ボタンラベル", "default": "ボタン" },
{ "type": "url", "id": "url", "label": "リンク先" }
]
}
]
管理画面では「ブロックを追加」をクリックしたときに「見出し」「テキスト」「ボタン」の3種類から選べるようになります。追加した順番がそのまま表示順になり、ドラッグで並べ替えも可能です。
Shopify でコーポレートサイトとECを兼用する構成では、こうした自由度の高いセクションがトップページの構築に特に役立ちます。Shopifyでコーポレートサイト・EC兼用|分けない選択肢も合わせて読んでみてください。
うまくいかないとき

セクション開発で遭遇しやすいトラブルと、その対処法をまとめます。
セクションが「セクションを追加」の一覧に出てこない
{% schema %} の中に presets が定義されているか確認してください。presets が空配列 [] でも、存在しないと一覧に表示されません。
"presets": [
{
"name": "セクション名"
}
]
schema の JSON がパースエラーになる
{% schema %} の中身は厳密な JSON です。よくある原因は次の3つです。
- 最後の要素の後ろにカンマがある(トレイリングカンマ)
- 文字列をダブルクォートではなくシングルクォートで囲んでいる
- コメント(
//や/* */)を書いている
JSON はコメントを許容しません。説明を残したい場合は {% schema %} の外に Liquid コメント {% comment %}...{% endcomment %} で書いてください。
設定を変更しても表示に反映されない
ブラウザのキャッシュが原因であることが多いです。Shopify CLI の shopify theme dev を使っている場合は、ターミナルを確認してエラーが出ていないかも見てください。Liquid の変数名(section.settings.xxxx の xxxx)と schema 内の id が一致しているかも要チェックです。
画像が表示されない
image_picker の値はそのままでは URL になりません。| image_url: width: 数値 フィルターを通す必要があります。
<!-- NG: URLが出力されない -->
<img src="{{ section.settings.hero_image }}">
<!-- OK -->
<img src="{{ section.settings.hero_image | image_url: width: 800 }}">
ブロックを追加できない / 上限に達したと表示される
max_blocks の値を確認してください。指定を省略した場合、デフォルトの上限は16個です。
よくある質問

Shopifyのセクションとテンプレートは何が違いますか?
テンプレートはページ全体の構成を定義する枠組みで、templates/ フォルダに配置します。セクションはテンプレートの中に配置するパーツ単位のモジュールで、sections/ フォルダに配置します。Online Store 2.0 では、テンプレート(JSON)がどのセクションをどの順番で表示するかを記述し、セクション側が実際のHTMLを出力する構造です。
schemaのsettingsはいくつまで定義できますか?
技術的な上限はありませんが、項目が多すぎると管理画面のサイドバーが長くなり、クライアントが設定に迷う原因になります。目安として、1セクションあたり多くても20項目前後にとどめるのが実用的です。項目が増える場合は header タイプのフィールドでグループ分けすると視認性が上がります。
他のテーマにセクションを移植できますか?
sections/ の .liquid ファイルと、assets/ の CSS/JS ファイルをコピーすれば基本的に動きます。ただし、テーマ固有の CSS クラスやグローバル変数に依存している部分は修正が必要です。移植前にセクション内で {{ settings.xxxxx }}(テーマ全体の設定)を参照している箇所がないか検索してください。section.settings ではなく settings だけの変数はテーマグローバルの値を参照しているため、移植先に同じ設定がないとエラーになります。
セクション内にJavaScriptを書いてもよいですか?
{% schema %} の外であれば <script> タグで JavaScript を書けます。セクションが複数回配置される可能性があるため、document.getElementById ではなく {{ section.id }} を使ってスコープを限定するのがコツです。
<div id="section-{{ section.id }}">
<!-- 中身 -->
</div>
<script>
(function() {
const container = document.getElementById('section-{{ section.id }}');
// このセクション内だけを対象にした処理を書く
})();
</script>
まとめ
Shopify でオリジナルセクションを作る手順を振り返ります。
sections/フォルダに.liquidファイルを作成する{% schema %}でname・settings・presetsを JSON で定義するsettingsの型(text/image_picker/range/colorなど)を用途に合わせて使い分ける- 繰り返し要素は
blocksで定義し、Liquid 側でsection.blocksをループする - 複数種類のブロックは
block.typeで{% case %}分岐する
schema の書き方さえ覚えれば、管理画面から柔軟に編集できるセクションを何パターンでも作れます。まずは今回の特徴カードセクションをそのまま動かしてみて、settings の型を入れ替えたり、ブロックの構造を変えたりしながら自分のプロジェクトに合わせてカスタマイズしてみてください。
