Scripts 移行期限: 2026年6月30日までに Functions へ移行を
Scripts 移行期限: 2026年6月30日までに Functions へ移行を
Scripts 移行期限: 2026年6月30日までに Functions へ移行を

2026年4月16日。昨日、4月15日はShopifyがScript Editorを完全に閉鎖した日です。すでに新しいScriptの作成や公開はできません。この期限が最も深刻に響くのが購入後ロジックです。配送先住所の変更は、編集された注文全体の30.2%を占める最大の購入後編集であり(Revize、2026年)、これらの編集を処理している既存のScriptはすべて凍結されました。実行停止は75日後の2026年6月30日に迫っています。
過去12ヶ月間、この移行を「次のスプリント」へと先送りしてきたShopify Plusデベロッパー、あるいはPlusストアを運営するパートナーエージェンシーにとって、これは重大な問題です。「できれば修正したい」レベルではなく、「7月1日の午前0時にチェックアウトがクラッシュする」問題です。ほとんどのPlusストアは長年にわたり5〜20個のScriptを蓄積しており、それらは誰が書いたかも覚えていない割引ルール、配送方法の非表示、決済ゲートウェイの制御をバックグラウンドで静かに処理しています。
このガイドは、1月に欲しかった技術的な移行マニュアルです。 単なる戦略ではなく、実際のコードに焦点を当てています。読み終える頃には、Shopify CLIを使用したFunctionの雛形生成、割引・配送カスタマイズ・決済カスタマイズのためのRustやJavaScriptロジックの記述、タグ付けされた顧客サブセットに対する安全なテスト方法、そして既存のチェックアウトを壊さずに本番環境へデプロイする方法が理解できているはずです。
ストアからScriptを排除し、Functionsを導入しましょう。

クイックアンサー:60秒で理解するScriptsからFunctionsへの移行
1段落でわかる移行概要: Shopify Scripts(Script Editor内のRubyコード、Plus限定)は、Shopify Functions(RustまたはJavaScriptで記述されたWebAssemblyモジュール、すべてのプランで利用可能)に置き換えられます。
shopify app generate extensionでFunctionを生成し、必要なカートデータを取得するrun.graphqlクエリを書き、処理(割引、配送方法の非表示など)を返すrun.rsまたはrun.jsファイルを記述します。その後、shopify app deployでデプロイし、管理画面またはGraphQLミューテーション経由で有効化します。FunctionsはコンパイルされたWASMとして5ms未満のレイテンシで実行され、すべてのプランで動作し、Shopifyが今後サポートする唯一のカスタマイズパスです。
6月30日に実際に何が起きるのか
コードに触れる前に、日付を整理しておきましょう。重要な日付は2つあります。
日付 | 発生する事象 | 必要なアクション |
|---|---|---|
2026年4月15日 (超過) | Script Editorが読み取り専用に。新規Scriptの作成および既存Scriptの編集が不可に。 | 既存のScriptは動作を継続。今すぐ移行するか、ロジックを凍結する。 |
2026年6月30日 | すべてのShopify Scriptsの実行が停止。 | この日より前に、代替となるFunctionを本番公開する必要あり。 |
この移行はオール・オア・ナッシングです。6月30日までにFunctionがデプロイされてチェックアウトが動作し続けるか、デプロイされずに影響を受けるすべてのカートが標準価格、標準配送レート、デフォルトの決済方法へと自動的に戻るかのどちらかです。中間はありません。Scriptが実行されるか停止するかの二択であり、6月30日以降は停止します。
ヒント: Shopify管理画面の
設定 → チェックアウト → カスタマイズレポートを開いてください。ストア内でアクティブなすべてのScript、その機能、および推奨される代替Functionタイプが一覧表示されています。まずはここから始めましょう。
Functions と Scripts の比較:何が変わったのか
比較項目 | Shopify Scripts(非推奨) | Shopify Functions(代替) |
|---|---|---|
言語 | Ruby DSL(Shopify専用) | Rust、JavaScript、TypeScript |
実行環境 | Shopifyインフラ上のサンドボックス化されたRuby | WebAssembly (WASM) — 5ms未満の実行速度 |
対応プラン | Plusのみ | すべてのプラン(カスタムアプリはPlusが必要、公開アプリは全プラン開放) |
エディタ | 管理画面内のScript Editor | ローカルIDE + Shopify CLI |
バージョン管理 | なし(直接編集・即時反映) | Git対応 — 完全なバージョン管理 |
テスト | チェックアウトでの手動テスト |
|
デプロイ | 管理画面で「保存」をクリック | ターミナルから |
制御対象 | ラインアイテム、配送、決済 | 割引、Cart Transform、バリデーション、配送カスタマイズ、決済カスタマイズ、注文ルーティング、フルフィルメント制約など |
アーキテクチャの転換は重要です。Scriptsは「テキストエリアでRubyを微調整する」ものでした。Functionsは「実際のアプリケーションを記述し、バージョン管理し、ローカルでテストし、CIパイプラインを通じてデプロイする」ものです。習得の難易度は上がりますが、チェックアウトロジックにおける今後の移行はこれが最後になります。Functionsは一時しのぎのScriptsとは異なり、Shopifyが長期的に提供する基盤です。
Scriptsから適切なFunctionタイプへのマッピング
現在稼働しているすべてのScriptは、対応するFunction APIにマッピングされます。以下は、移行作業において常に確認すべき対応表です。
従来のScriptタイプ | 機能概要 | 新しいFunction API | Functionターゲット |
|---|---|---|---|
Line Item Script | 特定の製品/顧客/カート条件に応じた割引適用 | Cart & Checkout Discounts API |
|
Shipping Script(割引) | カートルールに基づく送料無料または配送割引 | Cart & Checkout Discounts API |
|
Shipping Script(非表示/名称変更/並び替え) | 一定金額以上の送料無料時の特定配送法非表示、名称変更など | Delivery Customization API |
|
Payment Script | B2B顧客向けPayPalの非表示、高額注文時の代金引換非表示、並び替え | Payment Customization API |
|
カート変更Script(稀少) | 商品のバンドル、ラインアイテムの入れ替え | Cart Transform API |
|
チェックアウトブロックScript | 不適切なSKU組み合わせのカートを拒否 | Cart & Checkout Validation API |
|
10個のScriptを運用している場合、作成するFunctionは3〜5個程度に集約される傾向があります。複数のScriptは通常、分岐ロジックを整理して1つのFunctionに統合できます。

前提条件:ローカル開発環境の構築
Functionの作成を開始する前に、ローカル環境に以下の3つがインストールされていることを確認してください。ターミナルで各コマンドを実行してチェックします。
1. Node.js 18+
node --version # 18.0.0以上である必要があります
node --version # 18.0.0以上である必要があります
バージョンが古い場合は、nvmを使用するか、nodejs.orgからダウンロードしてインストールしてください。
2. Shopify CLI 3+
npm install -g @shopify/cli@latest shopify version # 3.x以上のバージョンが出力されることを確認します
npm install -g @shopify/cli@latest shopify version # 3.x以上のバージョンが出力されることを確認します
3. Rustツールチェーン(RustでFunctionを記述する場合のみ)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add wasm32-wasip1 cargo --version
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add wasm32-wasip1 cargo --version
JavaScriptでFunctionを書く場合、Rustは不要です。チームで記述言語を統一することを推奨します。両方を混在させるとメンテナンスコストが増大します。
4. 開発用ストア
パートナーダッシュボードにログインして新しい開発用ストアを作成するか、既存のストアを使用します。本番環境に適用する前に、まずこの開発ストアにFunctionをデプロイします。
最初のFunctionの作成
CLIがボイラープレートの大部分を生成します。任意のディレクトリ内で以下を実行します。
# 新しいShopifyアプリを作成(既存のアプリがある場合はスキップ) shopify app init my-checkout-functions cd my-checkout-functions # Function拡張機能を生成 shopify app generate extension
# 新しいShopifyアプリを作成(既存のアプリがある場合はスキップ) shopify app init my-checkout-functions cd my-checkout-functions # Function拡張機能を生成 shopify app generate extension
CLIプロンプトに従って選択していきます。割引Functionの場合、以下の構成を選択します。
タイプ: Function
テンプレート:
discount(またはcart_checkout_validation,delivery_customization,payment_customizationなど)言語: Rust または JavaScript
名称:
volume-discount-fnなど
これにより、以下の構成で extensions/volume-discount-fn/ が作成されます。
extensions/volume-discount-fn/ ├── shopify.extension.toml # Function設定(ターゲット、ビルド、バージョン) ├── src/ │ ├── cart_lines_discounts_generate_run.graphql # 入力クエリ │ └── cart_lines_discounts_generate_run.rs # Functionロジック ├── Cargo.toml # Rust依存関係(Rustのみ) └── README.md
extensions/volume-discount-fn/ ├── shopify.extension.toml # Function設定(ターゲット、ビルド、バージョン) ├── src/ │ ├── cart_lines_discounts_generate_run.graphql # 入力クエリ │ └── cart_lines_discounts_generate_run.rs # Functionロジック ├── Cargo.toml # Rust依存関係(Rustのみ) └── README.md
編集頻度が高いのは、.toml(設定)、.graphql(入力)、および.rs / .js(ロジック)の3つのファイルです。
チュートリアル 1:Line Item Scriptの代替(ボリュームディスカウント)
特定のコレクションがカート内に5点以上ある場合、注文小計から10%割引する従来のScriptを、Functionに移植する例を紹介します。
ステップ 1.1: 構成設定 (shopify.extension.toml)
api_version = "2026-01" [[extensions]] name = "volume-discount-fn" handle = "volume-discount-fn" type = "function" [[extensions.targeting]] target = "cart.lines.discounts.generate.run" input_query = "src/cart_lines_discounts_generate_run.graphql" export = "cart_lines_discounts_generate_run" [extensions.build] command = "cargo build --target=wasm32-wasip1 --release" path = "target/wasm32-wasip1/release/volume-discount-fn.wasm" watch = ["src/**/*.rs"]
api_version = "2026-01" [[extensions]] name = "volume-discount-fn" handle = "volume-discount-fn" type = "function" [[extensions.targeting]] target = "cart.lines.discounts.generate.run" input_query = "src/cart_lines_discounts_generate_run.graphql" export = "cart_lines_discounts_generate_run" [extensions.build] command = "cargo build --target=wasm32-wasip1 --release" path = "target/wasm32-wasip1/release/volume-discount-fn.wasm" watch = ["src/**/*.rs"]
ステップ 1.2: 入力クエリ (src/cart_lines_discounts_generate_run.graphql)
query Input { cart { lines { id quantity cost { subtotalAmount { amount } } merchandise { ... on ProductVariant { product { inAnyCollection(ids: ["gid://shopify/Collection/123456789"]) } } } } } discount { discountClasses } }
query Input { cart { lines { id quantity cost { subtotalAmount { amount } } merchandise { ... on ProductVariant { product { inAnyCollection(ids: ["gid://shopify/Collection/123456789"]) } } } } } discount { discountClasses } }
ヒント: Functionsはクエリされたデータのみを参照します。GraphQLクエリは最小限に抑えてください。不要なフィールドを除外することで、処理性能が向上します。
ステップ 1.3: ロジック記述 (src/cart_lines_discounts_generate_run.rs)
use super::schema; use shopify_function::prelude::*; use shopify_function::Result; #[shopify_function] fn cart_lines_discounts_generate_run( input: schema::cart_lines_discounts_generate_run::Input, ) -> Result<schema::CartLinesDiscountsGenerateRunResult> { // 割引区分が一致しない場合は処理を終了 let has_order_discount = input .discount() .discount_classes() .contains(&schema::DiscountClass::Order); if !has_order_discount { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 対象コレクション内アイテムの数量を合計 let qualifying_qty: i64 = input .cart() .lines() .iter() .filter(|line| { if let schema::Merchandise::ProductVariant(v) = line.merchandise() { *v.product().in_any_collection() } else { false } }) .map(|line| *line.quantity()) .sum(); if qualifying_qty < 5 { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 注文小計に10%割引を適用 Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![schema::CartOperation::OrderDiscountsAdd( schema::OrderDiscountsAddOperation { selection_strategy: schema::OrderDiscountSelectionStrategy::First, candidates: vec![schema::OrderDiscountCandidate { targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal( schema::OrderSubtotalTarget { excluded_cart_line_ids: vec![], }, )], message: Some("Volume discount: 10% off".to_string()), value: schema::OrderDiscountCandidateValue::Percentage( schema::Percentage { value: Decimal(10.0) } ), conditions: None, associated_discount_code: None, }], }, )], }) }
use super::schema; use shopify_function::prelude::*; use shopify_function::Result; #[shopify_function] fn cart_lines_discounts_generate_run( input: schema::cart_lines_discounts_generate_run::Input, ) -> Result<schema::CartLinesDiscountsGenerateRunResult> { // 割引区分が一致しない場合は処理を終了 let has_order_discount = input .discount() .discount_classes() .contains(&schema::DiscountClass::Order); if !has_order_discount { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 対象コレクション内アイテムの数量を合計 let qualifying_qty: i64 = input .cart() .lines() .iter() .filter(|line| { if let schema::Merchandise::ProductVariant(v) = line.merchandise() { *v.product().in_any_collection() } else { false } }) .map(|line| *line.quantity()) .sum(); if qualifying_qty < 5 { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 注文小計に10%割引を適用 Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![schema::CartOperation::OrderDiscountsAdd( schema::OrderDiscountsAddOperation { selection_strategy: schema::OrderDiscountSelectionStrategy::First, candidates: vec![schema::OrderDiscountCandidate { targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal( schema::OrderSubtotalTarget { excluded_cart_line_ids: vec![], }, )], message: Some("Volume discount: 10% off".to_string()), value: schema::OrderDiscountCandidateValue::Percentage( schema::Percentage { value: Decimal(10.0) } ), conditions: None, associated_discount_code: None, }], }, )], }) }
ステップ 1.4: テスト・デプロイ・有効化
# ホットリロードを有効にしてローカル開発を開始 shopify app dev # 準備ができたらデプロイを実行 shopify app deploy # 起動したGraphiQLパネル(開発ターミナルで `g` を入力)で、 # 作成したFunctionを使用する自動割引を作成します
# ホットリロードを有効にしてローカル開発を開始 shopify app dev # 準備ができたらデプロイを実行 shopify app deploy # 起動したGraphiQLパネル(開発ターミナルで `g` を入力)で、 # 作成したFunctionを使用する自動割引を作成します
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
これで完了です。Functionが本番稼働し、バージョン管理され、旧Scriptが完全に置き換わりました。
チュートリアル 2:Shipping Scriptの代替(一定金額以上の特定配送法の非表示)
「高額な即日配送コストを避けるため、カート小計が500ドルを超える場合は速達配送(Express)を非表示にする」という一般的なScriptを、Delivery Customization Functionで再現します。
ステップ 2.1: 拡張機能の生成
shopify app generate extension --template delivery_customization --name hide-express-fn
shopify app generate extension --template delivery_customization --name hide-express-fn
ステップ 2.2: 入力クエリ (src/run.graphql)
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
ステップ 2.3: ロジック記述 (src/run.js — JavaScript版)
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
ステップ 2.4: 管理画面での有効化(GraphQL不要)
配送カスタマイズは、管理画面上にUIが自動提供されます。shopify app deploy実行後の手順:
設定 → 配送と配達 に移動します
下部の カスタマイズ セクションまでスクロールします
カスタマイズを追加 → 作成したFunctionを選択します
保存します
これで、本番環境で非表示ルールが適用されます。追加のGraphQLミューテーションは不要です。

