EC事業をされている方で、記事と商品を合わせたメディアサイトを作りたいというお問い合わせを最近よくいただきます。
この記事ではECプラットフォームの Shopify と microCMS を組み合わせ、メディアECサイトを構築する方法を紹介します。
今回作るもの
このブログでは以下のようなサイトを作ることを目指します。
商品についての記事が書かれていて、その途中で商品の購入リンクが挟まれています。記事の情報は microCMS から、商品の情報は Shopify から取得しています。
記事を読んでいて気になった商品は「カートに追加」ボタンで購入動線へ遷移させ、スムーズな購入体験を実現できます。
今回紹介するのは最低限に絞ったシンプルな実装ですが、より高度な形をヤマップ様が実現されています。
こちらの導入事例インタビューも合わせてご覧ください:
>【株式会社ヤマップ様】Shopifyとのスムーズなデータ連携により、ECサイトリニューアル後の急成長に貢献
Shopify 側の設定
Shopify のアカウント登録はすでに完了しているものとします。
まずは Shopify のダッシュボードから商品を登録しましょう。
今回は「目覚まし時計」を追加します。
ここで登録した商品の情報をメディアECサイトで表示することを目指します。
商品情報を取得するには Shopify のストアフロントAPIを利用します。
API利用準備
APIを利用するには設定が必要です。
まず、サイドメニューの「アプリ管理」>「アプリを開発」を選択します。
アプリ開発のページで、右上の「アプリを作成」ボタンを選択します。
「API資格情報」タブから、「ストアフロントAPIのアクセストークン」を発行します(いくつか操作が必要です)。
このアクセストークンを利用して、API経由で商品を取得できます。
APIで商品を取得してみる
ストアフロントAPIはいろいろな方法で利用できますが、今回は shopify-buy
SDKを利用します。
// インストール
$ npm install shopify-buy
index.js
というファイル名で、以下のように記述しましょう。
import Client from "shopify-buy";
// 自分のストアのドメイン、アクセストークンを設定
const client = Client.buildClient({
domain: "<YOUR-DOMAIN>.myshopify.com",
storefrontAccessToken: "<YOUR-STOREFRONT-ACCESS-TOKEN>",
});
const products = await client.product.fetchAll();
console.log(products);
<YOUR-DOMAIN> と <YOUR-STOREFRONT-ACCESS-TOKEN> には自分のストアの情報を入力してください。$ node index.js
を実行すると、商品の一覧情報が取得できます。
// 一部抜粋
[
GraphModel {
id: [Getter],
availableForSale: [Getter],
createdAt: [Getter],
updatedAt: [Getter],
descriptionHtml: [Getter],
...
]
例えば一つ目の商品の情報を表示するには、スクリプトに次のようなログ出力を追加します。
console.log(products[0].id);
console.log(products[0].title);
実行すると以下のように出力されます。
gid://shopify/Product/7719453589752 // Shopify の商品ID
目覚まし時計 // Shopify で定義した商品名
ダッシュボードで設定した情報が取得されました。
商品名以外にも、価格や商品画像など様々な要素を取得できます。
これでAPI経由で商品を扱えるようになりました。
microCMS 側の設定
次に、microCMS側の設定を行います。
冒頭で少し紹介した通り、今回は以下のような見た目を目指します。
このような WordPress のブロックエディタライクな表現を作る際には「繰り返しフィールド」を利用します。
繰り返しフィールドをセットアップする
繰り返しフィールドはあらかじめ定義した「カスタムフィールド」を任意の回数追加しながらコンテンツを作成する機能です。
まずはカスタムフィールドを作成しましょう。以下の5種類を定義します。
定義できたらAPIスキーマで「繰り返しフィールド」を選び、
繰り返しフィールドで利用するカスタムフィールドを選択します(先ほど定義した5つを選択)。
APIスキーマはこのようになりました。
記事を入稿する
APIの準備ができたので、商品を紹介する記事を書いていきましょう。
繰り返しフィールドを使ったコンテンツの作成画面は以下のようになっています。
「+ フィールドを追加」を選択すると、追加するフィールドの種類を選択するモーダルが開きます。
このフィールドを組み合わせ、柔軟な構造を持ったコンテンツを作成できます。
今回は以下のように入稿しました。
大見出し、小見出し、見出し画像、本文、そして途中に「商品ID」が定義されています。
この商品IDは先ほど Shopify の API を試したときに確認した商品のIDを入れています。
microCMS では商品IDのみを定義しておき、ページ生成時に商品情報を Shopify から取得して記事に結合します。
microCMS で作成したコンテンツはAPI経由で利用します。
「APIプレビュー」機能でレスポンスを確認してみましょう。
繰り返しフィールドを用いたコンテンツのAPIレスポンスは以下のような形になっています。
{
"id": "lth2hw2j_r2",
"createdAt": "2022-05-20T06:06:35.676Z",
"updatedAt": "2022-06-14T07:58:00.709Z",
"publishedAt": "2022-05-20T06:06:35.676Z",
"revisedAt": "2022-06-14T07:58:00.709Z",
"title": "朝、スッキリと目覚めよう",
"content": [
{
"fieldId": "image",
"image": {
"url": "https://images.microcms-assets.io/assets/d1a1f3d920f8494c965c6bdec3ff7741/33004574e596419f9d8392d650b6d8c2/IMG_4275.JPG",
"height": 3024,
"width": 4032
}
},
{
"fieldId": "heading1",
"title": "朝、スッキリと目覚めよう"
},
{
"fieldId": "heading2",
"title": "心地よいアラーム音"
},
{
"fieldId": "text",
"text": "<p>朝気持ちよく目覚めるために、目覚まし時計をおすすめします。<br>視認性の高い文字盤、静かな秒針、アラーム、ナイトライト機能を搭載。机やベッド横デスクに置くのに映えるデザインに仕上がっています。</p>"
},
{
"fieldId": "shopifyItemID",
"itemID": "7719453589752"
},
{
"fieldId": "text",
"text": "<p>ブランドはオランダのCLOUDNOLA(クラウドノラ)。<br>単三電池一本で、サイズは W110mm x H150mm x D50mm のコンパクトサイズ。<br><br>ご購入から通常1~3日ほどでお届けできます。</p>"
}
]
}
このレスポンスをフロント側でハンドリングし、表示面を構築していくことになります。
メディアECサイトを構築する(Next.js)
ここまででデータの準備ができたので、実装に入っていきます。
今回は Next.js を例に進めますが、お好きなフレームワークで実装してください。
まずはプロジェクトの作成です。
$ yarn create next-app
次に、pages/index.js
を以下のように編集します。
// pages/index.js
import Head from "next/head";
import styles from "../styles/Home.module.css";
import Client from "shopify-buy";
export default function Home({ data, shopifyItem }) {
return (
<div className={styles.container}>
<Head>
<title>{data.title} | hims-shop</title>
<meta name="description" content="Media EC site demo" />
<link rel="icon" href="/favicon.ico" />
</Head>
<header className={styles.header}>Media EC site demo</header>
<main className={styles.main}>
<ul className={styles.container}>
// ① 繰り返しフィールドのタイプを見て表示を実装
{data.content.map((item, index) =>
item.fieldId === "heading1" ? (
<h1 className={styles.title}>{item.title}</h1>
) : item.fieldId === "heading2" ? (
<h2 className={styles.subtitle}>{item.title}</h2>
) : item.fieldId === "image" ? (
<div className={styles.expand}>
<img className={styles.image} src={item.image.url} />
</div>
) :
item.fieldId === "text" ? (
<div className={styles.article}>
<div dangerouslySetInnerHTML={{ __html: item.text }} />
</div>
) : item.fieldId === "shopifyItemID" ? (
<div className={styles.shopifyContainer}>
<div className={styles.shopify}>
<img src={shopifyItem.imageUrl} />
<h3>{shopifyItem.title}</h3>
<div className={styles.price}>¥{shopifyItem.price}</div>
// ② 「カートに追加」クリックで商品購入ページへ遷移
<a
href={`https://<YOUR-DOMAIN>.myshopify.com/products/${shopifyItem.handle}`}
target="_blank"
className={styles.addToCart}
>カートに追加</a>
</div>
</div>
) : null
)}
</ul>
</main>
<footer className={styles.footer}>
<span className={styles.logo}>microCMS media ec site demo.</span>
</footer>
</div>
);
}
export const getStaticProps = async () => {
// ③ microCMSから記事情報を取得
const key = {
headers: { "X-MICROCMS-API-KEY": "<YOUR-MICROCMS-API-KEY>" },
};
const data = await fetch(
"https://him-media-ec-site.microcms.io/api/v1/articles/lth2hw2j_r2",
key
)
.then((res) => res.json())
.catch(() => null);
// ④ Shopify の client を準備
const client = Client.buildClient({
domain: "<YOUR-DOMAIN>.myshopify.com",
storefrontAccessToken: "<YOUR-STOREFRONT-ACCESS-TOKEN>",
});
// ⑤ microCMSに入稿された Shopify の商品IDを抽出
const shopifyItemID = data.content.filter(
(x) => x.fieldId === "shopifyItemID"
)[0].itemID;
// ⑥ Shopify の API で商品の詳細情報を取得する
const productId = `gid://shopify/Product/${shopifyItemID}`;
const product = await client.product.fetch(productId);
const formatter = new Intl.NumberFormat("ja-JP");
const shopifyItem = {
title: product.title,
price: formatter.format(product.variants[0].price),
imageUrl: product.images[0].src,
handle: product.variants[0].handle,
};
return {
props: {
data,
shopifyItem,
},
};
};
いくつかポイントを紹介します。
① 繰り返しフィールドのタイプを見て表示要素を実装
{data.content.map((item, index) =>
item.fieldId === "heading1" ? (
<h1 className={styles.title}>{item.title}</h1>
) : item.fieldId === "heading2" ? (
<h2 className={styles.subtitle}>{item.title}</h2>
) : item.fieldId === "image" ? (
// ....
繰り返しフィールドではフィールドごとに fieldId
という値を持っています。
大見出し(heading1)なら h1 タグ、小見出し(heading2) なら h2 タグのように、fieldId
の値を見て表示面を実装しています。
② 「カートに追加」クリックで商品購入ページへ遷移
<a
href={`https://<YOUR-DOMAIN>.myshopify.com/products/${shopifyItem.handle}`}
target="_blank"
className={styles.addToCart}
>カートに追加</a>
「カートに追加」ボタンクリック時に Shopify の商品購入ページへ遷移させています。
今回の実装では Shopify のストアページに遷移させていますが、ストアフロントAPIを使えば「カートに追加」「決済」といったアクションも自社サイト内で完結することが可能です。
③ microCMSから記事情報を取得
const key = {
headers: { "X-MICROCMS-API-KEY": "<YOUR-MICROCMS-API-KEY>" },
};
const data = await fetch(
"https://him-media-ec-site.microcms.io/api/v1/articles/lth2hw2j_r2",
key
)
.then((res) => res.json())
.catch(() => null);
microCMS から記事の情報を取得しています。
先ほどAPIプレビューで確認したAPIレスポンスと同等のものが取得されます。
④ Shopify の client を準備
const client = Client.buildClient({
domain: "<YOUR_DOMAIN>.myshopify.com",
storefrontAccessToken: "<YOUR-STOREFRONT-ACCESS-TOKEN>",
});
Shopify のストアフロントAPIを利用するためのクライアントを準備します。
ドメイン、アクセストークンは自分のストアのものを入力します。
⑤ microCMSに入稿された Shopify の商品IDを抽出
const shopifyItemID = data.content.filter(
(x) => x.fieldId === "shopifyItemID"
)[0].itemID;
microCMSの繰り返しフィールド部分を探索し、 shopifyItemID
(Shopify商品IDのフィールド)に入稿された値を抽出します。
(※実際の例では1つの記事で複数商品を紹介するケースもあると思いますが、ここでは簡単のため1記事で1つの商品として実装しています)
⑥ Shopify の API で商品の詳細情報を取得する
const productId = `gid://shopify/Product/${shopifyItemID}`;
const product = await client.product.fetch(productId);
const formatter = new Intl.NumberFormat("ja-JP");
const shopifyItem = {
title: product.title,
price: formatter.format(product.variants[0].price),
imageUrl: product.images[0].src,
};
Shopify の商品情報を取得し、表示に必要な title, price, imageUrl の値を準備します。
この情報を用いて今回のサイトでは以下のように商品を表示します。(カートに追加ボタンを押した時の挙動は未実装)
さて、最後の仕上げとしてスタイルを当てましょう。styles/Home.module.css
を以下に変更します。
// styles/Home.module.css
.header {
text-align: center;
padding: 16px 0;
font-size: 18px;
font-style: italic;
color: #333;
}
.main {
min-height: 100vh;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #333;
background-color: #fefefe;
margin-bottom: 128px;
font-size: 18px;
}
.container {
margin: 0;
padding: 0;
}
.expand {
margin-right: calc(50% - 50vw);
margin-left: calc(50% - 50vw);
}
.image {
width: 100%;
object-fit: cover;
height: 480px;
margin: 64px 0;
}
.title {
margin: 32px 0 32px;
line-height: 1.15;
font-size: 2.4rem;
}
.subtitle {
margin: 48px 0 24px;
}
.shopify {
margin: 96px auto;
width: 200px;
}
.shopify img {
object-fit: cover;
width: 100%;
aspect-ratio: 1;
border-radius: 8px;
}
.shopify img:hover {
opacity: 0.83;
cursor: pointer;
}
.shopify h3 {
margin: 8px 0 0;
font-size: 1.1rem;
}
.shopifyContainer {
border-bottom: 2px solid #eaeaea;
margin-bottom: 48px;
}
.price {
margin: 4px 0;
font-size: 1.1rem;
font-weight: bold;
}
.addToCart {
display: block;
text-align: center;
margin-top: 12px;
width: 100%;
padding: 12px;
border-radius: 24px;
font-weight: bold;
font-size: 1rem;
border: none;
background-color: #000000;
color: #fff;
}
.addToCart:hover {
cursor: pointer;
opacity: 0.83;
}
.article {
max-width: 720px;
line-height: 1.8;
}
.footer {
display: flex;
flex: 1;
padding: 2rem 0;
border-top: 1px solid #eaeaea;
justify-content: center;
align-items: center;
}
以上で実装は完了です。yarn dev
を実行してここまで作ったページを確認してみましょう。
今回作ったページ
(再掲)
これで商品を紹介するメディアECサイトを作れました。
おわりに
Shopify と microCMS を組み合わせ、メディアECサイトを作る手順を紹介しました。
コンテンツ部分を microCMS で管理することで、柔軟にコンテンツを表現したり、複数人での運用ワークフローを作ったりなど、よりスムーズなコンテンツ運用が可能です。
ECサイトではサイトの表示速度が売上に大きく影響すると言われていますが、SSG構成で作れば高速なパフォーマンスの実現も可能です。
メディアECに興味のある方はぜひ試してみてください。
補足
今回の構成では microCMS に「Shopify の商品ID」だけを入稿する仕組みとしています。
商品に関する情報を microCMS 側に持たせすぎると、 Shopify のダッシュボードで情報を更新した場合にmicroCMS側で管理している情報と同期を取る必要があり、運用が煩雑になるため、それを避けるのが主な理由です。
SSG構成で作る場合にはビルド時の情報でページが構築されるので、要件に応じて Webhook や ISR などの利用して Shopify 側の情報更新を反映できる仕組みを検討するのが良いかと思います。