AppCotton の公開 REST では、販売ページや購入導線(UI/ショートコード/SDK) が参照する読み取り系エンドポイントとして /products と /plans を提供します。ここでは「何が取得できるか」「どう使うか」「型・例外・設計指針」をまとめます。
(※ 管理者による作成・更新は管理画面 or 管理用RESTで行い、本ページは主に公開読み取り前提です)
1. 目的と前提
- Webサイト側のLP/購入ページ/マイページで「表示用データ」を取得する。
- Product は販売対象(例: “CombPass Premium”)。
- Plan はその商品の料金/上限/課金モードのバリエーション(例: 1サイト/3サイト/5サイト、買い切り/サブスクなど)。
- 価格は最小通貨単位(例: JPYなら円、USDならセント) で返します。
2. エンドポイント一覧(読み取り)
2.1 製品一覧
GET /wp-json/appcotton/v1/products
用途: 一覧表示、商品カードの生成、プラン導線へ遷移の起点。
主なクエリ:
active=1… 公開中のプロダクトのみslug=combpass_premium… スラッグでの絞り込みper_page,page… ページング
レスポンス(要点)
[
{
"id": 1,
"name": "CombPass Premium",
"product_slug": "combpass_premium",
"description": "予約・ライセンス認証プラグイン",
"is_active": true,
"created_at": "2025-10-01 00:00:00",
"updated_at": "2025-11-01 00:00:00"
}
]
2.2 製品詳細
GET /wp-json/appcotton/v1/products/{product_id}
GET /wp-json/appcotton/v1/products/by-slug/{product_slug}
用途: ランディングで 1 商品の詳細をレンダリング。
レスポンス(要点)
{
"id": 1,
"name": "CombPass Premium",
"product_slug": "combpass_premium",
"description": "…",
"is_active": true
}
2.3 製品に紐づくプラン一覧
GET /wp-json/appcotton/v1/products/{product_id}/plans
GET /wp-json/appcotton/v1/products/by-slug/{product_slug}/plans
用途: 「購入」ボタンを“プランごと”に複数表示するためのデータ源。
標準並び順: sort_order ASC → price ASC を推奨。
レスポンス(要点)
[
{
"id": 101,
"product_id": 1,
"plan_name": "1サイト",
"activation_limit": 1,
"billing_type": "one_time", // one_time | subscription
"subscription_interval": null, // day|week|month|year
"price": 9800, // 最小通貨単位
"currency": "JPY",
"stripe_price_id": "price_xxx", // 買い切り用
"stripe_price_id_subscription": null,
"sort_order": 10,
"is_active": true
},
{
"id": 102,
"product_id": 1,
"plan_name": "3サイト",
"activation_limit": 3,
"billing_type": "one_time",
"price": 19800,
"currency": "JPY",
"stripe_price_id": "price_xxx_3",
"sort_order": 20,
"is_active": true
}
]
2.4 プラン詳細
GET /wp-json/appcotton/v1/plans/{plan_id}
用途: 単一プランの確認、価格・上限の再取得(購入直前の再確認など)。
レスポンスは 2.3 の各要素と同等。
3. 表示ロジック指針(UI/ショートコード/SDK)
- 「購入」ボタンを 1 つだけにしない
/products/{id or slug}/plansを必ず呼び、プランごとにボタンを並べる。
例)「1サイト」「3サイト」「5サイト」「無制限」… を同一商品ページで横並び。 - 課金モード表示
billing_type=one_time→ 「買い切り」「¥9,800」billing_type=subscription→ 「¥1,000/月」 (subscription_intervalをサフィックス表示)
- 無効(非公開)プランの抑止
is_active=falseは非表示。管理画面でドラフト化→非表示にできる設計に。 - 並び順
sort_order→priceの順で安定表示。UIブロックの並びと一致させる。
4. 差額課金(アップグレード)との関係
- アップグレードは「現在のライセンスのプラン」と「目標プラン」を比較し、
差額のみを生成するチェックアウトへ誘導(詳細は「/checkout(差額課金)」章に委譲)。 - このページでは**「どのプランに上げられるか」**を把握するため、
一覧取得→上限(activation_limit)や価格(price)の比較に使う。
5. クエリ・ページング・並びの仕様(提案)
- 共通クエリ:
per_page(default 20),page(default 1),orderby,order orderby候補- Products:
created_at,updated_at,name,id - Plans:
sort_order,price,activation_limit,id
- Products:
order:asc|desc
応答ヘッダ(推奨)
X-Total-Count… 総件数X-Total-Pages… 総ページ数
6. 例:表示用コード断片(参考)
PHP (ショートコード/テーマ側)
商品スラッグからプランを列挙してボタンを生成(イメージ)
// 1) プロダクトをスラッグで取得
$product = appcotton_get_product_by_slug('combpass_premium');
if ( $product ) {
// 2) プラン一覧を取得
$plans = appcotton_get_plans_by_product_slug('combpass_premium'); // SDK/ヘルパ層でラップ
foreach ( $plans as $plan ) {
// 3) 各プランのボタンを出力(例:data-plan-idを載せる)
printf(
'<button class="appcotton-buy-button" data-product-id="%d" data-plan-id="%d">%s - ¥%s</button>',
$product['id'],
$plan['id'],
esc_html($plan['plan_name']),
number_format_i18n($plan['price'])
);
}
}
JavaScript (フロントUI)
ボタン押下で plan_id を渡し、チェックアウトへ(差額課金フローは別章)
document.addEventListener('click', async (e) => {
const btn = e.target.closest('.appcotton-buy-button');
if (!btn) return;
const productId = btn.dataset.productId;
const planId = btn.dataset.planId; // ← プラン必須
// ここで /checkout/create-session 等へ POST し、result.redirect_url へ遷移
// ※ 詳細は「/checkout」ページへ
});
7. エラーとバリデーション(抜粋)
404…product_id/product_slug/plan_idが存在しない400… クエリ不正(例:per_pageが負数、orderbyが未サポート)410… 取得はできるが非公開(廃止) の場合の通知に使うことを推奨200でもis_active:falseは UI 側で非表示にする
8. 設計の注意
- 安定キーとして
product_slugを運用:テーマ・ショートコード・外部配布SDKは slug 参照が基本。 - 価格は常にバックエンドの値を最優先:UI表示前に
/plansで再取得、チェックアウト直前にも再確認。 - プランの整合:プラン削除/非公開により UI 側の plan_id が無効化される場合があるため、
その際は「在庫切れ/販売停止」扱いのメッセージを表示。
9. 典型フロー
- LP 表示時に
GET /products/by-slug/{slug}→ 商品存在確認 GET /products/by-slug/{slug}/plans→ ボタンをプラン分レンダリング- クリック時に
product_id + plan_idを持ってチェックアウト開始 - 完了後に
order/licenseが作成され、ユーザーへライセンス通知
10. チェックリスト
- product_slug はユニークか
- plan の
sort_orderとis_activeを設定済みか billing_typeとsubscription_intervalの整合が取れているかpriceは最小通貨単位か(UI で整形表示)- LP/ウィジェットは必ず
/plansを呼び、複数ボタンを出す実装になっているか