チュートリアル 3:Payment Scriptの代替(B2B顧客向け代金引換の非表示)
「顧客タグに 'B2B' が設定されている場合、代金引換(Cash on Delivery)を非表示にする」ロジックを、Payment Customization Functionで実装します。
ステップ 3.1: 拡張機能の生成
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
ステップ 3.2: 入力クエリの作成
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
ステップ 3.3: ロジック記述 (src/run.js)
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
ステップ 3.4: 有効化
決済カスタマイズも 設定 → 決済 → カスタマイズ に管理画面UIが用意されています。配送と同様に、作成したFunctionを選択して保存すれば完了です。
ここで重要:購入後処理(Post-Purchase)に関する補足
本稿が Revize ブログに掲載されていることに関連し、重要な点を補足します。Revizeは、現在のFunctionsがカバーできない領域、すなわち「注文完了後の処理」を担います。注文確定後にお客様がアイテムを追加したり、サイズを変更したり、配送先住所の間違いを修正したり、適用し忘れた割引コードを追加したいといった要望が発生します。Functionsの稼働範囲はチェックアウト時までであり、Revizeはチェックアウト後の処理に対応します。 Functionsが「カートで何を許可するか」を決定するのに対し、Revizeは返金や注文再作成の手間をかけずに、購入後にお客様やサポートチームが注文内容を直接編集できる仕組みを提供します。これは、手動編集が困難な大量注文を処理するPlusマーカーや、顧客体験を重視し「注文確定後の変更は承れません」という定型対応を避けたいD2Cブランドにとって不可欠な機能です。
ScriptsからFunctionsへの移行計画が完了していても、購入後の注文編集プロセスが考慮されていない場合、運用開始後にボトルネックが発生します。公開中の注文管理ガイドでは、チェックアウト後の注文管理ワークフローについて解説しています。
移行プロセスの解説に戻ります。
テスト戦略:検証用タグパターンの活用
Functionsには管理画面でワンクリックで切り替えられる「下書きモード」が存在しません。実務的な推奨アプローチは、特定の顧客タグによって新しいFunctionの処理判定をゲートし、旧Scriptと新Functionを並行稼働させて動作検証を行い、同一の結果を確認した段階で完全に切り替える方法です。
ステップ 1: テストユーザーへのタグ付与
顧客管理画面で、検証に使用する社内アカウント等に FN-TESTER タグを付与します。
ステップ 2: タグの有無による条件分岐の追加
// run関数の先頭部分に追加 let is_tester = input .cart() .buyer_identity() .and_then(|bi| bi.customer()) .map(|c| c.has_any_tag()) .unwrap_or(&false); if !*is_tester { return Ok(default_result); // タグがない場合は処理を実行せず、既存のScriptに委ねる } // 新しいFunctionの処理をここに記述(テストユーザーにのみ適用)
// run関数の先頭部分に追加 let is_tester = input .cart() .buyer_identity() .and_then(|bi| bi.customer()) .map(|c| c.has_any_tag()) .unwrap_or(&false); if !*is_tester { return Ok(default_result); // タグがない場合は処理を実行せず、既存のScriptに委ねる } // 新しいFunctionの処理をここに記述(テストユーザーにのみ適用)
ステップ 3: 入力クエリに hasAnyTag を追加
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
ステップ 4: チェックアウト画面での検証
タグ付きユーザーとしてログインし、チェックアウトを進め、Functionが正しく動作することを確認します。タグのないユーザーでログインし、旧Scriptが従来通り実行されることを確認します。数日間安定稼働が確認できたら、タグ判定ロジックを削除して全ユーザーに公開します。
ステップ 5: 旧Scriptの無効化
アプリ管理 → Script Editor → [対象のScript] → 公開停止 を実行します。公開停止により、該当ロジックの制御は新しいFunctionへ完全に移行されます。
実用的なデプロイワークフローの構築
デベロッパーのローカル環境から手動でデプロイし続ける運用は推奨されません。最初の数件の移行を完了したら、CIパイプラインを構築しましょう。
最小構成のGitHub Actions例
# .github/workflows/deploy-functions.yml name: Deploy Shopify Functions on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - uses: dtolnay/rust-toolchain@stable with: { targets: wasm32-wasip1 } - run: npm install -g @shopify/cli@latest - run: shopify app deploy --force env: SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
# .github/workflows/deploy-functions.yml name: Deploy Shopify Functions on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - uses: dtolnay/rust-toolchain@stable with: { targets: wasm32-wasip1 } - run: npm install -g @shopify/cli@latest - run: shopify app deploy --force env: SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
パートナーダッシュボードの 設定 → トークン からパートナーAPIトークンを生成し、GitHubのSecretに設定します。これにより、main ブランチへのマージをトリガーにFunctionが自動デプロイされる体制が整います。
バージョン管理とロールバック
shopify app deploy はバージョン履歴を保存します。以前のバージョンに戻す手順は以下の通りです。
shopify app versions list shopify app release --version <previous-version-id
shopify app versions list shopify app release --version <previous-version-id
Scripts時代の「旧コードを手動でエディタにコピー&ペーストして戻す」といった属人的な運用から、完全な構成管理へと進化します。

移行時に陥りがちな典型的な間違い
Plusマーチャントの移行を支援する中で、頻発する5つの共通の誤りを紹介します。
1. Scriptsのコードを1対1で直訳しようとする: FunctionsはScriptsと設計が異なります。1つのFunction内で条件分岐を行い、複数のScriptをよりシンプルに統合することができます。移植前にシステム全体の構成を見直しましょう。
2. 必要なAPIアクセス権限(scopes)の不足: 多くのFunctionは、read_customers、read_orders、write_discounts などの権限を要求します。これらを shopify.app.toml の scopes に追加し、アプリを再認証してください。不足している場合、入力クエリはnullを返します。
3. 並行検証なしの全ユーザー公開: コードに問題がないように見えても、カート内が空、ギフトカード併用、ストアクレジット適用、B2B下書き注文などのエッジケースで問題が顕在化します。タグ付き検証を2日間挟むだけで、本番障害を回避できます。
4. カスタマイズレポートの未確認: 管理画面で出力できるレポートは、現在稼働している全ロジックの最良のチェックリストです。記憶に頼らず、レポートをベースに移行を進めてください。
5. コレクションIDや顧客タグのハードコーディング: 運用側で条件値を頻繁に変更する必要がある場合は、メタフィールドを利用したFunction構成を導入してください。CLIを使用してメタフィールド連携構成を生成できます。詳細はShopify公式ドキュメントを参照してください。
移行に向けたタイムラインの設計(残り75日想定)
6月30日に余裕を持って間に合わせるための標準的な移行ロードマップです。
週 | 実施タスク |
|---|---|
第1週(今週) | カスタマイズレポートをダウンロードし、現在動いているすべてのScriptを把握。Function移行、既存公開アプリへの代替、または廃止を個別に決定。 |
第2〜3週 | ローカル開発環境のセットアップ。最初のFunction作成。最もシンプルなScript(決済非表示ルールなど)の移行から着手。 |
第4〜6週 | 割引ロジックの移行に着手。Discounts APIは仕様が多岐にわたるため、最も時間を要します。テスト用タグを用いて検証を実施。 |
第7〜8週 | 配送/配達ロジックの移行。配送カスタマイズFunctionをデプロイし、管理画面から有効化。 |
第9〜10週 | CIパイプライン(GitHub Actionsなど)の構築。手動デプロイからの脱却。 |
第11週 (6月中旬) | 既存の全Scriptを非公開化。Function単独でストアを2週間稼働させ、挙動を最終確認。 |
6月30日 | Scriptsサポート終了。先行して切り替えが完了しているため影響なし。 |
今すぐ開始すれば、想定外のバグに対するバッファが確保できます。6月に入ってからの着手では十分な検証が困難になります。

