> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# カスタムコードブロック

> Aftersell CartのCustom codeブロック：独自のHTMLやReactをドロワー内の任意の場所（Cart items内を含む）に追加できます。

> **Custom code**ブロックは、独自のHTMLまたはReactをカートに追加します。ドロワーの任意のセクションに配置するか、[**Cart items**](/ja/aftersell/cart/cart-items-block)内にサブブロックとしてネストして、各ラインごとに繰り返し表示させることができます。他のブロックとは異なり、Content設定もDesignセクションもありません。ブロック自体がコード\_そのもの\_なので、作業はすべて**Code**タブで行います。

<Frame>
  <img src="https://mintcdn.com/aftersell/1Y3gBpUfxv16VGSW/images/aftersell/cart-custom-code-block-add-and-enable.gif?s=6717cc64a8765b0c06b65990f99e12ff" alt="Aftersell CartエディターでCustom codeブロックを追加して有効にするアニメーションプレビュー" title="Aftersell CartエディターでCustom codeブロックを追加して有効にするアニメーションプレビュー" width="1200" height="558" data-path="images/aftersell/cart-custom-code-block-add-and-enable.gif" />
</Frame>

<div id="add-and-turn-on-a-custom-code-block">
  ## カスタムコードブロックを追加して有効にする
</div>

1. **Custom code**ブロックを任意のセクションに、または**Cart items**の下のサブブロックとして追加します。
2. ブロックを選択して**Code**タブを開きます。
3. **HTML**または**React component**を選択します。新しいブロックのデフォルトはHTMLです。
4. コードを書きます。
5. Reactを選択した場合は、<span style={{display:'inline-flex',alignItems:'center',gap:'4px',background:'#1C1C1C',color:'#fff',border:'1px solid #0A0A0A',borderRadius:'4px',padding:'0 6px',fontSize:'0.85em',fontWeight:500,lineHeight:'1.4em',verticalAlign:'middle'}}><svg width="8" height="9" viewBox="0 0 10 12" fill="none" aria-hidden="true" style={{display:'block'}}><path d="M1.5 1.2v9.6L8.8 6 1.5 1.2Z" stroke="#fff" strokeWidth="1.5" strokeLinejoin="round" /></svg>Compile</span>をクリックします。
6. \*\*「Use custom template」\*\*をオンにします。このブロックでは、このスイッチは「カスタムコードを表示する」を意味し、デフォルトはオフなので、有効にするまで何もレンダリングされません。
7. ブロックが購入者に表示され続けるよう、サイドバーの目のトグルをオンのままにしてください。

ブロックを表示するには、目のトグルと\*\*「Use custom template」\*\*の両方がオンになっている必要があります。

<div id="behavior">
  ## 動作
</div>

* カートの読み込みが完了するまで、このブロックは何もレンダリングしません。
* また、サイドバーの目のアイコンがオフの場合、\*\*「Use custom template」\*\*がオフの場合、コードが空の場合、またはReactのコンパイルやレンダリングが失敗した場合も何もレンダリングされません。失敗は静かに起こるため、公開前に[プレビュー](/ja/aftersell/cart/previewing-carts)でブロックを確認してください。

<div id="html-mode">
  ## HTMLモード
</div>

HTMLモードでは、少数のトークンがマークアップに置き換えられます。静的またはトークン駆動のコンテンツ向けであり、ロジックの実行には向いていません。

