
Shopifyには標準でディスカウントコードを設定する機能があります。例えば、商品割引や注文割引、送料割引が設定できます。最近では「Xを買うとYをプレゼント」といったニーズにも対応できるようになりました。しかし、Shopifyのディスカウント機能は、特定のニッチなニーズまで柔軟に対応することが難しい場合があります。
そこで、Shopify Discount Functionを使って、特定のニーズに合わせたディスカウントを実現する方法を解説します。
Shopify Discount Functionとは
Shopify discount extensionとは、Shopify Functionsを使ってカスタムの割引ロジックを実装できる拡張機能です。通常のディスカウントコード設定ではできない、細かい購入条件や顧客属性などに基づく割引の適用を実現できる点が大きな特徴です。
具体的には、Shopifyのチェックアウト時にバックエンドロジックを挟み込み、カート内容(商品や数量、価格など)を動的に検証して割引を計算・適用します。たとえば「特定の商品タイプを◯点以上購入した場合のみ割引」「会員ランクがゴールド以上の顧客だけ追加の割引を適用」など、標準機能だけでは実現しづらい高度な割引設定を構築可能です。
Shopify Discount Functionの設定方法
今回は、特定の異なる商品タイプを購入した場合に割引を適用する例を紹介します。4月の引越しシーズンであれば、「家具」と「家電」の商品タイプを同時に購入すると、10%の割引を適用するというシチュエーションで実装してみましょう。
extensionの作成
Shopify Discount Functionうちの Order Discount Functionを作成します。以下のコードを実行して、新しいFunctionを作成します。
shopify app generate extension --template order_discounts --name order-discount --flavor typescript
これで、extensions/order-discount ディレクトリが作成され、Functionの雛形が生成されます。
入力データの定義
Functionが実行される際の注文データの入力データを定義します。作成したextensionのsrc/run.graphql
を編集して、入力データの定義を追加します。
query RunInput {
cart {
lines {
merchandise {
... on ProductVariant {
product {
productType
}
}
}
}
}
}
このようにカートの中に入っている商品アイテムの商品タイプを取得するようにgraphQLのフィールドを定義します。
編集後、extensinsionディレクトリで以下のコマンドを実行して、入力データの定義を反映します。
cd extensions/order-discount
shopify app function typegen
これで、入力データをtypescriptの型定義として生成することができます。
ロジックの実装
Functionのロジックを実装します。src/run.ts
を編集して、カート内の商品タイプをチェックして割引を適用するロジックを実装します。
import type {
RunInput,
FunctionRunResult,
ProductVariant,
} from "../generated/api";
import { DiscountApplicationStrategy } from "../generated/api";
// 定数定義
const EMPTY_DISCOUNT: FunctionRunResult = {
discountApplicationStrategy: DiscountApplicationStrategy.First,
discounts: [],
};
const DISCOUNT_PERCENTAGE = 10;
const DISCOUNT_TARGET_PRODUCT_TYPES = ["家具", "家電"];
const DISCOUNT_MESSAGE = "春の一人暮らしキャンペーンです。新しい生活を応援します!";
// 割引ロジックを関数化
function createDiscount(): FunctionRunResult {
return {
discountApplicationStrategy: DiscountApplicationStrategy.First,
discounts: [
{
message: DISCOUNT_MESSAGE,
targets: [
{
orderSubtotal: { // カートの合計金額に対する割引
excludedVariantIds: [], // 除外する商品はなし
},
},
],
value: {
percentage: {
value: DISCOUNT_PERCENTAGE,
},
},
},
],
};
}
// メインの関数
export function run(input: RunInput): FunctionRunResult {
// カート内の商品タイプを抽出
const productTypes = input.cart.lines.map(
(line) => (line.merchandise as ProductVariant).product.productType,
);
// 割引対象のすべてのタイプがカート内に含まれているか確認
const isDiscountTarget = DISCOUNT_TARGET_PRODUCT_TYPES.every((target) =>
productTypes.includes(target),
);
// 割引対象の場合は割引を適用、それ以外は空の割引を返す
return isDiscountTarget ? createDiscount() : EMPTY_DISCOUNT;
}
run関数には先ほど定義したinputデータが渡され、カート内の商品タイプを取得して割引を適用するかどうかを判定するロジックを実装します。今回は、カート内の商品タイプに「家具」と「家電」が含まれている場合に10%の割引を適用するように設定しています。
商品の設定
商品タイプが「家具」と「家電」の商品を作成します。管理画面から商品を作成し、商品タイプを「家具」または「家電」に設定します。
デプロイ
Functionのロジックを実装したら、Functionをデプロイします。以下のコマンドを実行して、Functionをデプロイします。
shopify app deploy
Functionの有効化
Functionはデプロイしただけでは実行されません。Functionを有効化するためには、Admin APIを使ってFunctionを有効化する必要があります。今回は自動でディスカウントが適用されるようにdiscountAutomaticAppCreate
mutationを使ってFunctionを有効化します。
先にfunctionのIDを取得します。functions queryを使ってFunctionのIDを取得します。GraphQLの実行はShopify GraphiQL Appを使えば管理画面からアプリを開いて簡単に実行できます。
query shopifyFunctions{
shopifyFunctions(first: 30){
edges {
node {
id
title
apiType
description
}
}
}
}
クエリを実行したら先ほど作成したFunctionがあることを確認して、IDをコピーします。
{
"node": {
"id": "5e61dede-e4d5-40d7-9a4d-7f7705d0b5e6",
"title": "注文の割引金額",
"apiType": "order_discounts",
"description": "カスタムのカートルールとお客様ルールに基づいた注文レベルのディスカウント。"
}
}
次に、Functionを有効化します。以下のmutationを実行してFunctionを有効化します。シーズンに合わせてキャンペーンの期間を設定すると良いでしょう。 また、今回は他のとのクーポンの併用を許可しないように設定しています。
mutation discountAutomaticAppCreate($automaticAppDiscount: DiscountAutomaticAppInput!) {
discountAutomaticAppCreate(automaticAppDiscount: $automaticAppDiscount) {
automaticAppDiscount {
discountId
title
startsAt
endsAt
status
}
userErrors {
field
message
}
}
}
# Variables
{
"automaticAppDiscount": {
"title": "春の一人暮らしキャンペーン",
"functionId": "9d9183a7-f307-49dd-8a4d-1b579ba06d62",
"combinesWith": {
"orderDiscounts": false,
"productDiscounts": false,
"shippingDiscounts": false
},
"startsAt": "2025-03-01T00:00:00Z",
"endsAt": "2025-04-30T23:59:59Z"
}
}
実行後の結果は以下のようになります。無事にFunctionが有効化されたことが確認できます。
{
"data": {
"discountAutomaticAppCreate": {
"automaticAppDiscount": {
"discountId": "gid://shopify/DiscountAutomaticNode/1096034746468",
"title": "春の一人暮らしキャンペーン",
"startsAt": "2025-03-01T00:00:00Z",
"endsAt": "2025-04-30T23:59:59Z",
"status": "SCHEDULED"
},
"userErrors": []
}
},
"extensions": {
"cost": {
"requestedQueryCost": 10,
"actualQueryCost": 10,
"throttleStatus": {
"maximumAvailable": 2000,
"currentlyAvailable": 1990,
"restoreRate": 100
}
}
}
}
管理画面のディスカウント一覧からもアプリディスカウントとして作成されていることが確認できます。こちらのディスカウントは来年の3月から適用されるのでステータスは「スケジュール済み」になっています。
埋め込みアプリやAdmin Blockを組み合わせて、管理画面からFunctionの設定を行うことも可能で、後日blogにてご紹介する予定です。
動作確認
ディスカウントの開始日を迎えたら、カートに「家具」と「家電」の商品を追加してチェックアウトすると、10%の割引が適用されることを確認します。
きちんと注文合計の10%である100円が割引されていることが確認できました。
運用のポイント
- テストを書いて要件通りの条件で割引が適用されることを確認しましょう。
- 動作確認で失敗していたらパートナーダッシュボードからログを確認してエラーの原因を特定しましょう。
- 実際は他のクーポンとの併用を許可するかどうか、割引の適用条件や割引率などを検討して設定しましょう。
まとめ
Shopify Discount Functionを使えば、特定のニーズに合わせたディスカウントを柔軟に設定できます。今回は、異なる商品タイプを購入した場合に割引を適用する例を紹介しましたが、他にも様々な割引設定が可能です。ぜひ、自社のビジネスニーズに合わせてカスタムディスカウントを設定してみてください。