よくある質問(FAQ)
Functionsの利用にはShopify Plusプランが必要ですか?
独自に開発したカスタムFunctionを利用するにはShopify Plusが必要ですが、Shopifyアプリストアで公開されている一般的なアプリ経由であれば、すべてのプランでFunctionsを利用できます。 Plus以外のマーチャントの場合、アプリストアから対象のFunction機能を提供するパブリックアプリをインストールするか、PlusへアップグレードしてカスタムFunctionを作成するかの選択となります。Scriptsを利用していたマーチャントは原則すでにPlusを契約しているため、影響は軽微です。
TypeScriptでFunctionを開発することはできますか?
はい、TypeScriptは公式にサポートされており、CLIによるコード自動生成が可能です。 shopify app generate extension で 「JavaScript」を選択して生成すると、プロジェクトには自動的に import("../generated/api") などの型定義が含まれます。必要に応じて .ts への拡張子変更および tsconfig.json の構成を行ってください。最終的に出力されるコンパイル済みファイル(WASM)の実行性能に言語間の差はありません。
従来のScriptsと比較して、Functionsの処理速度はどうですか?
通常5ms未満で実行され、従来のRubyベースのScriptsよりも圧倒的に高速です。 FunctionsはWebAssemblyにコンパイルされ専用のランタイムで動作するため、Shopifyは5msの実行制限時間を設けています。この制限時間を超えた場合、そのFunctionはスキップされ処理は適用されません。通常、適切に設計されたコードであれば1〜2msで処理が完了します。性能面での上限はScriptsに比べて大幅に向上しています。
Function内部から外部のAPIを呼び出すことは可能ですか?
いいえ、Functions内から外部ネットワークへのリクエスト(APIコール)は行えません。 セキュリティとパフォーマンスを担保するため、Functionは純粋なデータ処理(入力データに基づく出力を定義する)に限定されています。外部システムの情報(CRMデータ、動的な在庫連携など)が必要な場合は、あらかじめそのデータをメタフィールド等に書き出しておくか、App ProxyやWebhook、バックエンド処理と連携するCart Transformなど別の手法を用いて設計を行う必要があります。
Cart Transform API と Discounts API の違いは何ですか?
Discounts APIは金額の割り引き処理を担当し、Cart Transform APIはカートの中身(ラインアイテム自体)の変更を担当します。 10%引き、送料無料、BOGO(Buy One Get One)の適用にはDiscounts APIを使用します。2つの商品をカート内で自動的に1つのバンドル商品にまとめたり、特定のバリアントを複数のラインアイテムに分割したりする場合はCart Transformを使用します。一部の古いScriptは両方の処理を1つで行っていましたが、移行時は役割ごとに別々のFunctionへ分割して実装する必要があります。
開発ストアを使わずに、ローカル環境だけでFunctionをテストする方法はありますか?
cargo test(Rust)や npm test(JavaScript)による単体テスト(ユニットテスト)はローカル環境で完結しますが、チェックアウトを含めた全体的な疎通確認には開発ストアでのテストが不可欠です。 CLIツールには、ダミーの入力ファイルを用いてFunctionを実行する shopify app function run コマンドが用意されており、ローカルでの素早いロジック修正に役立ちます。ただし、最終的なカートでの振る舞いを検証するためには実環境が必要です。
同じタイプのFunctionを複数同時に有効化できますか?
はい、同じターゲットに対して複数のFunctionをデプロイし、設定順序に従って決定論的に連続実行させることが可能です。 割引に関しては、Shopifyの割引スタックルールが適用されます。配送や決済のカスタマイズにおいては、各Functionの出力データが次のFunctionに連携される形でチェーン実行されます。設計をシンプルに保つため、多くの開発チームは対象タイプごとにFunctionを1つに集約するアプローチをとっています。
Functionのデプロイ後、既存のScriptはどうなりますか?
Script Editorアプリから明示的に非公開にするまで、双方のロジックが並行して実行されます。 これにより本番環境での安全な並行テスト運用が可能です。新ロジックの安定動作を確認した後に、手動で旧Scriptを非公開に切り替えてください。なお、2026年6月30日を過ぎると、公開状態であってもすべてのScriptの実行がShopify側で強制停止されます。
この移行によってSEOやストアテーマに影響はありますか?
いいえ、ありません。Functionsはチェックアウト時のサーバーサイドで実行されるため、フロントエンドのテーマファイルや製品ページ、SEO構造を損なうことはありません。 変更が加わるのはチェックアウト内の割引、配送オプション、決済方法に限定されています。
旧Scriptで Input.line_items のカスタム属性を利用していた場合、どのように移行すればよいですか?
カートのラインアイテム(cart lines)の attribute フィールドから、GraphQL経由でカスタム属性を取得できます。 入力クエリ(GraphQL)の lines 内に attribute(key: "your-key") { value } を定義してください。Function内では、従来のRubyによるプロパティ参照とほぼ同様の手順でカスタム属性を利用して判定ロジックを組むことができます。
分析データや注文タグ(Order Tags)の付与をFunction側で行えますか?
いいえ、Functions自体は注文タグの書き込みやWebhookのトリガーを発行することはできません。現カートに対する変更操作の配列を返すのみの役割を持ちます。 注文完了後のタグ付与や他システムへの連携は、注文作成イベント(Order Creation)をトリガーとする Shopify Flow などを利用して実装してください。一般的な手法として、割引処理をFunctionで行い、その割引適用の履歴を検知したShopify Flowによって「VOLUME-DISCOUNT-APPLIED」といった注文タグを付与する組み合わせが用いられます。
カスタム開発をせず、既存の公開アプリで代替することは可能ですか?
はい、Shopifyアプリストアには、一般的なユースケースをカバーするFunctionsベースのアプリが多数提供されています。 「discount function」「delivery customization」「payment customization」などのキーワードで検索してください。段階的な割引、タグによる特定の決済方法の除外、特定金額以上の配送制限など、一般的な要件であれば既存のSaaSツールを使用することで、自社でのコード開発・保守コストを大幅に削減できます。独自の高度なロジックを要する場合に限定して、独自カスタムFunctionの開発を選択することを強く推奨します。
6月30日の期限に移行が間に合わなかった場合、どうなりますか?
該当のScriptの実行は完全に停止します。代替手段による救済、猶予期間、期限の延長は一切ありません。 割引、特定の配送レートの制御、決済方法の制限など、それまでScriptで処理されていたすべての機能が、世界協定時(UTC)の7月1日午前0時に無効化され、標準の挙動に戻ります。ビジネスに不可欠なロジックがある場合は、移行期限よりも大幅に前倒しした稼働スケジュールを設定してください。一般的に、並行テストを含めると移行期間は予想以上に長引きます。
移行後、Script Editorアプリはストアから削除しても構いませんか?
移行が完全に終了している場合はアンインストールして問題ありません。 6月30日以降、同アプリは機能しなくなります。すべての処理が新構成のFunctionに移行し、安定稼働が確認された時点でアプリを削除してください。Functionの稼働環境は独立しているため、アプリの削除による影響はありません。
今週取り組むべきアクション
この記事を読み終えたら、以下の4つのステップを最初の7日間で実行してください。
1. カスタマイズレポートの取得: 設定 → チェックアウト → カスタマイズレポート からレポートを出力し、タスクをリストアップします。これが移行作業のバックログになります。
2. 開発環境の確認: Node 18+、Shopify CLI、Rust(必要な場合)をインストールし、shopify version が動作することを確認します。所要時間は約30分です。
3. 開発ストアへのテスト実装: 決済方法の非表示など、最もシンプルな構成のFunctionを1つ作成し、開発ストアへデプロイします。本番への適用可否に関わらず、これによって一連のデプロイ・開発フローの動作が実証されます。
4. 今後8週間の作業時間の確保: 移行作業を他タスクの隙間時間で行うのは困難です。毎週火曜日と木曜日の午後など、スケジュールに固定枠を確保し、優先プロジェクトとして管理してください。
これまでのPlusマーチャントの移行パターンを見ると、環境調査と計画決定に2週間、コード開発に3週間、最終検証と微調整に1週間を要しています(計6週間)。現在、終了まで10週間の猶予があるならば、その余裕分をコードレビューとQA(品質管理)に充て、遅滞なく進めてください。
チェックアウトロジックが片付いた後、多くのマーチャントが次に取り組むのが「購入後処理」の最適化です(注文確定後の住所変更、商品の入れ替え、割引の適用漏れ対応)。もしこれらが今後のロードマップに含まれているならば(トランザクション数の多いPlusストアや顧客体験を重視するストアでは不可欠な項目です)、Shopifyアプリストアで提供されているRevizeが、ここで構築するFunctionsと並行してその解決をサポートします。
関連リソース
関連記事
2026年8月更新。 Revizeは、配送先住所の変更、商品の交換、注文キャンセル、返金、ストアクレジットの付与などを、出荷完了前であればサポートに問い合わせることなく、顧客自身で行えるようにするShopifyアプリです。詳細については、購入後の注文変更機能の導入を参照するか、ShopifyアプリストアでRevizeを確認してください。
2026年4月16日。昨日、4月15日はShopifyがScript Editorを完全に閉鎖した日です。すでに新しいScriptの作成や公開はできません。この期限が最も深刻に響くのが購入後ロジックです。配送先住所の変更は、編集された注文全体の30.2%を占める最大の購入後編集であり(Revize、2026年)、これらの編集を処理している既存のScriptはすべて凍結されました。実行停止は75日後の2026年6月30日に迫っています。
過去12ヶ月間、この移行を「次のスプリント」へと先送りしてきたShopify Plusデベロッパー、あるいはPlusストアを運営するパートナーエージェンシーにとって、これは重大な問題です。「できれば修正したい」レベルではなく、「7月1日の午前0時にチェックアウトがクラッシュする」問題です。ほとんどのPlusストアは長年にわたり5〜20個のScriptを蓄積しており、それらは誰が書いたかも覚えていない割引ルール、配送方法の非表示、決済ゲートウェイの制御をバックグラウンドで静かに処理しています。
このガイドは、1月に欲しかった技術的な移行マニュアルです。 単なる戦略ではなく、実際のコードに焦点を当てています。読み終える頃には、Shopify CLIを使用したFunctionの雛形生成、割引・配送カスタマイズ・決済カスタマイズのためのRustやJavaScriptロジックの記述、タグ付けされた顧客サブセットに対する安全なテスト方法、そして既存のチェックアウトを壊さずに本番環境へデプロイする方法が理解できているはずです。
ストアからScriptを排除し、Functionsを導入しましょう。

