shopifyのカスタマイズ – オーダー注文商品に対応する方法
2024.09.13.金
クライアント要望
- オーダー注文に対応し、顧客がカスタマイズした商品を注文できるようにしたい。
対応したこと
- 商品の詳細ページに独自のオプション選択項目を追加し、選択されたオプションに基づいて価格を自動的に計算。その価格を反映させて商品をカートに追加できるよう改修。
今回は、Shopifyでオーダー商品の注文に対応するためのカスタマイズ手法について、具体的な実装方法を交えてご紹介します。
shopifyのバリエーションとオプション設定
shopifyでは、商品の登録が必須であり、商品に対するオプション(バリエーション)も価格設定が必要です。オーダー注文商品の場合は、独自の設計が必要となります。
オーダー商品の処理フロー
オーダー商品の場合、独自のデータベースに商品データが格納されている場合があります。この場合、以下のフローで対応します。
- 価格設定
商品のオプションをプルダウンメニューなどで選択できるようにし、選択されたオプションに基づいてAjaxを使用して独自のデータベースから価格を取得します。 - 商品コピー
ベースとなる商品を事前に作成し、Shopify Admin APIを使用してその商品をコピーします。この際、取得した価格を新しい商品の価格として設定します。 - カートへの追加
コピーされた商品がカートに正しく追加されるように処理します。
処理速度とAPIのレート制限への対策
商品コピーには多少の時間がかかるため、ユーザーに対してローディング中であることを示すインジケーターを設けるのが望ましいです。また、shopifyのAPIにはレート制限があるため、一定時間内に実行できるAPIリクエスト数に注意が必要です。
現在のレート制限については、以下のページから詳細を確認してください。
API処理
今回もPHPのLaravelで実装を行います。予めAPIのアクセストークンは作成しておく必要があります。
// 商品テンプレートからコピーしてオーダー注文商品を作成する
public function copyToOriginalProduct(Request $request)
{
$productId = $request->input('product_id');
$productImg = $request->input('product_image');
$newPrice = $request->input('price');
$newTitle = $request->input('title');
$newSku = $request->input('sku');
$newBarcode = $request->input('product_standard');
$newWeight = $request->input('weight');
$option1 = $request->input('option1');
$selectedOptions = $request->input('selected_options'); // 受け取ったJSON文字列
try {
// 元の商品情報を取得
$response = $this->client->get("https://{$this->shopName}/admin/api/2024-07/products/{$productId}.json", [
'headers' => [
'X-Shopify-Access-Token' => $this->accessToken,
],
]);
$product = json_decode($response->getBody(), true)['product'];
// 新しい商品データを作成
$newProductData = [
'product' => [
'title' => $newTitle,
'body_html' => $product['body_html'],
'vendor' => $product['vendor'],
'product_type' => 'copy',
'tags' => $product['tags'],
'variants' => [
[
'option1' => $option1,
'price' => $newPrice,
'sku' => $newSku,
'barcode' => $newBarcode,
'weight' => $newWeight, // kg単位で設定
'weight_unit' => 'kg', // 重量の単位をキログラムに設定
'inventory_management' => null,
'inventory_policy' => 'continue',
],
],
'images' => [
[
'src' => $productImg
]
]
]
];
// 新しい商品を作成
$response = $this->client->post("https://{$this->shopName}/admin/api/2024-07/products.json", [
'headers' => [
'X-Shopify-Access-Token' => $this->accessToken,
'Content-Type' => 'application/json',
],
'json' => $newProductData,
]);
$newProduct = json_decode($response->getBody(), true)['product'];
$newProductId = $newProduct['id'];
$newVariantId = $newProduct['variants'][0]['id']; // 最初のバリアントIDを取得
// コピー元の商品IDをメタフィールドに保存
$metafieldData = [
'metafield' => [
'namespace' => 'global',
'key' => 'original_product_id',
'value' => $productId,
'type' => 'single_line_text_field',
'value_type' => 'string',
],
];
$this->client->post("https://{$this->shopName}/admin/api/2024-07/products/{$newProductId}/metafields.json", [
'headers' => [
'X-Shopify-Access-Token' => $this->accessToken,
'Content-Type' => 'application/json',
],
'json' => $metafieldData,
]);
return response()->json([
'status' => 'success',
'new_product_id' => $newProductId,
'new_variant_id' => $newVariantId, // バリエーションIDを返す
]);
} catch (\Exception $e) {
return response()->json(['status' => 'error', 'message' => $e->getMessage()]);
}
}
javascript処理
Laravelのエンドポイントを作成し、以下のような処理でサーバーにリクエストを行います。
サーバーから返却されたバリエーションIDをcart.jsを使用してカートに追加します。
const singlePrice = 5000;
const product_code = '1000-001';
const finalOption1 = generatedOption1.join('|'); //オリジナルの選択オプションを取得
const quantity = parseInt($('#quantity-select').val()); //オリジナルの数量を取得
//商品画像を取得
const productImg = `${product_url}/assets/images/products/${product_image}`;
// パラメータを設定
const params = {
product_id: "{{ product.id }}",
product_image: productImg,
price: singlePrice, //オリジナルの価格を設定
weight: singleWeight,
sku: product_code,
product_standard: product_standard,
title: "{{ product.title }}", // 元のタイトルを使用
option1: finalOption1, // 生成されたoption1を使用
selected_options: JSON.stringify(selectedOptions), // selectedOptionsをJSON文字列に変換して送信
};
// Ajaxリクエストで商品をコピーし、新しい商品を作成
$.ajax({
url: `${baseUrl}/shopify/product/copy_to_original_product`,
method: 'POST',
data: params,
success: function(response) {
if (response.status === 'success') {
// 作成されたバリエーションIDを取得し、カートに追加
const new_variant_id = response.new_variant_id;
// カートに追加するためのURLを作成
const addToCartUrl = '/cart/add.js';
const addToCartData = {
id: new_variant_id,
quantity: quantity,
};
// カートに商品を追加
$.ajax({
url: addToCartUrl,
method: 'POST',
data: addToCartData,
dataType: 'json',
success: function() {
//カート追加処理
},
error: function() {
//カート追加エラー処理
}
});
} else {
//商品作成エラー処理
}
},
error: function() {
//サーバー通信エラー処理
}
});
おわりに
今回のカスタマイズは、オーダー注文商品に対応するために、さまざまな工夫を凝らして実装しました。
shopify自体は本来、カスタムオーダーには対応していないため、独自の仕組みを追加するのに苦労しましたが、何とかクライアントの要望に応えられる形に仕上げることができました。今回の経験を通して、より柔軟なカスタマイズの可能性を感じました。今後もこうしたチャレンジを続けていきたいと思います。