mcpField
S
shopify-checkout-extensions

shopify-checkout-extensions

github.com/finsilabs開発6079 回インストール6 日前に更新
リポジトリ

shopify-checkout-extensions について

Shopifyアプリ開発者向けに、チェックアウトUIブロックとShopify Functionsによるバックエンドルールの実装を案内するガイドです。非推奨の`checkout.liquid`カスタマイズに代わる方法として、構築、設定、テスト、デプロイを扱います。

主な機能

  1. 01Checkout UI拡張の生成
  2. 02Shopify Functionsによるルール実装
  3. 03拡張ターゲットと設定の構成
  4. 04拡張のローカルプレビューとデプロイ
  5. 05チェックアウトのサンドボックスと実行制限への対応

活用シーン

  1. 01チェックアウトにギフトメッセージ欄を追加
  2. 02カート内容に応じて配送方法を絞り込む
  3. 03注文に独自の割引ルールを適用
  4. 04チェックアウト完了前に注文内容を検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill shopify-checkout-extensions

インストール後、Claude Code で/shopify-checkout-extensionsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

tile.json
evals/checkout-metafield-persistence-with-ui-e/
criteria.json
task.md
evals/configurable-ui-extension-with-settings-/
criteria.json
task.md
evals/shopify-function-configuration-and-wasm-/
criteria.json
task.md

詳細

Shopify チェックアウト拡張機能

概要

Shopify チェックアウト拡張機能を使うと、チェックアウトテンプレートをフォークせずに、Shopify のチェックアウト内にアプリのカスタム UI ブロックを表示できます。Shopify Functions を使うと、割引、配送、決済方法、注文の検証といったバックエンドロジックを、Shopify のインフラストラクチャ内で実行されるカスタム WebAssembly モジュールに置き換えられます。これらを組み合わせることで、非推奨となった checkout.liquid によるカスタマイズ方法を置き換え、Shopify Plus とそれ以外のストア(UI 拡張機能)、または Shopify Plus のストアのみ(一部の Functions ターゲット)で利用できます。

このスキルを使用する場面

  • チェックアウトにカスタム UI ブロック(アップセル、信頼性バッジ、ギフトメッセージ欄、保証オプションなど)を追加するとき
  • Shopify 標準の割引ルールを超えるカスタム割引ロジック(段階的な割引、B2B 価格設定など)を実装するとき
  • カートの内容に基づいて、カスタムの配送方法のフィルタリングや名称変更を行うとき
  • 特定の顧客に対して決済方法を非表示にしたり、名称を変更したりするカスタム決済機能を構築するとき
  • チェックアウト完了前に注文内容を検証するとき(数量制限、地域制限など)
  • Shopify Plus ストアで非推奨となった checkout.liquid のカスタマイズを置き換えるとき