クイックアンサー:60秒で理解するScriptsからFunctionsへの移行
1段落でわかる移行概要: Shopify Scripts(Script Editor内のRubyコード、Plus限定)は、Shopify Functions(RustまたはJavaScriptで記述されたWebAssemblyモジュール、すべてのプランで利用可能)に置き換えられます。
shopify app generate extensionでFunctionを生成し、必要なカートデータを取得するrun.graphqlクエリを書き、処理(割引、配送方法の非表示など)を返すrun.rsまたはrun.jsファイルを記述します。その後、shopify app deployでデプロイし、管理画面またはGraphQLミューテーション経由で有効化します。FunctionsはコンパイルされたWASMとして5ms未満のレイテンシで実行され、すべてのプランで動作し、Shopifyが今後サポートする唯一のカスタマイズパスです。
6月30日に実際に何が起きるのか
コードに触れる前に、日付を整理しておきましょう。重要な日付は2つあります。
日付 | 発生する事象 | 必要なアクション |
|---|---|---|
2026年4月15日 (超過) | Script Editorが読み取り専用に。新規Scriptの作成および既存Scriptの編集が不可に。 | 既存のScriptは動作を継続。今すぐ移行するか、ロジックを凍結する。 |
2026年6月30日 | すべてのShopify Scriptsの実行が停止。 | この日より前に、代替となるFunctionを本番公開する必要あり。 |
この移行はオール・オア・ナッシングです。6月30日までにFunctionがデプロイされてチェックアウトが動作し続けるか、デプロイされずに影響を受けるすべてのカートが標準価格、標準配送レート、デフォルトの決済方法へと自動的に戻るかのどちらかです。中間はありません。Scriptが実行されるか停止するかの二択であり、6月30日以降は停止します。
ヒント: Shopify管理画面の
設定 → チェックアウト → カスタマイズレポートを開いてください。ストア内でアクティブなすべてのScript、その機能、および推奨される代替Functionタイプが一覧表示されています。まずはここから始めましょう。
Functions と Scripts の比較:何が変わったのか
比較項目 | Shopify Scripts(非推奨) | Shopify Functions(代替) |
|---|---|---|
言語 | Ruby DSL(Shopify専用) | Rust、JavaScript、TypeScript |
実行環境 | Shopifyインフラ上のサンドボックス化されたRuby | WebAssembly (WASM) — 5ms未満の実行速度 |
対応プラン | Plusのみ | すべてのプラン(カスタムアプリはPlusが必要、公開アプリは全プラン開放) |
エディタ | 管理画面内のScript Editor | ローカルIDE + Shopify CLI |
バージョン管理 | なし(直接編集・即時反映) | Git対応 — 完全なバージョン管理 |
テスト | チェックアウトでの手動テスト |
|
デプロイ | 管理画面で「保存」をクリック | ターミナルから |
制御対象 | ラインアイテム、配送、決済 | 割引、Cart Transform、バリデーション、配送カスタマイズ、決済カスタマイズ、注文ルーティング、フルフィルメント制約など |
アーキテクチャの転換は重要です。Scriptsは「テキストエリアでRubyを微調整する」ものでした。Functionsは「実際のアプリケーションを記述し、バージョン管理し、ローカルでテストし、CIパイプラインを通じてデプロイする」ものです。習得の難易度は上がりますが、チェックアウトロジックにおける今後の移行はこれが最後になります。Functionsは一時しのぎのScriptsとは異なり、Shopifyが長期的に提供する基盤です。
Scriptsから適切なFunctionタイプへのマッピング
現在稼働しているすべてのScriptは、対応するFunction APIにマッピングされます。以下は、移行作業において常に確認すべき対応表です。
従来のScriptタイプ | 機能概要 | 新しいFunction API | Functionターゲット |
|---|---|---|---|
Line Item Script | 特定の製品/顧客/カート条件に応じた割引適用 | Cart & Checkout Discounts API |
|
Shipping Script(割引) | カートルールに基づく送料無料または配送割引 | Cart & Checkout Discounts API |
|
Shipping Script(非表示/名称変更/並び替え) | 一定金額以上の送料無料時の特定配送法非表示、名称変更など | Delivery Customization API |
|
Payment Script | B2B顧客向けPayPalの非表示、高額注文時の代金引換非表示、並び替え | Payment Customization API |
|
カート変更Script(稀少) | 商品のバンドル、ラインアイテムの入れ替え | Cart Transform API |
|
チェックアウトブロックScript | 不適切なSKU組み合わせのカートを拒否 | Cart & Checkout Validation API |
|
10個のScriptを運用している場合、作成するFunctionは3〜5個程度に集約される傾向があります。複数のScriptは通常、分岐ロジックを整理して1つのFunctionに統合できます。

前提条件:ローカル開発環境の構築
Functionの作成を開始する前に、ローカル環境に以下の3つがインストールされていることを確認してください。ターミナルで各コマンドを実行してチェックします。
1. Node.js 18+
node --version # 18.0.0以上である必要があります
バージョンが古い場合は、nvmを使用するか、nodejs.orgからダウンロードしてインストールしてください。
2. Shopify CLI 3+
npm install -g @shopify/cli@latest shopify version # 3.x以上のバージョンが出力されることを確認します
3. Rustツールチェーン(RustでFunctionを記述する場合のみ)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add wasm32-wasip1 cargo --version
JavaScriptでFunctionを書く場合、Rustは不要です。チームで記述言語を統一することを推奨します。両方を混在させるとメンテナンスコストが増大します。
4. 開発用ストア
パートナーダッシュボードにログインして新しい開発用ストアを作成するか、既存のストアを使用します。本番環境に適用する前に、まずこの開発ストアにFunctionをデプロイします。
最初のFunctionの作成
CLIがボイラープレートの大部分を生成します。任意のディレクトリ内で以下を実行します。
# 新しいShopifyアプリを作成(既存のアプリがある場合はスキップ) shopify app init my-checkout-functions cd my-checkout-functions # Function拡張機能を生成 shopify app generate extension
CLIプロンプトに従って選択していきます。割引Functionの場合、以下の構成を選択します。
タイプ: Function
テンプレート:
discount(またはcart_checkout_validation,delivery_customization,payment_customizationなど)言語: Rust または JavaScript
名称:
volume-discount-fnなど
これにより、以下の構成で extensions/volume-discount-fn/ が作成されます。
extensions/volume-discount-fn/ ├── shopify.extension.toml # Function設定(ターゲット、ビルド、バージョン) ├── src/ │ ├── cart_lines_discounts_generate_run.graphql # 入力クエリ │ └── cart_lines_discounts_generate_run.rs # Functionロジック ├── Cargo.toml # Rust依存関係(Rustのみ) └── README.md
編集頻度が高いのは、.toml(設定)、.graphql(入力)、および.rs / .js(ロジック)の3つのファイルです。
チュートリアル 1:Line Item Scriptの代替(ボリュームディスカウント)
特定のコレクションがカート内に5点以上ある場合、注文小計から10%割引する従来のScriptを、Functionに移植する例を紹介します。
ステップ 1.1: 構成設定 (shopify.extension.toml)
api_version = "2026-01" [[extensions]] name = "volume-discount-fn" handle = "volume-discount-fn" type = "function" [[extensions.targeting]] target = "cart.lines.discounts.generate.run" input_query = "src/cart_lines_discounts_generate_run.graphql" export = "cart_lines_discounts_generate_run" [extensions.build] command = "cargo build --target=wasm32-wasip1 --release" path = "target/wasm32-wasip1/release/volume-discount-fn.wasm" watch = ["src/**/*.rs"]
ステップ 1.2: 入力クエリ (src/cart_lines_discounts_generate_run.graphql)
query Input { cart { lines { id quantity cost { subtotalAmount { amount } } merchandise { ... on ProductVariant { product { inAnyCollection(ids: ["gid://shopify/Collection/123456789"]) } } } } } discount { discountClasses } }
ヒント: Functionsはクエリされたデータのみを参照します。GraphQLクエリは最小限に抑えてください。不要なフィールドを除外することで、処理性能が向上します。
ステップ 1.3: ロジック記述 (src/cart_lines_discounts_generate_run.rs)
use super::schema; use shopify_function::prelude::*; use shopify_function::Result; #[shopify_function] fn cart_lines_discounts_generate_run( input: schema::cart_lines_discounts_generate_run::Input, ) -> Result<schema::CartLinesDiscountsGenerateRunResult> { // 割引区分が一致しない場合は処理を終了 let has_order_discount = input .discount() .discount_classes() .contains(&schema::DiscountClass::Order); if !has_order_discount { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 対象コレクション内アイテムの数量を合計 let qualifying_qty: i64 = input .cart() .lines() .iter() .filter(|line| { if let schema::Merchandise::ProductVariant(v) = line.merchandise() { *v.product().in_any_collection() } else { false } }) .map(|line| *line.quantity()) .sum(); if qualifying_qty < 5 { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 注文小計に10%割引を適用 Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![schema::CartOperation::OrderDiscountsAdd( schema::OrderDiscountsAddOperation { selection_strategy: schema::OrderDiscountSelectionStrategy::First, candidates: vec![schema::OrderDiscountCandidate { targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal( schema::OrderSubtotalTarget { excluded_cart_line_ids: vec![], }, )], message: Some("Volume discount: 10% off".to_string()), value: schema::OrderDiscountCandidateValue::Percentage( schema::Percentage { value: Decimal(10.0) } ), conditions: None, associated_discount_code: None, }], }, )], }) }
ステップ 1.4: テスト・デプロイ・有効化
# ホットリロードを有効にしてローカル開発を開始 shopify app dev # 準備ができたらデプロイを実行 shopify app deploy # 起動したGraphiQLパネル(開発ターミナルで `g` を入力)で、 # 作成したFunctionを使用する自動割引を作成します
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
これで完了です。Functionが本番稼働し、バージョン管理され、旧Scriptが完全に置き換わりました。
チュートリアル 2:Shipping Scriptの代替(一定金額以上の特定配送法の非表示)
「高額な即日配送コストを避けるため、カート小計が500ドルを超える場合は速達配送(Express)を非表示にする」という一般的なScriptを、Delivery Customization Functionで再現します。
ステップ 2.1: 拡張機能の生成
shopify app generate extension --template delivery_customization --name hide-express-fn
ステップ 2.2: 入力クエリ (src/run.graphql)
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
ステップ 2.3: ロジック記述 (src/run.js — JavaScript版)
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
ステップ 2.4: 管理画面での有効化(GraphQL不要)
配送カスタマイズは、管理画面上にUIが自動提供されます。shopify app deploy実行後の手順:
設定 → 配送と配達 に移動します
下部の カスタマイズ セクションまでスクロールします
カスタマイズを追加 → 作成したFunctionを選択します
保存します
これで、本番環境で非表示ルールが適用されます。追加のGraphQLミューテーションは不要です。

