WordPressでStripeの購入完了メールを自動送信させる

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ライブラリをインストール又はダウンロード。

    1. Composer を使用してライブラリをインストール
    2. 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ファイルの
    ①署名シークレット
    ②シークレットキー

    を本番環境のキーへ入れ替える。