
Stripeの「Stripe Payment Links」で商品を作成し、リンクボタンをWordPressに設置。商品が購入されたら「購入完了ページ」へリダイレクトするようにStripe側で設置しています。
併せて、商品購入時に「購入完了ページ」へのリンクを含んだ自動返信サンクスメールを送りたかったのですが、Stripe側の設定ではカスタマイズできない?仕様。
なので、Stripe WebhookのイベントをキャッチしてPHPでメール送信するコードを作成してみました。
メールはwp_mail()関数を使用します。
また、複数の商品があるため、商品ごとに違うメッセージ内容にしています。
それなりの作業量だったため、備忘録として残します。
※記事内で紹介しているHTML・CSS・JavaScript・PHPなどのコードは、作成時点における作成者の最適解です。動作環境やバージョンによって結果が異なる場合があります。コードの使用により生じたいかなる損害やトラブルについても、当サイトは責任を負いかねます。
実装手順
1.Stripeライブラリのインストール
2.Webhookエンドポイントの設定
3.Stripe側で商品作成&メタデータ設定
4.PHPファイルの作成
5.テスト
6.本番環境へ
Stripeライブラリのインストール
まずは、PHPでStripeのWebhookを処理するためにstripeのphpライブラリをインストール又はダウンロード。
- Composer を使用してライブラリをインストール
- stripe-php ライブラリのソースコードを直接 GitHub からダウンロード
のどちらかで行う。
どちらで行うかによって、後で作成するPHPファイルでのStripe読み込みコードが変わる。
2.のダウンロードの場合は、例えば「https://◯◯◯.com/」の下に新しいディレクトリ「stripe」を作成する。つまり、「https://◯◯◯.com/stripe/」の下に作成するのであれば、
「require_once $_SERVER['DOCUMENT_ROOT'] . '/stripe/stripe-php/init.php';」となる。
Webhookエンドポイントの設定
次はStripeにログインして、Webhookエンドポイントの設定。
まずは「テスト環境」で実施する。
左下にある「開発者」から「Webhook」を開く。
右端の「+ エンドポイントを追加」ボタンをクリック。
エンドポイントとはイベントが起こった際に通知されるURL。
作成するPHPファイル名を「stripe_send_mail.php」とし、「https://◯◯◯.com/stripe/」の下に作成するので、エンドポイントURLは
「https://◯◯◯.com/stripe/stripe_send_mail.php」と入力。
バージョンは最新のものを選択し、「+イベントを選択」ボタンをクリック。
送信するイベント「checkout.session.completed」にチェックを入れて「イベントを追加」。
当初は「payment_intent.succeeded」にしていたが上手くいかず。
イベントデータを見ると、購入者の名前や商品情報が含まれていないことに気付き「checkout.session.completed」
へ変更。

追加したら、追加したWebhook エンドポイントのURLをクリックし、「署名シークレット」の「表示」をクリックして表示させ、そのキー(whsec_◯◯◯)をコピーしておく。
次に同じ「開発者」から「APIキー」を開き、「シークレットキー(sk_test_◯◯◯)」もコピーしておく。
この2つのキーは、後で使う。
Stripe側で商品作成&メタデータ設定
Stripeで商品を作成し、メタデータを設定する。
商品のメタデータにある「編集」ボタンをクリック。
一つの商品につき、キーと値のペアを2つ追加する。
キーの名前は何でもいいが、「product_id」と「product_name」とした。
値の名前も何でもいいが、管理しやすいように「product_id」は「product_1」として商品ごとに数字を増やしていく。
「product_name」は日本語で該当の商品名(自分で管理しやすい名前)を入れる。(例:Tシャツ)