チュートリアル 3:Payment Scriptの代替(B2B顧客向け代金引換の非表示)
「顧客タグに 'B2B' が設定されている場合、代金引換(Cash on Delivery)を非表示にする」ロジックを、Payment Customization Functionで実装します。
ステップ 3.1: 拡張機能の生成
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
ステップ 3.2: 入力クエリの作成
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
ステップ 3.3: ロジック記述 (src/run.js)
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
ステップ 3.4: 有効化
決済カスタマイズも 設定 → 決済 → カスタマイズ に管理画面UIが用意されています。配送と同様に、作成したFunctionを選択して保存すれば完了です。
ここで重要:購入後処理(Post-Purchase)に関する補足
本稿が Revize ブログに掲載されていることに関連し、重要な点を補足します。Revizeは、現在のFunctionsがカバーできない領域、すなわち「注文完了後の処理」を担います。注文確定後にお客様がアイテムを追加したり、サイズを変更したり、配送先住所の間違いを修正したり、適用し忘れた割引コードを追加したいといった要望が発生します。Functionsの稼働範囲はチェックアウト時までであり、Revizeはチェックアウト後の処理に対応します。 Functionsが「カートで何を許可するか」を決定するのに対し、Revizeは返金や注文再作成の手間をかけずに、購入後にお客様やサポートチームが注文内容を直接編集できる仕組みを提供します。これは、手動編集が困難な大量注文を処理するPlusマーカーや、顧客体験を重視し「注文確定後の変更は承れません」という定型対応を避けたいD2Cブランドにとって不可欠な機能です。
ScriptsからFunctionsへの移行計画が完了していても、購入後の注文編集プロセスが考慮されていない場合、運用開始後にボトルネックが発生します。公開中の注文管理ガイドでは、チェックアウト後の注文管理ワークフローについて解説しています。
移行プロセスの解説に戻ります。
テスト戦略:検証用タグパターンの活用
Functionsには管理画面でワンクリックで切り替えられる「下書きモード」が存在しません。実務的な推奨アプローチは、特定の顧客タグによって新しいFunctionの処理判定をゲートし、旧Scriptと新Functionを並行稼働させて動作検証を行い、同一の結果を確認した段階で完全に切り替える方法です。
ステップ 1: テストユーザーへのタグ付与
顧客管理画面で、検証に使用する社内アカウント等に FN-TESTER タグを付与します。
ステップ 2: タグの有無による条件分岐の追加
// run関数の先頭部分に追加 let is_tester = input .cart() .buyer_identity() .and_then(|bi| bi.customer()) .map(|c| c.has_any_tag()) .unwrap_or(&false); if !*is_tester { return Ok(default_result); // タグがない場合は処理を実行せず、既存のScriptに委ねる } // 新しいFunctionの処理をここに記述(テストユーザーにのみ適用)
ステップ 3: 入力クエリに hasAnyTag を追加
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
ステップ 4: チェックアウト画面での検証
タグ付きユーザーとしてログインし、チェックアウトを進め、Functionが正しく動作することを確認します。タグのないユーザーでログインし、旧Scriptが従来通り実行されることを確認します。数日間安定稼働が確認できたら、タグ判定ロジックを削除して全ユーザーに公開します。
ステップ 5: 旧Scriptの無効化
アプリ管理 → Script Editor → [対象のScript] → 公開停止 を実行します。公開停止により、該当ロジックの制御は新しいFunctionへ完全に移行されます。
実用的なデプロイワークフローの構築
デベロッパーのローカル環境から手動でデプロイし続ける運用は推奨されません。最初の数件の移行を完了したら、CIパイプラインを構築しましょう。
最小構成のGitHub Actions例
# .github/workflows/deploy-functions.yml name: Deploy Shopify Functions on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - uses: dtolnay/rust-toolchain@stable with: { targets: wasm32-wasip1 } - run: npm install -g @shopify/cli@latest - run: shopify app deploy --force env: SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
パートナーダッシュボードの 設定 → トークン からパートナーAPIトークンを生成し、GitHubのSecretに設定します。これにより、main ブランチへのマージをトリガーにFunctionが自動デプロイされる体制が整います。
バージョン管理とロールバック
shopify app deploy はバージョン履歴を保存します。以前のバージョンに戻す手順は以下の通りです。
shopify app versions list shopify app release --version <previous-version-id
Scripts時代の「旧コードを手動でエディタにコピー&ペーストして戻す」といった属人的な運用から、完全な構成管理へと進化します。

移行時に陥りがちな典型的な間違い
Plusマーチャントの移行を支援する中で、頻発する5つの共通の誤りを紹介します。
1. Scriptsのコードを1対1で直訳しようとする: FunctionsはScriptsと設計が異なります。1つのFunction内で条件分岐を行い、複数のScriptをよりシンプルに統合することができます。移植前にシステム全体の構成を見直しましょう。
2. 必要なAPIアクセス権限(scopes)の不足: 多くのFunctionは、read_customers、read_orders、write_discounts などの権限を要求します。これらを shopify.app.toml の scopes に追加し、アプリを再認証してください。不足している場合、入力クエリはnullを返します。
3. 並行検証なしの全ユーザー公開: コードに問題がないように見えても、カート内が空、ギフトカード併用、ストアクレジット適用、B2B下書き注文などのエッジケースで問題が顕在化します。タグ付き検証を2日間挟むだけで、本番障害を回避できます。
4. カスタマイズレポートの未確認: 管理画面で出力できるレポートは、現在稼働している全ロジックの最良のチェックリストです。記憶に頼らず、レポートをベースに移行を進めてください。
5. コレクションIDや顧客タグのハードコーディング: 運用側で条件値を頻繁に変更する必要がある場合は、メタフィールドを利用したFunction構成を導入してください。CLIを使用してメタフィールド連携構成を生成できます。詳細はShopify公式ドキュメントを参照してください。
移行に向けたタイムラインの設計(残り75日想定)
6月30日に余裕を持って間に合わせるための標準的な移行ロードマップです。
週 | 実施タスク |
|---|---|
第1週(今週) | カスタマイズレポートをダウンロードし、現在動いているすべてのScriptを把握。Function移行、既存公開アプリへの代替、または廃止を個別に決定。 |
第2〜3週 | ローカル開発環境のセットアップ。最初のFunction作成。最もシンプルなScript(決済非表示ルールなど)の移行から着手。 |
第4〜6週 | 割引ロジックの移行に着手。Discounts APIは仕様が多岐にわたるため、最も時間を要します。テスト用タグを用いて検証を実施。 |
第7〜8週 | 配送/配達ロジックの移行。配送カスタマイズFunctionをデプロイし、管理画面から有効化。 |
第9〜10週 | CIパイプライン(GitHub Actionsなど)の構築。手動デプロイからの脱却。 |
第11週 (6月中旬) | 既存の全Scriptを非公開化。Function単独でストアを2週間稼働させ、挙動を最終確認。 |
6月30日 | Scriptsサポート終了。先行して切り替えが完了しているため影響なし。 |
今すぐ開始すれば、想定外のバグに対するバッファが確保できます。6月に入ってからの着手では十分な検証が困難になります。

よくある質問(FAQ)
Functionsの利用にはShopify Plusプランが必要ですか?
独自に開発したカスタムFunctionを利用するにはShopify Plusが必要ですが、Shopifyアプリストアで公開されている一般的なアプリ経由であれば、すべてのプランでFunctionsを利用できます。 Plus以外のマーチャントの場合、アプリストアから対象のFunction機能を提供するパブリックアプリをインストールするか、PlusへアップグレードしてカスタムFunctionを作成するかの選択となります。Scriptsを利用していたマーチャントは原則すでにPlusを契約しているため、影響は軽微です。
TypeScriptでFunctionを開発することはできますか?
はい、TypeScriptは公式にサポートされており、CLIによるコード自動生成が可能です。 shopify app generate extension で 「JavaScript」を選択して生成すると、プロジェクトには自動的に import("../generated/api") などの型定義が含まれます。必要に応じて .ts への拡張子変更および tsconfig.json の構成を行ってください。最終的に出力されるコンパイル済みファイル(WASM)の実行性能に言語間の差はありません。
従来のScriptsと比較して、Functionsの処理速度はどうですか?
通常5ms未満で実行され、従来のRubyベースのScriptsよりも圧倒的に高速です。 FunctionsはWebAssemblyにコンパイルされ専用のランタイムで動作するため、Shopifyは5msの実行制限時間を設けています。この制限時間を超えた場合、そのFunctionはスキップされ処理は適用されません。通常、適切に設計されたコードであれば1〜2msで処理が完了します。性能面での上限はScriptsに比べて大幅に向上しています。
Function内部から外部のAPIを呼び出すことは可能ですか?
いいえ、Functions内から外部ネットワークへのリクエスト(APIコール)は行えません。 セキュリティとパフォーマンスを担保するため、Functionは純粋なデータ処理(入力データに基づく出力を定義する)に限定されています。外部システムの情報(CRMデータ、動的な在庫連携など)が必要な場合は、あらかじめそのデータをメタフィールド等に書き出しておくか、App ProxyやWebhook、バックエンド処理と連携するCart Transformなど別の手法を用いて設計を行う必要があります。
Cart Transform API と Discounts API の違いは何ですか?
Discounts APIは金額の割り引き処理を担当し、Cart Transform APIはカートの中身(ラインアイテム自体)の変更を担当します。 10%引き、送料無料、BOGO(Buy One Get One)の適用にはDiscounts APIを使用します。2つの商品をカート内で自動的に1つのバンドル商品にまとめたり、特定のバリアントを複数のラインアイテムに分割したりする場合はCart Transformを使用します。一部の古いScriptは両方の処理を1つで行っていましたが、移行時は役割ごとに別々のFunctionへ分割して実装する必要があります。
開発ストアを使わずに、ローカル環境だけでFunctionをテストする方法はありますか?
cargo test(Rust)や npm test(JavaScript)による単体テスト(ユニットテスト)はローカル環境で完結しますが、チェックアウトを含めた全体的な疎通確認には開発ストアでのテストが不可欠です。 CLIツールには、ダミーの入力ファイルを用いてFunctionを実行する shopify app function run コマンドが用意されており、ローカルでの素早いロジック修正に役立ちます。ただし、最終的なカートでの振る舞いを検証するためには実環境が必要です。
同じタイプのFunctionを複数同時に有効化できますか?
はい、同じターゲットに対して複数のFunctionをデプロイし、設定順序に従って決定論的に連続実行させることが可能です。 割引に関しては、Shopifyの割引スタックルールが適用されます。配送や決済のカスタマイズにおいては、各Functionの出力データが次のFunctionに連携される形でチェーン実行されます。設計をシンプルに保つため、多くの開発チームは対象タイプごとにFunctionを1つに集約するアプローチをとっています。
Functionのデプロイ後、既存のScriptはどうなりますか?
Script Editorアプリから明示的に非公開にするまで、双方のロジックが並行して実行されます。 これにより本番環境での安全な並行テスト運用が可能です。新ロジックの安定動作を確認した後に、手動で旧Scriptを非公開に切り替えてください。なお、2026年6月30日を過ぎると、公開状態であってもすべてのScriptの実行がShopify側で強制停止されます。
この移行によってSEOやストアテーマに影響はありますか?
いいえ、ありません。Functionsはチェックアウト時のサーバーサイドで実行されるため、フロントエンドのテーマファイルや製品ページ、SEO構造を損なうことはありません。 変更が加わるのはチェックアウト内の割引、配送オプション、決済方法に限定されています。
旧Scriptで Input.line_items のカスタム属性を利用していた場合、どのように移行すればよいですか?
カートのラインアイテム(cart lines)の attribute フィールドから、GraphQL経由でカスタム属性を取得できます。 入力クエリ(GraphQL)の lines 内に attribute(key: "your-key") { value } を定義してください。Function内では、従来のRubyによるプロパティ参照とほぼ同様の手順でカスタム属性を利用して判定ロジックを組むことができます。
分析データや注文タグ(Order Tags)の付与をFunction側で行えますか?
いいえ、Functions自体は注文タグの書き込みやWebhookのトリガーを発行することはできません。現カートに対する変更操作の配列を返すのみの役割を持ちます。 注文完了後のタグ付与や他システムへの連携は、注文作成イベント(Order Creation)をトリガーとする Shopify Flow などを利用して実装してください。一般的な手法として、割引処理をFunctionで行い、その割引適用の履歴を検知したShopify Flowによって「VOLUME-DISCOUNT-APPLIED」といった注文タグを付与する組み合わせが用いられます。
カスタム開発をせず、既存の公開アプリで代替することは可能ですか?
はい、Shopifyアプリストアには、一般的なユースケースをカバーするFunctionsベースのアプリが多数提供されています。 「discount function」「delivery customization」「payment customization」などのキーワードで検索してください。段階的な割引、タグによる特定の決済方法の除外、特定金額以上の配送制限など、一般的な要件であれば既存のSaaSツールを使用することで、自社でのコード開発・保守コストを大幅に削減できます。独自の高度なロジックを要する場合に限定して、独自カスタムFunctionの開発を選択することを強く推奨します。
6月30日の期限に移行が間に合わなかった場合、どうなりますか?
該当のScriptの実行は完全に停止します。代替手段による救済、猶予期間、期限の延長は一切ありません。 割引、特定の配送レートの制御、決済方法の制限など、それまでScriptで処理されていたすべての機能が、世界協定時(UTC)の7月1日午前0時に無効化され、標準の挙動に戻ります。ビジネスに不可欠なロジックがある場合は、移行期限よりも大幅に前倒しした稼働スケジュールを設定してください。一般的に、並行テストを含めると移行期間は予想以上に長引きます。
移行後、Script Editorアプリはストアから削除しても構いませんか?
移行が完全に終了している場合はアンインストールして問題ありません。 6月30日以降、同アプリは機能しなくなります。すべての処理が新構成のFunctionに移行し、安定稼働が確認された時点でアプリを削除してください。Functionの稼働環境は独立しているため、アプリの削除による影響はありません。
今週取り組むべきアクション
この記事を読み終えたら、以下の4つのステップを最初の7日間で実行してください。
1. カスタマイズレポートの取得: 設定 → チェックアウト → カスタマイズレポート からレポートを出力し、タスクをリストアップします。これが移行作業のバックログになります。
2. 開発環境の確認: Node 18+、Shopify CLI、Rust(必要な場合)をインストールし、shopify version が動作することを確認します。所要時間は約30分です。
3. 開発ストアへのテスト実装: 決済方法の非表示など、最もシンプルな構成のFunctionを1つ作成し、開発ストアへデプロイします。本番への適用可否に関わらず、これによって一連のデプロイ・開発フローの動作が実証されます。
4. 今後8週間の作業時間の確保: 移行作業を他タスクの隙間時間で行うのは困難です。毎週火曜日と木曜日の午後など、スケジュールに固定枠を確保し、優先プロジェクトとして管理してください。
これまでのPlusマーチャントの移行パターンを見ると、環境調査と計画決定に2週間、コード開発に3週間、最終検証と微調整に1週間を要しています(計6週間)。現在、終了まで10週間の猶予があるならば、その余裕分をコードレビューとQA(品質管理)に充て、遅滞なく進めてください。
チェックアウトロジックが片付いた後、多くのマーチャントが次に取り組むのが「購入後処理」の最適化です(注文確定後の住所変更、商品の入れ替え、割引の適用漏れ対応)。もしこれらが今後のロードマップに含まれているならば(トランザクション数の多いPlusストアや顧客体験を重視するストアでは不可欠な項目です)、Shopifyアプリストアで提供されているRevizeが、ここで構築するFunctionsと並行してその解決をサポートします。
関連リソース
関連記事
2026年8月更新。 Revizeは、配送先住所の変更、商品の交換、注文キャンセル、返金、ストアクレジットの付与などを、出荷完了前であればサポートに問い合わせることなく、顧客自身で行えるようにするShopifyアプリです。詳細については、購入後の注文変更機能の導入を参照するか、ShopifyアプリストアでRevizeを確認してください。
2026年4月16日。昨日、4月15日はShopifyがScript Editorを完全に閉鎖した日です。すでに新しいScriptの作成や公開はできません。この期限が最も深刻に響くのが購入後ロジックです。配送先住所の変更は、編集された注文全体の30.2%を占める最大の購入後編集であり(Revize、2026年)、これらの編集を処理している既存のScriptはすべて凍結されました。実行停止は75日後の2026年6月30日に迫っています。
過去12ヶ月間、この移行を「次のスプリント」へと先送りしてきたShopify Plusデベロッパー、あるいはPlusストアを運営するパートナーエージェンシーにとって、これは重大な問題です。「できれば修正したい」レベルではなく、「7月1日の午前0時にチェックアウトがクラッシュする」問題です。ほとんどのPlusストアは長年にわたり5〜20個のScriptを蓄積しており、それらは誰が書いたかも覚えていない割引ルール、配送方法の非表示、決済ゲートウェイの制御をバックグラウンドで静かに処理しています。
このガイドは、1月に欲しかった技術的な移行マニュアルです。 単なる戦略ではなく、実際のコードに焦点を当てています。読み終える頃には、Shopify CLIを使用したFunctionの雛形生成、割引・配送カスタマイズ・決済カスタマイズのためのRustやJavaScriptロジックの記述、タグ付けされた顧客サブセットに対する安全なテスト方法、そして既存のチェックアウトを壊さずに本番環境へデプロイする方法が理解できているはずです。
ストアからScriptを排除し、Functionsを導入しましょう。