基本的な手順

  1. Shopify CLI で拡張機能のひな形を作成する

    # Inside an existing Shopify app directory
    shopify app generate extension
    # Choose: Checkout UI extension OR Shopify Function
    # Name: my-checkout-extension
    

    これにより、src/index.tsx(UI)または src/index.ts(Function)を含む extensions/my-checkout-extension/ ディレクトリが作成されます。

  2. チェックアウト UI 拡張機能を構築する

    チェックアウト UI 拡張機能では、@shopify/ui-extensions-react/checkout の React に似たコンポーネント API を使用します。

    // extensions/order-upsell/src/index.tsx
    import {
      reactExtension,
      useCartLines,
      useApplyCartLinesChange,
      useSettings,
      BlockStack,
      Button,
      Image,
      Text,
      InlineStack,
      Divider,
    } from "@shopify/ui-extensions-react/checkout";
    
    const CheckoutBlock = reactExtension(
      "purchase.checkout.block.render",
      () => <OrderUpsell />
    );
    export { CheckoutBlock };
    
    function OrderUpsell() {
      const cartLines = useCartLines();
      const applyCartLinesChange = useApplyCartLinesChange();
      const { upsell_variant_id: upsellVariantId } = useSettings();
    
      // Only show upsell if a variant is configured and cart doesn't already contain it
      if (!upsellVariantId) return null;
    
      const alreadyInCart = cartLines.some(
        (line) => line.merchandise.id === upsellVariantId
      );
    
      if (alreadyInCart) return null;
    
      const handleAddUpsell = async () => {
        await applyCartLinesChange({
          type: "addCartLine",
          merchandiseId: upsellVariantId,
          quantity: 1,
        });
      };
    
      return (
        <BlockStack spacing="base">
          <Divider />
          <InlineStack blockAlignment="center" spacing="base">
            <Image source="https://cdn.shopify.com/s/files/..." aspectRatio={1} />
            <BlockStack>
              <Text emphasis="bold">Add a gift bag for $3.99</Text>
              <Text appearance="subdued">Beautiful packaging for your order</Text>
            </BlockStack>
            <Button onPress={handleAddUpsell}>Add</Button>
          </InlineStack>
        </BlockStack>
      );
    }
    
  3. shopify.extension.toml で拡張機能を設定する

    api_version = "2025-01"
    
    [[extensions]]
    type = "ui_extension"
    name = "Order Upsell"
    handle = "order-upsell"
    
    [[extensions.targeting]]
    module = "./src/index.tsx"
    target = "purchase.checkout.block.render"
    
    [extensions.settings]
    [[extensions.settings.fields]]
    key = "upsell_variant_id"
    type = "variant_reference"
    name = "Upsell Product Variant"
    
  4. カスタム割引用の Shopify Function を構築する

    Shopify Functions は WebAssembly にコンパイルされます。Rust または JavaScript を使用します。

    // extensions/volume-discount/src/index.ts
    import type {
      RunInput,
      FunctionRunResult,
      CartLineInput,
    } from "../generated/api";
    
    const NO_CHANGES: FunctionRunResult = { discounts: [], discountApplicationStrategy: "FIRST" };
    
    export function run(input: RunInput): FunctionRunResult {
      const { cart } = input;
    
      // Calculate total quantity across all lines
      const totalQuantity = cart.lines.reduce(
        (sum, line) => sum + line.quantity,
        0
      );
    
      // Tiered volume discount
      let discountPercent = 0;
      if (totalQuantity >= 20) discountPercent = 20;
      else if (totalQuantity >= 10) discountPercent = 10;
      else if (totalQuantity >= 5) discountPercent = 5;
    
      if (discountPercent === 0) return NO_CHANGES;
    
      return {
        discounts: [
          {
            value: {
              percentage: { value: discountPercent.toString() },
            },
            targets: [{ orderSubtotal: { excludedVariantIds: [] } }],
            message: `${discountPercent}% volume discount (${totalQuantity} items)`,
          },
        ],
        discountApplicationStrategy: "FIRST",
      };
    }
    

    Function の shopify.extension.toml:

    api_version = "2025-01"
    
    [[extensions]]
    type = "function"
    name = "Volume Discount"
    handle = "volume-discount"
    runtime = "javascript"
    
    [[extensions.input.variables]]
    name = "cart"
    type = "Cart"
    
    [extensions.build]
    command = "npm run build"
    path = "dist/index.wasm"
    
  5. 拡張機能をテストしてデプロイする

    # Run local dev preview (UI extension hot-reloads in checkout)
    shopify app dev
    # Open the checkout preview URL shown in terminal
    
    # Deploy all extensions to Shopify
    shopify app deploy
    

    デプロイ後、管理画面で[チェックアウト]→[カスタマイズ]に移動し、チェックアウトテンプレートに UI 拡張機能のブロックを追加します。Functions は、管理画面の[割引]からその Function を使った割引を作成すると有効になります。

例

useApplyMetafieldsChange を使ったギフトメッセージ欄
import {
  reactExtension,
  TextField,
  useApplyMetafieldsChange,
  useMetafield,
  BlockStack,
  Text,
} from "@shopify/ui-extensions-react/checkout";