つまり、例えば商品が「Tシャツ」「ジーパン」「ジャケット」の3つあれば、それぞれにキーと値のペア2つのメタデータを設定。
(例)
① 商品「Tシャツ」:
「product_id」は「product_1」
「product_name」は「Tシャツ」
② 商品「ジーパン」:
「product_id」は「product_2」
「product_name」は「ジーパン」
③ 商品「ジャケット」:
「product_id」は「product_3」
「product_name」は「ジャケット」
このメタデータの設定は、商品ごとに違うメッセージ内容を送信するために設定するもの。
PHPファイルの作成
.envファイルと.htaccessファイルの作成
PHPファイル作成の前に、Stripeのキーの保護のために .env ファイルと .htaccess ファイルを作成する。
.env ファイルには先ほどコピーした
①署名シークレット(テスト環境のもの)
②シークレットキー(テスト環境のもの)
を入れる。
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx
次に、 .env ファイルへのアクセス防止の対策として、 .htaccess を使って .env ファイルをブラウザから見えなくする。
<Files .env>
Order allow,deny
Deny from all
</Files>
上記2つのファイルは、stripe-php ライブラリをComposerを使わずに直接ダウンロードした場合は、自動でメールを返信PHP「stripe_send_mail.php」と同じディレクトリに作成する。
すなわち、「https://◯◯◯.com/stripe/」の下に作成する。
PHPファイルの作成
最後に自動でメールを返信するPHPファイルを作成。
メールは購入者と運営サイドに送る。
購入者には商品ごとにStripe側で設定しているリダイレクトページの「購入完了ページ」へのリンクとメッセージを用意した。
PHPファイル名は、上で述べたように「stripe_send_mail.php」とし、「https://◯◯◯.com/stripe/」の下に作成する。
3.Stripe側で商品作成&メタデータ設定で例として挙げた(Tシャツ・ジーパン・ジャケット)場合のコードは次のとおり。
なお、stripe-phpライブラリをComposerを使わずに直接ダウンロードした場合のコードであり、Composerでインストールした場合のコードは省略する。
<?php
// stripe-phpライブラリをComposerを使わずに直接ダウンロードした場合のコード
function load_env($path) {
if (!file_exists($path)) return;
$lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos(trim($line), '#') === 0) continue;
list($name, $value) = explode('=', $line, 2);
putenv(trim($name) . '=' . trim($value));
}
}
load_env(__DIR__ . '/.env');
require_once $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/stripe/stripe-php/init.php';
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
$endpoint_secret = getenv('STRIPE_WEBHOOK_SECRET');
$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '';
try {
$event = \Stripe\Webhook::constructEvent($payload, $sig_header, $endpoint_secret);
} catch (\UnexpectedValueException $e) {
error_log('Invalid payload: ' . $e->getMessage());
http_response_code(400);
exit();
} catch (\Stripe\Exception\SignatureVerificationException $e) {
error_log('Invalid signature: ' . $e->getMessage());
http_response_code(400);
exit();
}
if ($event->type == 'checkout.session.completed') {
$session = $event->data->object;
$product_id = $session->metadata->product_id ?? '不明な商品';
$product_name = $session->metadata->product_name ?? '商品名不明';
$customer_email = $session->customer_details->email ?? '';
$customer_name = $session->customer_details->name ?? 'お客様';
$currency = strtoupper($session->currency);
$amount = $session->amount_total;
if ($currency !== 'JPY') {
$amount = $amount / 100;
}
// 商品ごとのページリンク
$product_link = 'https://◯◯◯.com/';
switch ($product_id) {
case 'product_1': // Tシャツのリダイレクトページ
$product_link = 'https://◯◯◯.com/××××××/';
break;
case 'product_2': // ジーパンのリダイレクトページ
$product_link = 'https://◯◯◯.com/××××××/';
break;
case 'product_3': // ジャケットのリダイレクトページ
$product_link = 'https://◯◯◯.com/××××××/';
break;
}
send_email_to_customer($customer_email, $customer_name, $product_name, $amount, $product_link, $product_id);
send_email_to_admin($customer_email, $customer_name, $product_name, $amount);
error_log('Webhook processed successfully: checkout.session.completed');
http_response_code(200);
} else {
error_log('Received non-target event: ' . $event->type);
http_response_code(200);
}
// 購入者向けメール送信関数
function send_email_to_customer($customer_email, $customer_name, $product_name, $amount, $product_link, $product_id) {
if (empty($customer_email)) return;
$to = $customer_email;
$subject = "ご購入ありがとうございます";
// 商品ごとのメッセージ内容
switch ($product_id) {
case 'product_1': // Tシャツ
$message = "
{$customer_name} 様<br><br>
この度は、{$product_name}のご購入ありがとうございます。<br>
○○○○ // Tシャツ用のメッセージ
<a href='{$product_link}'>購入完了ページ</a>へ<br>
";
break;
case 'product_2': // ジーパン
$message = "
{$customer_name} 様<br><br>
この度は、{$product_name}のご購入ありがとうございます。<br>
○○○○ // ジーパン用のメッセージ
<a href='{$product_link}'>購入完了ページ</a>へ<br>
";
break;
case 'product_3': // ジャケット
$message = "
{$customer_name} 様<br><br>
この度は、{$product_name}のご購入ありがとうございます。<br>
○○○○ // ジャケット用のメッセージ
<a href='{$product_link}'>購入完了ページ</a>へ<br>
";
break;
default:
$message = "
{$customer_name} 様<br><br>
この度は、{$product_name}のご購入ありがとうございます。<br><br>
下記からも購入完了ページへアクセスできます。<br><br>
<a href='{$product_link}'>購入完了ページ</a>へ<br>
";
}
// 金額と共通の情報を追加
$message .= "
<hr>
このメールはシステムから自動送信です。<br><br>
<strong>ご購入内容</strong><br>
商品名:{$product_name}<br>
金額:{$amount}円<br><br>
会社名、担当者、電話番号など
";
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: ◯◯◯ <◯◯◯@◯◯◯.◯◯>', // SMTP設定と合致させる
'Reply-To: ◯◯◯@◯◯◯.◯◯'
);
$mail_sent = wp_mail($to, $subject, $message, $headers);
}
// 運営者向けメール送信関数
function send_email_to_admin($customer_email, $customer_name, $product_name, $amount) {
$admin_email = '◯◯◯@◯◯◯.◯◯'; // 送信する運営サイドのメルアド
$subject = "商品が購入されました";
$message = "
以下の商品が購入されました。<br><br>
<strong>商品名:</strong> {$product_name}<br>
<strong>金額:</strong> {$amount}円<br>
<strong>購入者:</strong> {$customer_name}<br>
<strong>メールアドレス:</strong> {$customer_email}
";
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: ◯◯◯ <◯◯◯@◯◯◯.◯◯>', // SMTP設定と合致させる
);
$mail_sent = wp_mail($admin_email, $subject, $message, $headers);
}
テスト
Stripe側が用意しているテスト用クレジットカードでテストする。
リンク先に間違いがないか確認し、メールの文面など修正していく。
本番環境へ
テスト環境で上手くいけば、本番環境へ移行する。
.envファイルの
①署名シークレット
②シークレットキー
を本番環境のキーへ入れ替える。