クイックアンサー:60秒で理解するScriptsからFunctionsへの移行
1段落でわかる移行概要: Shopify Scripts(Script Editor内のRubyコード、Plus限定)は、Shopify Functions(RustまたはJavaScriptで記述されたWebAssemblyモジュール、すべてのプランで利用可能)に置き換えられます。
shopify app generate extensionでFunctionを生成し、必要なカートデータを取得するrun.graphqlクエリを書き、処理(割引、配送方法の非表示など)を返すrun.rsまたはrun.jsファイルを記述します。その後、shopify app deployでデプロイし、管理画面またはGraphQLミューテーション経由で有効化します。FunctionsはコンパイルされたWASMとして5ms未満のレイテンシで実行され、すべてのプランで動作し、Shopifyが今後サポートする唯一のカスタマイズパスです。
6月30日に実際に何が起きるのか
コードに触れる前に、日付を整理しておきましょう。重要な日付は2つあります。
日付 | 発生する事象 | 必要なアクション |
|---|---|---|
2026年4月15日 (超過) | Script Editorが読み取り専用に。新規Scriptの作成および既存Scriptの編集が不可に。 | 既存のScriptは動作を継続。今すぐ移行するか、ロジックを凍結する。 |
2026年6月30日 | すべてのShopify Scriptsの実行が停止。 | この日より前に、代替となるFunctionを本番公開する必要あり。 |
この移行はオール・オア・ナッシングです。6月30日までにFunctionがデプロイされてチェックアウトが動作し続けるか、デプロイされずに影響を受けるすべてのカートが標準価格、標準配送レート、デフォルトの決済方法へと自動的に戻るかのどちらかです。中間はありません。Scriptが実行されるか停止するかの二択であり、6月30日以降は停止します。
ヒント: Shopify管理画面の
設定 → チェックアウト → カスタマイズレポートを開いてください。ストア内でアクティブなすべてのScript、その機能、および推奨される代替Functionタイプが一覧表示されています。まずはここから始めましょう。
Functions と Scripts の比較:何が変わったのか
比較項目 | Shopify Scripts(非推奨) | Shopify Functions(代替) |
|---|---|---|
言語 | Ruby DSL(Shopify専用) | Rust、JavaScript、TypeScript |
実行環境 | Shopifyインフラ上のサンドボックス化されたRuby | WebAssembly (WASM) — 5ms未満の実行速度 |
対応プラン | Plusのみ | すべてのプラン(カスタムアプリはPlusが必要、公開アプリは全プラン開放) |
エディタ | 管理画面内のScript Editor | ローカルIDE + Shopify CLI |
バージョン管理 | なし(直接編集・即時反映) | Git対応 — 完全なバージョン管理 |
テスト | チェックアウトでの手動テスト |
|
デプロイ | 管理画面で「保存」をクリック | ターミナルから |
制御対象 | ラインアイテム、配送、決済 | 割引、Cart Transform、バリデーション、配送カスタマイズ、決済カスタマイズ、注文ルーティング、フルフィルメント制約など |
アーキテクチャの転換は重要です。Scriptsは「テキストエリアでRubyを微調整する」ものでした。Functionsは「実際のアプリケーションを記述し、バージョン管理し、ローカルでテストし、CIパイプラインを通じてデプロイする」ものです。習得の難易度は上がりますが、チェックアウトロジックにおける今後の移行はこれが最後になります。Functionsは一時しのぎのScriptsとは異なり、Shopifyが長期的に提供する基盤です。
Scriptsから適切なFunctionタイプへのマッピング
現在稼働しているすべてのScriptは、対応するFunction APIにマッピングされます。以下は、移行作業において常に確認すべき対応表です。
従来のScriptタイプ | 機能概要 | 新しいFunction API | Functionターゲット |
|---|---|---|---|
Line Item Script | 特定の製品/顧客/カート条件に応じた割引適用 | Cart & Checkout Discounts API |
|
Shipping Script(割引) | カートルールに基づく送料無料または配送割引 | Cart & Checkout Discounts API |
|
Shipping Script(非表示/名称変更/並び替え) | 一定金額以上の送料無料時の特定配送法非表示、名称変更など | Delivery Customization API |
|
Payment Script | B2B顧客向けPayPalの非表示、高額注文時の代金引換非表示、並び替え | Payment Customization API |
|
カート変更Script(稀少) | 商品のバンドル、ラインアイテムの入れ替え | Cart Transform API |
|
チェックアウトブロックScript | 不適切なSKU組み合わせのカートを拒否 | Cart & Checkout Validation API |
|
10個のScriptを運用している場合、作成するFunctionは3〜5個程度に集約される傾向があります。複数のScriptは通常、分岐ロジックを整理して1つのFunctionに統合できます。