export default reactExtension(
  "purchase.checkout.shipping-option-list.render-after",
  () => <GiftMessage />
);

function GiftMessage() {
  const giftMessage = useMetafield({ namespace: "custom", key: "gift_message" });
  const applyMetafieldsChange = useApplyMetafieldsChange();

  return (
    <BlockStack spacing="tight">
      <Text emphasis="bold">Gift message (optional)</Text>
      <TextField
        label="Message"
        value={giftMessage?.value ?? ""}
        multiline={3}
        onChange={(value) =>
          applyMetafieldsChange({
            type: "updateMetafield",
            namespace: "custom",
            key: "gift_message",
            valueType: "string",
            value,
          })
        }
      />
    </BlockStack>
  );
}
決済カスタマイズ Function(海外注文で代金引換を非表示にする)
// extensions/payment-customization/src/index.ts
import type { RunInput, FunctionRunResult } from "../generated/api";

export function run(input: RunInput): FunctionRunResult {
  const country = input.cart.buyerIdentity?.countryCode;

  // Hide "Cash on Delivery" for non-domestic orders
  const hideOperations = input.paymentMethods
    .filter((pm) => pm.name.toLowerCase().includes("cash on delivery") && country !== "US")
    .map((pm) => ({
      hide: { paymentMethodId: pm.id },
    }));

  return { operations: hideOperations };
}

ベストプラクティス

  • 配置の柔軟性を最大限に高めるには、purchase.checkout.block.render ターゲットを使用する。マーチャントはチェックアウトエディターでブロックを任意の位置にドラッグできます。
  • Function の実行時間を 5ms 未満に抑える。Shopify は実行時間に厳しい制限を設けています。Functions 内でのネットワーク呼び出しは避け、設定にはメタフィールドまたは Function の入力変数を使用します。
  • useSettings() フックを使って、拡張機能の設定スキーマでマーチャントが設定した値を読み取る。拡張機能のコードに ID をハードコードせずに済みます。
  • UI 拡張機能では DOM を読み取ったり、ブラウザー API を使用したりしない。これらは DOM にアクセスできないサンドボックス化された Worker 環境で実行されます。
  • @shopify/ui-extensions-react/checkout のコンポーネントのみを使用する。拡張機能のサンドボックスでは、ネイティブ HTML やその他の UI ライブラリは使用できません。
  • 決済および配送の Functions は、実際のチェックアウトセッションでテストする。ローカルの開発プレビューで動作するのは UI 拡張機能のみです。Functions のテストにはデプロイが必要です。
  • 拡張機能の API バージョンを固定する。新しい API を利用しつつ下位互換性を保てるよう、shopify.extension.toml の api_version を更新します。
  • 非同期処理では読み込み状態を表示する。useApplyCartLinesChange は非同期処理のため、変更処理中はスピナーを表示します。

よくある問題

問題解決策
チェックアウトエディターに拡張機能が表示されない拡張機能がデプロイされていること(shopify app deploy)と、Admin → Checkout で正しいチェックアウトテンプレートが選択されていることを確認してください
Function が FUNCTION_EXECUTION_TIMEOUT を返す設定を実行時のロジックから Function の入力メタフィールドに移してください。大規模なカタログに対する複雑なループは避けてください
カートの更新後に useCartLines が古いデータを返すカート行を再度読み込む前にチェックアウトの再評価を待つため、applyCartLinesChange が返す promise を使用してください
拡張機能が「Cannot use browser APIs」でクラッシュするdocument、window、localStorage の参照を削除してください。拡張機能は Worker サンドボックスで実行されます
Discount Function が適用されないAdmin → Discounts で Function ベースのディスカウントが有効になっていることと、顧客が適用資格の条件を満たしていることを確認してください
Checkout UI 拡張機能の設定が保存されない設定フィールドには、拡張機能のコード内で useSettings() が参照するキーと一致する handle 値が必要です

関連スキル

  • @shopify-app-development
  • @shopify-storefront-api
  • @shopify-metafields
  • @checkout-flow-optimization
  • @shopify-admin-api

コメント