はじめに
ヘッドレスE-commerceシステムの成長には、多チャネル販売と国際化が不可欠です。これにより、顧客リーチを拡大し、グローバル市場での競争力を強化できます。この第8部では、ShopifyのStorefront APIとAdmin APIを活用して、Instagram Shopping、Amazon、楽天などのプラットフォームと統合する方法を解説します。また、Next.jsのi18n機能とShopify Translations APIを使用した多言語対応の実装も扱います。開発者向けに、API同期、PWA(Progressive Web App)、およびキャッシュ戦略をコードスニペットとともに提供し、スケーラブルなE-commerceを構築します。
多チャネル販売の重要性
多チャネル販売は、以下の利点を提供します:
- リーチの拡大: SNSやマーケットプレイスで新たな顧客層にアクセス。
- 売上増加: 複数の販売チャネルで収益源を多様化。
- ブランド認知度: 異なるプラットフォームでの露出で知名度向上。
- 顧客体験: 顧客が好むプラットフォームでの購入を可能に。
国際化は、言語や通貨の違いに対応し、グローバル市場での成長を加速します。ShopifyとNext.jsを組み合わせることで、これらを効率的に実現します。
多チャネル販売の実装
1. Instagram Shoppingの統合
Instagram ShoppingをShopifyと統合し、SNSで直接販売:
Shopifyでの設定
# Instagram Shoppingのセットアップ
1. Shopify管理画面で「Sales Channels」→「Facebook & Instagram」を追加
2. Instagramビジネスアカウントを接続
3. 商品カタログを同期:
- Shopify商品をFacebookカタログにエクスポート
- Instagramで商品タグを有効化
4. Instagram投稿に商品タグを追加
Next.jsでの商品タグ表示
InstagramフィードをNext.jsに統合(例:Instafeed.jsライブラリ):
# Instafeed.jsのインストール
npm install instafeed.js
Instagramフィードコンポーネント(components/InstagramFeed.tsx
):
import { useEffect } from 'react';
import Instafeed from 'instafeed.js';
export default function InstagramFeed() {
useEffect(() => {
const feed = new Instafeed({
accessToken: process.env.INSTAGRAM_ACCESS_TOKEN,
limit: 6,
template: `
<div class="border rounded p-2">
<a href="{{link}}" target="_blank">
<img src="{{image}}" alt="{{caption}}" class="w-full h-48 object-cover" />
<p class="text-sm">{{caption}}</p>
</a>
</div>
`,
after: () => {
// フィードロード後のカスタム処理
},
});
feed.run();
}, []);
return <div id="instafeed" className="grid grid-cols-3 gap-4"></div>;
}
環境変数にInstagramトークンを追加:
# .env.local
INSTAGRAM_ACCESS_TOKEN=your_instagram_access_token
2. Amazonとの統合
ShopifyとAmazonを同期し、マーケットプレイスで販売:
Shopifyでの設定
# Amazonとの統合
1. Shopify管理画面で「Sales Channels」→「Amazon」を追加
2. Amazonセラーアカウントを接続
3. 商品を同期:
- Shopifyの商品をAmazonリスティングにエクスポート
- 在庫と価格を自動同期
Next.jsでのAmazonリンク表示
Amazonリスティングへのリンクを商品ページに追加:
// pages/products/[handle].tsx (抜粋)
export default function ProductPage({ product }: { product: any }) {
return (
<div className="container mx-auto p-4">
{/* 既存の商品詳細 */}
<a
href={`https://www.amazon.com/dp/${product.amazonASIN}`}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 underline"
>
Amazonで購入
</a>
</div>
);
}
Amazon ASINをShopifyの商品メタフィールドに保存:
# メタフィールドの設定
mutation productUpdate($input: ProductInput!) {
productUpdate(input: $input) {
product {
id
}
userErrors { field message }
}
}
# 変数
{
"input": {
"id": "gid://shopify/Product/123456789",
"metafields": [
{
"namespace": "custom",
"key": "amazon_asin",
"value": "B08XXXXXXX",
"type": "string"
}
]
}
}
3. 楽天との統合
楽天市場とShopifyを同期(サードパーティアプリ使用):
# 楽天統合アプリのインストール
1. Shopify App Storeで「Rakuten Connector」または類似アプリをインストール
2. 楽天セラーアカウントを接続
3. 商品、在庫、価格を同期
楽天リンクをNext.jsに追加(上記Amazonと同様のアプローチ)。
国際化(i18n)の実装
Next.js i18nとShopify Translations APIで多言語対応を実現:
1. Next.js i18nの設定
Next.jsで多言語ルーティングを有効化:
// next.config.js
module.exports = {
i18n: {
locales: ['ja', 'en', 'zh'],
defaultLocale: 'ja',
localeDetection: true,
},
images: {
domains: ['cdn.shopify.com'],
},
};
言語切り替えコンポーネント(components/LanguageSwitcher.tsx
):
import { useRouter } from 'next/router';
import Link from 'next/link';
export default function LanguageSwitcher() {
const router = useRouter();
const { locales, locale } = router;
return (
<div className="flex space-x-4">
{locales?.map((loc) => (
<Link key={loc} href={router.asPath} locale={loc} className={loc === locale ? 'font-bold' : ''}>
{loc.toUpperCase()}
</Link>
))}
</div>
);
}
2. Shopify Translations API
Shopify Translations APIで商品の多言語データを取得:
query GetProductTranslations($id: ID!, $locale: String!) {
product(id: $id) {
translations(locale: $locale) {
key
value
}
}
}
Next.jsで翻訳データを動的に取得(pages/products/[handle].tsx
):
import { GetStaticPaths, GetStaticProps } from 'next';
import { gql } from '@apollo/client';
import { client } from '../../lib/apollo-client';
import { useRouter } from 'next/router';
const GET_PRODUCT_WITH_TRANSLATIONS = gql`
query GetProductWithTranslations($handle: String!, $locale: String!) {
product(handle: $handle) {
id
title
description
priceRange { minVariantPrice { amount currencyCode } }
images(first: 1) { edges { node { src altText } } }
translations(locale: $locale) { key value }
}
}
`;
export const getStaticPaths: GetStaticPaths = async ({ locales }) => {
const { data } = await client.query({
query: gql`query { products(first: 100) { edges { node { handle } } } }`,
});
const paths = data.products.edges.flatMap(({ node }: { node: any }) =>
locales!.map((locale) => ({
params: { handle: node.handle },
locale,
}))
);
return { paths, fallback: 'blocking' };
};
export const getStaticProps: GetStaticProps = async ({ params, locale }) => {
const { data } = await client.query({
query: GET_PRODUCT_WITH_TRANSLATIONS,
variables: { handle: params?.handle, locale: locale || 'ja' },
});
return {
props: { product: data.product },
revalidate: 60,
};
};
export default function ProductPage({ product }: { product: any }) {
const { locale } = useRouter();
const translatedTitle = product.translations.find((t: any) => t.key === 'title')?.value || product.title;
const translatedDescription = product.translations.find((t: any) => t.key === 'description')?.value || product.description;
return (
<div className="container mx-auto p-4">
<h1 className="text-3xl font-bold mb-6">{translatedTitle}</h1>
<p className="text-gray-600 mb-4">{translatedDescription}</p>
<p className="text-xl font-semibold mb-4">
{product.priceRange.minVariantPrice.amount} {product.priceRange.minVariantPrice.currencyCode}
</p>
</div>
);
}
3. 通貨の動的切り替え
Shopifyのmulti-currency機能を活用:
query GetProductWithCurrency($handle: String!, $currency: CurrencyCode!) {
product(handle: $handle) {
id
title
priceRange(currency: $currency) { minVariantPrice { amount currencyCode } }
}
}
PWAの実装
PWAでモバイル体験を向上:
# PWAのセットアップ
npm install next-pwa
PWA設定(next.config.js
):
const withPWA = require('next-pwa')({
dest: 'public',
register: true,
skipWaiting: true,
});
module.exports = withPWA({
i18n: {
locales: ['ja', 'en', 'zh'],
defaultLocale: 'ja',
},
images: {
domains: ['cdn.shopify.com'],
},
});
マニフェストファイル(public/manifest.json
):
{
"name": "YourStore",
"short_name": "YourStore",
"icons": [
{
"src": "/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone",
"start_url": "/"
}
キャッシュ戦略
RedisまたはVercel Edge Functionsでデータキャッシュを最適化:
// pages/api/cache.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const cacheKey = `products:${req.query.handle}`;
const cached = await redis.get(cacheKey);
if (cached) {
return res.status(200).json(cached);
}
const { data } = await client.query({
query: gql`
query GetProduct($handle: String!) {
product(handle: $handle) { id title }
}
`,
variables: { handle: req.query.handle },
});
await redis.set(cacheKey, data, { ex: 3600 }); // 1時間キャッシュ
return res.status(200).json(data);
}
環境変数にRedis設定を追加:
# .env.local
UPSTASH_REDIS_REST_URL=your_redis_url
UPSTASH_REDIS_REST_TOKEN=your_redis_token
テストとデバッグ
以下のテストを実施:
- 多チャネルテスト: InstagramとAmazonで商品が正しく表示されるか。
- i18nテスト: 言語切り替えで翻訳データが正しく表示されるか。
- PWAテスト: オフライン対応とプッシュ通知の動作確認。
- キャッシュテスト: Redisキャッシュがヒットするか。
PWAテスト:
# LighthouseでPWAスコアを確認
lighthouse https://my-ecommerce.vercel.app --only-categories=pwa --view
まとめ
この第8部では、ShopifyとNext.jsを使った多チャネル販売と国際化の実装を解説しました。Instagram Shopping、Amazon、楽天との統合、i18n、PWA、およびキャッシュ戦略により、グローバルなE-commerceを構築しました。次の第9部では、AIと自動化について掘り下げます。
Qiitaの皆さん、この記事が役に立ったら「いいね」や「ストック」をお願いします!コメントで技術的な質問や提案もお待ちしています!