前提条件:ローカル開発環境の構築
Functionの作成を開始する前に、ローカル環境に以下の3つがインストールされていることを確認してください。ターミナルで各コマンドを実行してチェックします。
1. Node.js 18+
node --version # 18.0.0以上である必要があります
バージョンが古い場合は、nvmを使用するか、nodejs.orgからダウンロードしてインストールしてください。
2. Shopify CLI 3+
npm install -g @shopify/cli@latest shopify version # 3.x以上のバージョンが出力されることを確認します
3. Rustツールチェーン(RustでFunctionを記述する場合のみ)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add wasm32-wasip1 cargo --version
JavaScriptでFunctionを書く場合、Rustは不要です。チームで記述言語を統一することを推奨します。両方を混在させるとメンテナンスコストが増大します。
4. 開発用ストア
パートナーダッシュボードにログインして新しい開発用ストアを作成するか、既存のストアを使用します。本番環境に適用する前に、まずこの開発ストアにFunctionをデプロイします。
最初のFunctionの作成
CLIがボイラープレートの大部分を生成します。任意のディレクトリ内で以下を実行します。
# 新しいShopifyアプリを作成(既存のアプリがある場合はスキップ) shopify app init my-checkout-functions cd my-checkout-functions # Function拡張機能を生成 shopify app generate extension
CLIプロンプトに従って選択していきます。割引Functionの場合、以下の構成を選択します。
タイプ: Function
テンプレート:
discount(またはcart_checkout_validation,delivery_customization,payment_customizationなど)言語: Rust または JavaScript
名称:
volume-discount-fnなど
これにより、以下の構成で extensions/volume-discount-fn/ が作成されます。
extensions/volume-discount-fn/ ├── shopify.extension.toml # Function設定(ターゲット、ビルド、バージョン) ├── src/ │ ├── cart_lines_discounts_generate_run.graphql # 入力クエリ │ └── cart_lines_discounts_generate_run.rs # Functionロジック ├── Cargo.toml # Rust依存関係(Rustのみ) └── README.md
編集頻度が高いのは、.toml(設定)、.graphql(入力)、および.rs / .js(ロジック)の3つのファイルです。
チュートリアル 1:Line Item Scriptの代替(ボリュームディスカウント)
特定のコレクションがカート内に5点以上ある場合、注文小計から10%割引する従来のScriptを、Functionに移植する例を紹介します。
ステップ 1.1: 構成設定 (shopify.extension.toml)
api_version = "2026-01" [[extensions]] name = "volume-discount-fn" handle = "volume-discount-fn" type = "function" [[extensions.targeting]] target = "cart.lines.discounts.generate.run" input_query = "src/cart_lines_discounts_generate_run.graphql" export = "cart_lines_discounts_generate_run" [extensions.build] command = "cargo build --target=wasm32-wasip1 --release" path = "target/wasm32-wasip1/release/volume-discount-fn.wasm" watch = ["src/**/*.rs"]
ステップ 1.2: 入力クエリ (src/cart_lines_discounts_generate_run.graphql)
query Input { cart { lines { id quantity cost { subtotalAmount { amount } } merchandise { ... on ProductVariant { product { inAnyCollection(ids: ["gid://shopify/Collection/123456789"]) } } } } } discount { discountClasses } }
ヒント: Functionsはクエリされたデータのみを参照します。GraphQLクエリは最小限に抑えてください。不要なフィールドを除外することで、処理性能が向上します。
ステップ 1.3: ロジック記述 (src/cart_lines_discounts_generate_run.rs)
use super::schema; use shopify_function::prelude::*; use shopify_function::Result; #[shopify_function] fn cart_lines_discounts_generate_run( input: schema::cart_lines_discounts_generate_run::Input, ) -> Result<schema::CartLinesDiscountsGenerateRunResult> { // 割引区分が一致しない場合は処理を終了 let has_order_discount = input .discount() .discount_classes() .contains(&schema::DiscountClass::Order); if !has_order_discount { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 対象コレクション内アイテムの数量を合計 let qualifying_qty: i64 = input .cart() .lines() .iter() .filter(|line| { if let schema::Merchandise::ProductVariant(v) = line.merchandise() { *v.product().in_any_collection() } else { false } }) .map(|line| *line.quantity()) .sum(); if qualifying_qty < 5 { return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] }); } // 注文小計に10%割引を適用 Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![schema::CartOperation::OrderDiscountsAdd( schema::OrderDiscountsAddOperation { selection_strategy: schema::OrderDiscountSelectionStrategy::First, candidates: vec![schema::OrderDiscountCandidate { targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal( schema::OrderSubtotalTarget { excluded_cart_line_ids: vec![], }, )], message: Some("Volume discount: 10% off".to_string()), value: schema::OrderDiscountCandidateValue::Percentage( schema::Percentage { value: Decimal(10.0) } ), conditions: None, associated_discount_code: None, }], }, )], }) }
ステップ 1.4: テスト・デプロイ・有効化
# ホットリロードを有効にしてローカル開発を開始 shopify app dev # 準備ができたらデプロイを実行 shopify app deploy # 起動したGraphiQLパネル(開発ターミナルで `g` を入力)で、 # 作成したFunctionを使用する自動割引を作成します
mutation { discountAutomaticAppCreate( automaticAppDiscount: { title: "Volume Discount (5+ collection items)" functionHandle: "volume-discount-fn" discountClasses: [ORDER] startsAt: "2026-04-16T00:00:00Z" } ) { automaticAppDiscount { discountId } userErrors { field message } } }
これで完了です。Functionが本番稼働し、バージョン管理され、旧Scriptが完全に置き換わりました。
チュートリアル 2:Shipping Scriptの代替(一定金額以上の特定配送法の非表示)
「高額な即日配送コストを避けるため、カート小計が500ドルを超える場合は速達配送(Express)を非表示にする」という一般的なScriptを、Delivery Customization Functionで再現します。
ステップ 2.1: 拡張機能の生成
shopify app generate extension --template delivery_customization --name hide-express-fn
ステップ 2.2: 入力クエリ (src/run.graphql)
query Input { cart { cost { subtotalAmount { amount } } deliveryGroups { deliveryOptions { handle title } } } }
ステップ 2.3: ロジック記述 (src/run.js — JavaScript版)
// @ts-check /** * @typedef {import("../generated/api").RunInput} RunInput * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult */ const NO_CHANGES = { operations: [] }; const THRESHOLD = 500.0; const HIDE_TITLES = ["Express", "Overnight"]; /** * @param {RunInput} input * @returns {FunctionRunResult} */ export function run(input) { const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount); if (subtotal < THRESHOLD) return NO_CHANGES; const operations = input.cart.deliveryGroups.flatMap((group) => group.deliveryOptions .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t))) .map((opt) => ({ hide: { deliveryOptionHandle: opt.handle }, })) ); return { operations }; }
ステップ 2.4: 管理画面での有効化(GraphQL不要)
配送カスタマイズは、管理画面上にUIが自動提供されます。shopify app deploy実行後の手順:
設定 → 配送と配達 に移動します
下部の カスタマイズ セクションまでスクロールします
カスタマイズを追加 → 作成したFunctionを選択します
保存します
これで、本番環境で非表示ルールが適用されます。追加のGraphQLミューテーションは不要です。

チュートリアル 3:Payment Scriptの代替(B2B顧客向け代金引換の非表示)
「顧客タグに 'B2B' が設定されている場合、代金引換(Cash on Delivery)を非表示にする」ロジックを、Payment Customization Functionで実装します。
ステップ 3.1: 拡張機能の生成
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
ステップ 3.2: 入力クエリの作成
query Input { cart { buyerIdentity { customer { hasTags(tags: [{ tag: "B2B" }]) { tag hasTag } } } } paymentMethods { id name } }
ステップ 3.3: ロジック記述 (src/run.js)
const NO_CHANGES = { operations: [] }; export function run(input) { const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0]; const isB2B = tagCheck?.hasTag === true; if (!isB2B) return NO_CHANGES; const codMethod = input.paymentMethods.find((pm) => pm.name.toLowerCase().includes("cash on delivery") ); if (!codMethod) return NO_CHANGES; return { operations: [{ hide: { paymentMethodId: codMethod.id } }], }; }
ステップ 3.4: 有効化
決済カスタマイズも 設定 → 決済 → カスタマイズ に管理画面UIが用意されています。配送と同様に、作成したFunctionを選択して保存すれば完了です。
ここで重要:購入後処理(Post-Purchase)に関する補足
本稿が Revize ブログに掲載されていることに関連し、重要な点を補足します。Revizeは、現在のFunctionsがカバーできない領域、すなわち「注文完了後の処理」を担います。注文確定後にお客様がアイテムを追加したり、サイズを変更したり、配送先住所の間違いを修正したり、適用し忘れた割引コードを追加したいといった要望が発生します。Functionsの稼働範囲はチェックアウト時までであり、Revizeはチェックアウト後の処理に対応します。 Functionsが「カートで何を許可するか」を決定するのに対し、Revizeは返金や注文再作成の手間をかけずに、購入後にお客様やサポートチームが注文内容を直接編集できる仕組みを提供します。これは、手動編集が困難な大量注文を処理するPlusマーカーや、顧客体験を重視し「注文確定後の変更は承れません」という定型対応を避けたいD2Cブランドにとって不可欠な機能です。
ScriptsからFunctionsへの移行計画が完了していても、購入後の注文編集プロセスが考慮されていない場合、運用開始後にボトルネックが発生します。公開中の注文管理ガイドでは、チェックアウト後の注文管理ワークフローについて解説しています。
移行プロセスの解説に戻ります。
テスト戦略:検証用タグパターンの活用
Functionsには管理画面でワンクリックで切り替えられる「下書きモード」が存在しません。実務的な推奨アプローチは、特定の顧客タグによって新しいFunctionの処理判定をゲートし、旧Scriptと新Functionを並行稼働させて動作検証を行い、同一の結果を確認した段階で完全に切り替える方法です。
ステップ 1: テストユーザーへのタグ付与
顧客管理画面で、検証に使用する社内アカウント等に FN-TESTER タグを付与します。
ステップ 2: タグの有無による条件分岐の追加
// run関数の先頭部分に追加 let is_tester = input .cart() .buyer_identity() .and_then(|bi| bi.customer()) .map(|c| c.has_any_tag()) .unwrap_or(&false); if !*is_tester { return Ok(default_result); // タグがない場合は処理を実行せず、既存のScriptに委ねる } // 新しいFunctionの処理をここに記述(テストユーザーにのみ適用)
ステップ 3: 入力クエリに hasAnyTag を追加
cart { buyerIdentity { customer { hasAnyTag(tags: ["FN-TESTER"]) } } }
ステップ 4: チェックアウト画面での検証
タグ付きユーザーとしてログインし、チェックアウトを進め、Functionが正しく動作することを確認します。タグのないユーザーでログインし、旧Scriptが従来通り実行されることを確認します。数日間安定稼働が確認できたら、タグ判定ロジックを削除して全ユーザーに公開します。
ステップ 5: 旧Scriptの無効化
アプリ管理 → Script Editor → [対象のScript] → 公開停止 を実行します。公開停止により、該当ロジックの制御は新しいFunctionへ完全に移行されます。
実用的なデプロイワークフローの構築
デベロッパーのローカル環境から手動でデプロイし続ける運用は推奨されません。最初の数件の移行を完了したら、CIパイプラインを構築しましょう。
最小構成のGitHub Actions例
# .github/workflows/deploy-functions.yml name: Deploy Shopify Functions on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - uses: dtolnay/rust-toolchain@stable with: { targets: wasm32-wasip1 } - run: npm install -g @shopify/cli@latest - run: shopify app deploy --force env: SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
パートナーダッシュボードの 設定 → トークン からパートナーAPIトークンを生成し、GitHubのSecretに設定します。これにより、main ブランチへのマージをトリガーにFunctionが自動デプロイされる体制が整います。
バージョン管理とロールバック
shopify app deploy はバージョン履歴を保存します。以前のバージョンに戻す手順は以下の通りです。
shopify app versions list shopify app release --version <previous-version-id
Scripts時代の「旧コードを手動でエディタにコピー&ペーストして戻す」といった属人的な運用から、完全な構成管理へと進化します。

