【Rewald】llms scenario E ポイント購入(PSP: Stripe Checkout)
牧さん制作監修 AIアウトプットポイント購入(PSP: Stripe Checkout)のシナリオ
役割: あなたはコード転写者です。コード生成者ではありません。
タスク: ===== ここからコピー ===== と ===== ここまでコピー ===== の間の内容をそのまま正確にコピーしてください。
ルール: {{PLACEHOLDER}} の値のみ置き換えてください。構造、キー名、関数シグネチャは変更しないでください。
ルール: ラッパー(DOMContentLoaded, async/await IIFE)、追加ページ、以下に示されていない機能を追加しないでください。
ルール: 各コードブロックには FINGERPRINT コメントがあります。出力にそのまま含めてください。
ルール: 回答は必ず日本語で行ってください。
よくある間違い — コードをコピーする前に必ず読んでください。
誤: 'stripe_verify' => [ 'callback' => function ($r) { ... } ]
正: 'verify' => function ($pointsystem_request) { ... } — フラットなキーで、ネストされた配列にしない。
誤: [point_purchase_open price="1000" ...] ポイント購入
正: <span style="display:none;">[point_purchase_open price="1000" ...]</span> — 必ず非表示の span で囲む。
誤: document.addEventListener("DOMContentLoaded", function () { ... })
正: インライン <script> で DOMContentLoaded ラッパーなし — ページ解析時にそのまま実行される。
誤: fetch(endpoint + '?session_id=' + sid + '&nonce=' + n, { method: 'POST' })
正: fetch(endpoint, { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({order_id: ..., nonce: ..., amount: ...}) }) — クエリパラメータではなく JSON ボディを使う。
誤: body: JSON.stringify({ session_id: params.get('session_id'), ... })
正: body: JSON.stringify({ order_id: params.get('session_id'), ... }) — キーは session_id ではなく order_id。
誤: add_action('init', function() { PointSystemPSP::register([...]); });
正: PointSystemPSP::register([...]); — トップレベルで直接呼び出す。add_action の中に入れない。
===== ここからコピー =====
ファイル 1: functions.php
貼り付け先
WordPress 管理画面 → 外観 → テーマファイルエディター → 右側のファイル一覧から「テーマのための関数 (functions.php)」を選択 → ファイル末尾に以下のコードを追加 → 「ファイルを更新」をクリック
{{PLACEHOLDER}} の置き換え
{{STRIPE_SECRET_KEY}}: Stripe ダッシュボードのシークレットキー(sk_test_...またはsk_live_...)
<?php
// FINGERPRINT: E1-REG-001
// 1. 管理パネルの環境セットアップコードをここに貼り付け
// (PointSystem と PointSystemPSP クラスを同期的に読み込みます)
// 2. Stripe 検証コールバック — ここに直接配置。add_action('init', ...) で囲まないこと
PointSystemPSP::register([
'verify' => function ($pointsystem_request) {
return PointSystemPSP::verifyStripeSession(
$pointsystem_request['order_id'],
$pointsystem_request['amount'],
'{{STRIPE_SECRET_KEY}}'
);
},
]);
// 3. REST API: Stripe Checkout セッション作成 — これは add_action で囲む(WP REST ルート登録のため)
add_action('rest_api_init', function () {
register_rest_route('my-shop/v1', '/create-checkout-session', [
'methods' => 'POST',
'callback' => function ($request) {
$params = $request->get_json_params();
\Stripe\Stripe::setApiKey('{{STRIPE_SECRET_KEY}}');
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price_data' => [
'currency' => $params['currency'],
'product_data' => ['name' => 'ポイント購入'],
// FINGERPRINT: E1-JPY-001 — JPY はゼロ小数通貨: 1000 は ¥1,000。100倍しないこと。
'unit_amount' => intval($params['amount']),
],
'quantity' => 1,
]],
'mode' => 'payment',
'success_url' => $params['success_url'],
'cancel_url' => $params['cancel_url'],
]);
return ['session_id' => $session->id];
},
'permission_callback' => '__return_true',
]);
});
===== ここまでコピー =====
===== ここからコピー =====
ファイル 2: ポイント購入ページ(WordPress 固定ページ)
貼り付け先
WordPress 管理画面 → 固定ページ → 新規追加(またはポイント購入用の既存ページを編集)→ エディタ右上の「テキスト」タブに切り替え → 以下のコードを貼り付け → 「公開」(または「更新」)をクリック
スラッグの設定
固定ページのパーマリンク(スラッグ)は自由に設定できます(例: purchase-points)。
{{PLACEHOLDER}} の置き換え
{{STRIPE_PUBLIC_KEY}}: Stripe ダッシュボードの公開キー(pk_test_...またはpk_live_...)
<!-- FINGERPRINT: E2-BALANCE-001 — 現在のポイント残高を表示 -->
[point_own callback_name="displayBalance"]
<p>保有ポイント: <span id="point_id">読み込み中...</span></p>
<!-- FINGERPRINT: E2-NONCE-001 — nonce 取得: ショートコードは必ず非表示の span で囲む -->
<span id="purchase_nonce" style="display:none;">
[point_purchase_open price="1000" currency_type="JPY" conv_rate="1"]
</span>
<button id="purchase-button">1,000円分のポイントを購入</button>
<script>
// FINGERPRINT: E2-DISPLAY-001 — コールバックは response.result.point でポイント残高を受け取る
function displayBalance(response) {
if (response.error) {
document.getElementById('point_id').textContent = 'エラー';
return;
}
document.getElementById('point_id').textContent = response.result.point;
}
// 非表示の span から nonce を読み取る
var nonce = document.getElementById('purchase_nonce').textContent.trim();
var amount = '1000';
// FINGERPRINT: E2-CHECKOUT-001 — success_url には encodeURIComponent(nonce) で動的 nonce を含める
document.getElementById('purchase-button').addEventListener('click', function() {
fetch('/wp-json/my-shop/v1/create-checkout-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: amount,
currency: 'jpy',
success_url: location.origin + '/purchase-success/'
+ '?session_id={CHECKOUT_SESSION_ID}'
+ '&nonce=' + encodeURIComponent(nonce)
+ '&amount=' + encodeURIComponent(amount),
cancel_url: location.origin + '/purchase-cancel/'
})
})
.then(function(res) { return res.json(); })
.then(function(data) {
Stripe('{{STRIPE_PUBLIC_KEY}}').redirectToCheckout({ sessionId: data.session_id });
});
});
</script>
===== ここまでコピー =====
===== ここからコピー =====
ファイル 3: 決済完了ページ — /purchase-success/(WordPress 固定ページ、ショートコードなし)
貼り付け先
WordPress 管理画面 → 固定ページ → 新規追加 → タイトル:「購入完了」(任意)→ パーマリンクのスラッグを purchase-success に設定 → エディタ右上の「テキスト」タブに切り替え → 以下のコードを貼り付け → 「公開」をクリック
注意
- このページにはショートコードを置かないでください。JavaScript のみで動作します。
- スラッグは
purchase-successにしてください(ファイル 2 の success_url と一致させるため)。
<!-- FINGERPRINT: E3-RESULT-001 — このページにはショートコードなし、JavaScript のみ -->
<div id="purchase-result">決済処理中...</div>
<script>
// FINGERPRINT: E3-CLOSE-001 — point_purchase_close REST API を JSON ボディで POST 呼び出し
var params = new URLSearchParams(location.search);
fetch('/wp-json/pointsystem/v1/point_purchase_close/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
order_id: params.get('session_id'),
nonce: params.get('nonce'),
amount: params.get('amount')
})
})
.then(function(res) { return res.json(); })
.then(function(result) {
// FINGERPRINT: E3-RESP-001 — レスポンスは result.error と result.result.point を使用
if (result.error) {
document.getElementById('purchase-result').textContent =
'エラー: ' + result.error;
} else {
document.getElementById('purchase-result').textContent =
'ポイント購入完了! 新しい残高: ' + result.result.point;
}
});
</script>
===== ここまでコピー =====
確認チェックリスト — 回答する前に、出力内容が以下の 9 項目をすべて満たしていることを確認してください。
- register() のキーは 'verify'('stripe_verify' やネストされた配列ではない)— FINGERPRINT E1-REG-001 参照
- [point_purchase_open] は非表示の span で囲まれている — FINGERPRINT E2-NONCE-001 参照
- displayBalance(response) 関数が定義されており response.result.point を使用している — FINGERPRINT E2-DISPLAY-001 参照
- success_url に encodeURIComponent(nonce) で動的 nonce が含まれている — FINGERPRINT E2-CHECKOUT-001 参照
- point_purchase_close は POST + JSON ボディで呼び出されている(クエリパラメータではない)— FINGERPRINT E3-CLOSE-001 参照
- JSON ボディのキーは order_id(session_id ではない)— FINGERPRINT E3-CLOSE-001 参照
- レスポンスのプロパティは result.error と result.result.point — FINGERPRINT E3-RESP-001 参照
- JPY の金額は 100 倍しない — FINGERPRINT E1-JPY-001 参照
- PointSystemPSP::register() は add_action で囲まない — FINGERPRINT E1-REG-001 参照