* **インラインの`<script>`タグは実行されず**、HTMLモードは**SDKや`window`にアクセスできません。**
* ロジックが必要な場合は、[**Reactモード**](#react-mode)、または[Cart SDK](/ja/aftersell/cart/sdk-overview)と組み合わせた[カスタムスクリプト](/ja/aftersell/cart/custom-scripts)を使用してください。

<div id="tokens">
  ### トークン
</div>

トークンの値は、そのままマークアップに使える**フォーマット済みの文字列**（ショップの通貨形式、`%`付きのパーセンテージ、または数量）です。

| トークン                     | 表示内容                                |
| ------------------------ | ----------------------------------- |
| `{{pre_cart_total}}`     | ディスカウント適用前のカート合計。                   |
| `{{post_cart_total}}`    | ディスカウント適用後のカート合計。                   |
| `{{savings_amount}}`     | 節約額（ディスカウント前の合計からディスカウント後の合計を引いた額）。 |
| `{{savings_percentage}}` | パーセンテージとしての節約分。`%`記号を含みます（例：`15%`）。 |
| `{{cart_quantity}}`      | カート内の表示されている商品数。                    |

<div id="example">
  ### 例
</div>

```html theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
<div class="cart-external-custom-code_html">
  You saved {{savings_amount}} ({{savings_percentage}})
</div>
```

<div id="react-mode">
  ## Reactモード
</div>

Reactモードはコンポーネントをコンパイルし、カートデータと`add-to-cart`アクションを渡します。

* エディターはラッパーを`function CustomCode(props: CustomCodeProps) { … }`に固定しており、それらの行の間の本体のみを編集します。
* ブロックが表示される前に、<span style={{display:'inline-flex',alignItems:'center',gap:'4px',background:'#1C1C1C',color:'#fff',border:'1px solid #0A0A0A',borderRadius:'4px',padding:'0 6px',fontSize:'0.85em',fontWeight:500,lineHeight:'1.4em',verticalAlign:'middle'}}><svg width="8" height="9" viewBox="0 0 10 12" fill="none" aria-hidden="true" style={{display:'block'}}><path d="M1.5 1.2v9.6L8.8 6 1.5 1.2Z" stroke="#fff" strokeWidth="1.5" strokeLinejoin="round" /></svg>Compile</span>をクリックしてから、\*\*「Use custom template」\*\*をオンにする必要があります。
* コンポーネントでは`useState`、`useEffect`、`useMemo`、`useRef`、`useCallback`を使用できます。
* HTMLモードと異なり、Reactはページコンテキストで実行されるため、利用可能であれば`window`や[Cart SDK](/ja/aftersell/cart/sdk-overview)を呼び出せます。
* コンポーネントが実行時にエラーをスローした場合、ブロックは何もレンダリングせず、カートの他の部分は動作し続けます。

<div id="props">
  ### Props
</div>

合計や節約額は、その通貨の[補助単位](/ja/aftersell/cart/sdk-actions#formatmoneycents)（USDならセント）での整数値です。つまり`$12.50`は`1250`であり、`12.50`ではありません。HTMLトークンのようなフォーマット済み金額文字列ではありません。

| Prop                                            | 型                           | 説明                                                                                    |
| ----------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------- |
| `cart`                                          | `AftersellCart`             | 現在のカート。[カートオブジェクトリファレンス](/ja/aftersell/cart/sdk-cart-object)を参照してください。                |
| `line`                                          | `AftersellCartLine \| null` | ブロックがCart itemsのサブブロックの場合のみ設定されます（ラインごとに1回レンダリング）。セクション内では`null`です。                   |
| `preCartTotal`                                  | `number`                    | **ディスカウント適用前**のカート合計（Shopifyの`original_total_price`）。通貨の補助単位（例：セント）です。                |
| `postCartTotal`                                 | `number`                    | **ディスカウント適用後**のカート合計。通貨の補助単位です。                                                       |
| `savings`                                       | `{ amount, percentage }`    | 節約額とパーセンテージ。                                                                          |
| `addProduct(variantId, quantity?, properties?)` | `function`                  | 商品をカートに追加します。このブロックのアトリビューションが付与されるため、[分析](/ja/aftersell/cart/analytics)で貢献として計上されます。 |

<div id="the-cart-and-line-shapes">
  ### カートとラインの構造
</div>

`cart`と`line`は、SDKが他のあらゆる場所で公開しているのと同じオブジェクトです。そのため、\*\*[カートオブジェクトリファレンス](/ja/aftersell/cart/sdk-cart-object)\*\*にまとめてドキュメント化されています。カート、ライン、バンドルのすべてのフィールドが記載されています。

最もよく使うのは、`cart.items`、`cart.itemCount`、`cart.totalPrice`、`line.title`、`line.quantity`、`line.finalLinePrice`です。

このブロックに固有の3つのポイント：

* **`line`はCart itemsのサブブロックでのみ設定され**、コンポーネントはラインごとに1回レンダリングされます。セクションとして配置した場合、`line`は`null`になるため、代わりに`cart.items`を読み取ります。
* **バンドルの子は`cart.items`に含まれません。** ラインが[バンドルにグループ化](/ja/aftersell/cart/sdk-use-case-bundles)されている場合、アンカーラインのみが表示され、子は`line.bundle.children`に含まれます。
* **[ライントランスフォーム](/ja/aftersell/cart/sdk-hooks#registerlinetransform)によって非表示にされたラインも含まれません**が、それらは引き続き`cart.totalPrice`にカウントされます。

<div id="examples">
  ### 例
</div>

商品数を表示する：

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  return (
    <div className="cart-external-custom-code_jsx">
      {props.cart.itemCount} items
    </div>
  );
}
```

Cart itemsのサブブロックとしては、`props.line`を使って商品ごとのコンテンツを表示します。ブロックはラインごとに1回レンダリングされ、そのラインの商品とバリエーションがタグ付けされます。

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  if (!props.line) return null;
  return (
    <div className="cart-external-custom-code_jsx">
      {props.line.productTitle}
      {props.line.variantTitle ? ` · ${props.line.variantTitle}` : ''}
    </div>
  );
}
```

<div id="reading-enrichment-metadata">
  ### エンリッチメントメタデータの読み取り
</div>

`cart.items`の各アイテムには`metadata`フィールドがあります。[カートエンリッチャー](/ja/aftersell/cart/sdk-hooks#registercartenricher)がデータを設定するまでは空のオブジェクト`{}`です。設定されると、エンリッチャーの`id`をキーとして、そのラインの商品またはバリエーションのStorefrontデータが含まれます。

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  return (
    <ul>
      {(props.cart.items ?? []).map((item) => {
        const note = item.metadata?.shipping?.shippingNote;
        return (
          <li key={item.key}>
            {item.title}
            {note ? ` · ${note.value}` : ''}
          </li>
        );
      })}
    </ul>
  );
}
```

`metadata`は常に存在し、エンリッチャーの非同期フェッチが完了するまでは空のオブジェクト`{}`がデフォルトです（「まだエンリッチされていない」かどうかのテストは`Object.keys(item.metadata).length === 0`です）。特定のエンリッチャーのキーを読み取る際は、エンリッチメントが完了するまでそのキーが存在しないため、オプショナルチェーン（`item.metadata?.enricherId`）を使用してください。

<div id="reading-discount-codes-and-line-discounts">
  ### ディスカウントコードとラインディスカウントの読み取り
</div>

`cart.discountCodes`にはカートに適用されているディスカウントコードが一覧され、各ラインの`discountAllocations`にはそのラインに適用されているディスカウントが一覧されます。

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  const codes = props.cart.discountCodes;
  return (
    <div>
      {codes.length > 0 && (
        <p>Active discounts: {codes.join(', ')}</p>
      )}
      <ul>
        {(props.cart.items ?? []).map((item) => {
          return (
            <li key={item.key}>
              {item.title}
              {item.discountAllocations.map(
                (discount) => ` · ${discount.title} (-${(discount.amount / 100).toFixed(2)})`
              )}
            </li>
          );
        })}
      </ul>
    </div>
  );
}
```

<div id="placement-and-limits">
  ## 配置と制限
</div>

* **領域：** 任意（上部、本体、下部）。Cart itemsのサブブロックとしても利用可能です。
* **最大数：** 無制限。
* **状態：** 商品が入ったカートと空のカート（セクションブロックとして）。Cart itemsのサブブロックとしては、カートにラインがある場合のみ、ラインごとに1インスタンスがレンダリングされます。
* ロックされていないため、削除や非表示が可能です。
* ブロック単位のDesignセクションはありません。独自のマークアップ、[**カスタムCSS**](/ja/aftersell/cart/custom-css)、およびグローバルの[**デザイン設定**](/ja/aftersell/cart/design-settings)でスタイルを設定してください。

<div id="when-to-use-custom-code-block-vs-custom-template-vs-custom-script">
  ## カスタムコードブロック、カスタムテンプレート、カスタムスクリプトの使い分け
</div>

|                                                       | 機能                                                                      | 使うタイミング                                   | 例                                                                                                         |
| ----------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| **カスタムコードブロック**                                       | 独自のHTMLまたはReactによる\_新しい\_ブロックを追加します。                                    | 組み込みブロックではカバーできない何かが必要な場合。                | カート合計に固定送料を加算した見積合計行や、チェックアウトボタンの上に配置する配送締め切りカウントダウンなど。                                                   |
| **[カスタムテンプレート](/ja/aftersell/cart/custom-templates)** | \_既存の\_ブロックのレンダリングを、そのブロックのデータを使った独自のJSXに置き換えます。                        | 組み込みブロックがほぼ望みどおりだが、異なるマークアップが必要な場合。       | バリエーション名、節約額、数量ピッカーを1行に並べるように[Product row](/ja/aftersell/cart/cart-items-block#custom-template)を再構築するなど。  |
| **[カスタムスクリプト](/ja/aftersell/cart/custom-scripts)**    | [Cart SDK](/ja/aftersell/cart/sdk-overview)を介してカートに対してJavaScriptを実行します。 | ドロワーのマークアップではなく、カート全体のロジック、イベント、設定が必要な場合。 | \$75の購入で無料トートバッグをプレゼント：カートがしきい値を超えたら[ギフトを追加](/ja/aftersell/cart/sdk-use-case-free-gift)し、購入者が下回ったら取り除くなど。 |