移行時に陥りがちな典型的な間違い
Plusマーチャントの移行を支援する中で、頻発する5つの共通の誤りを紹介します。
1. Scriptsのコードを1対1で直訳しようとする: FunctionsはScriptsと設計が異なります。1つのFunction内で条件分岐を行い、複数のScriptをよりシンプルに統合することができます。移植前にシステム全体の構成を見直しましょう。
2. 必要なAPIアクセス権限(scopes)の不足: 多くのFunctionは、read_customers、read_orders、write_discounts などの権限を要求します。これらを shopify.app.toml の scopes に追加し、アプリを再認証してください。不足している場合、入力クエリはnullを返します。
3. 並行検証なしの全ユーザー公開: コードに問題がないように見えても、カート内が空、ギフトカード併用、ストアクレジット適用、B2B下書き注文などのエッジケースで問題が顕在化します。タグ付き検証を2日間挟むだけで、本番障害を回避できます。
4. カスタマイズレポートの未確認: 管理画面で出力できるレポートは、現在稼働している全ロジックの最良のチェックリストです。記憶に頼らず、レポートをベースに移行を進めてください。
5. コレクションIDや顧客タグのハードコーディング: 運用側で条件値を頻繁に変更する必要がある場合は、メタフィールドを利用したFunction構成を導入してください。CLIを使用してメタフィールド連携構成を生成できます。詳細はShopify公式ドキュメントを参照してください。
移行に向けたタイムラインの設計(残り75日想定)
6月30日に余裕を持って間に合わせるための標準的な移行ロードマップです。
週 | 実施タスク |
|---|---|
第1週(今週) | カスタマイズレポートをダウンロードし、現在動いているすべてのScriptを把握。Function移行、既存公開アプリへの代替、または廃止を個別に決定。 |
第2〜3週 | ローカル開発環境のセットアップ。最初のFunction作成。最もシンプルなScript(決済非表示ルールなど)の移行から着手。 |
第4〜6週 | 割引ロジックの移行に着手。Discounts APIは仕様が多岐にわたるため、最も時間を要します。テスト用タグを用いて検証を実施。 |
第7〜8週 | 配送/配達ロジックの移行。配送カスタマイズFunctionをデプロイし、管理画面から有効化。 |
第9〜10週 | CIパイプライン(GitHub Actionsなど)の構築。手動デプロイからの脱却。 |
第11週 (6月中旬) | 既存の全Scriptを非公開化。Function単独でストアを2週間稼働させ、挙動を最終確認。 |
6月30日 | Scriptsサポート終了。先行して切り替えが完了しているため影響なし。 |
今すぐ開始すれば、想定外のバグに対するバッファが確保できます。6月に入ってからの着手では十分な検証が困難になります。

よくある質問(FAQ)
Functionsの利用にはShopify Plusプランが必要ですか?
独自に開発したカスタムFunctionを利用するにはShopify Plusが必要ですが、Shopifyアプリストアで公開されている一般的なアプリ経由であれば、すべてのプランでFunctionsを利用できます。 Plus以外のマーチャントの場合、アプリストアから対象のFunction機能を提供するパブリックアプリをインストールするか、PlusへアップグレードしてカスタムFunctionを作成するかの選択となります。Scriptsを利用していたマーチャントは原則すでにPlusを契約しているため、影響は軽微です。
TypeScriptでFunctionを開発することはできますか?
はい、TypeScriptは公式にサポートされており、CLIによるコード自動生成が可能です。 shopify app generate extension で 「JavaScript」を選択して生成すると、プロジェクトには自動的に import("../generated/api") などの型定義が含まれます。必要に応じて .ts への拡張子変更および tsconfig.json の構成を行ってください。最終的に出力されるコンパイル済みファイル(WASM)の実行性能に言語間の差はありません。
従来のScriptsと比較して、Functionsの処理速度はどうですか?
通常5ms未満で実行され、従来のRubyベースのScriptsよりも圧倒的に高速です。 FunctionsはWebAssemblyにコンパイルされ専用のランタイムで動作するため、Shopifyは5msの実行制限時間を設けています。この制限時間を超えた場合、そのFunctionはスキップされ処理は適用されません。通常、適切に設計されたコードであれば1〜2msで処理が完了します。性能面での上限はScriptsに比べて大幅に向上しています。
Function内部から外部のAPIを呼び出すことは可能ですか?
いいえ、Functions内から外部ネットワークへのリクエスト(APIコール)は行えません。 セキュリティとパフォーマンスを担保するため、Functionは純粋なデータ処理(入力データに基づく出力を定義する)に限定されています。外部システムの情報(CRMデータ、動的な在庫連携など)が必要な場合は、あらかじめそのデータをメタフィールド等に書き出しておくか、App ProxyやWebhook、バックエンド処理と連携するCart Transformなど別の手法を用いて設計を行う必要があります。
Cart Transform API と Discounts API の違いは何ですか?
Discounts APIは金額の割り引き処理を担当し、Cart Transform APIはカートの中身(ラインアイテム自体)の変更を担当します。 10%引き、送料無料、BOGO(Buy One Get One)の適用にはDiscounts APIを使用します。2つの商品をカート内で自動的に1つのバンドル商品にまとめたり、特定のバリアントを複数のラインアイテムに分割したりする場合はCart Transformを使用します。一部の古いScriptは両方の処理を1つで行っていましたが、移行時は役割ごとに別々のFunctionへ分割して実装する必要があります。
開発ストアを使わずに、ローカル環境だけでFunctionをテストする方法はありますか?
cargo test(Rust)や npm test(JavaScript)による単体テスト(ユニットテスト)はローカル環境で完結しますが、チェックアウトを含めた全体的な疎通確認には開発ストアでのテストが不可欠です。 CLIツールには、ダミーの入力ファイルを用いてFunctionを実行する shopify app function run コマンドが用意されており、ローカルでの素早いロジック修正に役立ちます。ただし、最終的なカートでの振る舞いを検証するためには実環境が必要です。
同じタイプのFunctionを複数同時に有効化できますか?
はい、同じターゲットに対して複数のFunctionをデプロイし、設定順序に従って決定論的に連続実行させることが可能です。 割引に関しては、Shopifyの割引スタックルールが適用されます。配送や決済のカスタマイズにおいては、各Functionの出力データが次のFunctionに連携される形でチェーン実行されます。設計をシンプルに保つため、多くの開発チームは対象タイプごとにFunctionを1つに集約するアプローチをとっています。
Functionのデプロイ後、既存のScriptはどうなりますか?
Script Editorアプリから明示的に非公開にするまで、双方のロジックが並行して実行されます。 これにより本番環境での安全な並行テスト運用が可能です。新ロジックの安定動作を確認した後に、手動で旧Scriptを非公開に切り替えてください。なお、2026年6月30日を過ぎると、公開状態であってもすべてのScriptの実行がShopify側で強制停止されます。
この移行によってSEOやストアテーマに影響はありますか?
いいえ、ありません。Functionsはチェックアウト時のサーバーサイドで実行されるため、フロントエンドのテーマファイルや製品ページ、SEO構造を損なうことはありません。 変更が加わるのはチェックアウト内の割引、配送オプション、決済方法に限定されています。
旧Scriptで Input.line_items のカスタム属性を利用していた場合、どのように移行すればよいですか?
カートのラインアイテム(cart lines)の attribute フィールドから、GraphQL経由でカスタム属性を取得できます。 入力クエリ(GraphQL)の lines 内に attribute(key: "your-key") { value } を定義してください。Function内では、従来のRubyによるプロパティ参照とほぼ同様の手順でカスタム属性を利用して判定ロジックを組むことができます。
分析データや注文タグ(Order Tags)の付与をFunction側で行えますか?
いいえ、Functions自体は注文タグの書き込みやWebhookのトリガーを発行することはできません。現カートに対する変更操作の配列を返すのみの役割を持ちます。 注文完了後のタグ付与や他システムへの連携は、注文作成イベント(Order Creation)をトリガーとする Shopify Flow などを利用して実装してください。一般的な手法として、割引処理をFunctionで行い、その割引適用の履歴を検知したShopify Flowによって「VOLUME-DISCOUNT-APPLIED」といった注文タグを付与する組み合わせが用いられます。
カスタム開発をせず、既存の公開アプリで代替することは可能ですか?
はい、Shopifyアプリストアには、一般的なユースケースをカバーするFunctionsベースのアプリが多数提供されています。 「discount function」「delivery customization」「payment customization」などのキーワードで検索してください。段階的な割引、タグによる特定の決済方法の除外、特定金額以上の配送制限など、一般的な要件であれば既存のSaaSツールを使用することで、自社でのコード開発・保守コストを大幅に削減できます。独自の高度なロジックを要する場合に限定して、独自カスタムFunctionの開発を選択することを強く推奨します。
6月30日の期限に移行が間に合わなかった場合、どうなりますか?
該当のScriptの実行は完全に停止します。代替手段による救済、猶予期間、期限の延長は一切ありません。 割引、特定の配送レートの制御、決済方法の制限など、それまでScriptで処理されていたすべての機能が、世界協定時(UTC)の7月1日午前0時に無効化され、標準の挙動に戻ります。ビジネスに不可欠なロジックがある場合は、移行期限よりも大幅に前倒しした稼働スケジュールを設定してください。一般的に、並行テストを含めると移行期間は予想以上に長引きます。
移行後、Script Editorアプリはストアから削除しても構いませんか?
移行が完全に終了している場合はアンインストールして問題ありません。 6月30日以降、同アプリは機能しなくなります。すべての処理が新構成のFunctionに移行し、安定稼働が確認された時点でアプリを削除してください。Functionの稼働環境は独立しているため、アプリの削除による影響はありません。
今週取り組むべきアクション
この記事を読み終えたら、以下の4つのステップを最初の7日間で実行してください。
1. カスタマイズレポートの取得: 設定 → チェックアウト → カスタマイズレポート からレポートを出力し、タスクをリストアップします。これが移行作業のバックログになります。
2. 開発環境の確認: Node 18+、Shopify CLI、Rust(必要な場合)をインストールし、shopify version が動作することを確認します。所要時間は約30分です。
3. 開発ストアへのテスト実装: 決済方法の非表示など、最もシンプルな構成のFunctionを1つ作成し、開発ストアへデプロイします。本番への適用可否に関わらず、これによって一連のデプロイ・開発フローの動作が実証されます。
4. 今後8週間の作業時間の確保: 移行作業を他タスクの隙間時間で行うのは困難です。毎週火曜日と木曜日の午後など、スケジュールに固定枠を確保し、優先プロジェクトとして管理してください。
これまでのPlusマーチャントの移行パターンを見ると、環境調査と計画決定に2週間、コード開発に3週間、最終検証と微調整に1週間を要しています(計6週間)。現在、終了まで10週間の猶予があるならば、その余裕分をコードレビューとQA(品質管理)に充て、遅滞なく進めてください。
チェックアウトロジックが片付いた後、多くのマーチャントが次に取り組むのが「購入後処理」の最適化です(注文確定後の住所変更、商品の入れ替え、割引の適用漏れ対応)。もしこれらが今後のロードマップに含まれているならば(トランザクション数の多いPlusストアや顧客体験を重視するストアでは不可欠な項目です)、Shopifyアプリストアで提供されているRevizeが、ここで構築するFunctionsと並行してその解決をサポートします。
関連リソース
関連記事
2026年8月更新。 Revizeは、配送先住所の変更、商品の交換、注文キャンセル、返金、ストアクレジットの付与などを、出荷完了前であればサポートに問い合わせることなく、顧客自身で行えるようにするShopifyアプリです。詳細については、購入後の注文変更機能の導入を参照するか、ShopifyアプリストアでRevizeを確認してください。
RevizeでShopifyストアを刷新しましょう。顧客体験を軸にリードする。
© 著作権 2024、無断転載を禁じます
RevizeでShopifyストアを刷新しましょう。顧客体験を軸にリードする。
© 著作権 2024、無断転載を禁じます
RevizeでShopifyストアを刷新しましょう。顧客体験を軸にリードする。
© 著作権 2024、無断転載を禁じます
RevizeでShopifyストアを刷新しましょう。顧客体験を軸にリードする。
© 著作権 2024、無断転載を禁じます



