0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

電子商取引システムの構築と最適化 | 第8部: 多チャネル販売と国際化

Posted at

はじめに

ヘッドレスE-commerceシステムの成長には、多チャネル販売国際化が不可欠です。これにより、顧客リーチを拡大し、グローバル市場での競争力を強化できます。この第8部では、ShopifyStorefront APIAdmin APIを活用して、Instagram ShoppingAmazon楽天などのプラットフォームと統合する方法を解説します。また、Next.jsi18n機能とShopify Translations APIを使用した多言語対応の実装も扱います。開発者向けに、API同期PWA(Progressive Web App)、およびキャッシュ戦略をコードスニペットとともに提供し、スケーラブルなE-commerceを構築します。

多チャネル販売の重要性

多チャネル販売は、以下の利点を提供します:

  • リーチの拡大: SNSやマーケットプレイスで新たな顧客層にアクセス。
  • 売上増加: 複数の販売チャネルで収益源を多様化。
  • ブランド認知度: 異なるプラットフォームでの露出で知名度向上。
  • 顧客体験: 顧客が好むプラットフォームでの購入を可能に。

国際化は、言語や通貨の違いに対応し、グローバル市場での成長を加速します。ShopifyNext.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との統合

ShopifyAmazonを同期し、マーケットプレイスで販売:

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 i18nShopify 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部では、ShopifyNext.jsを使った多チャネル販売国際化の実装を解説しました。Instagram ShoppingAmazon楽天との統合、i18nPWA、およびキャッシュ戦略により、グローバルなE-commerceを構築しました。次の第9部では、AI自動化について掘り下げます。

Qiitaの皆さん、この記事が役に立ったら「いいね」や「ストック」をお願いします!コメントで技術的な質問や提案もお待ちしています!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?