タグアーカイブ Webhook

WooCommerceのStripe SEPA決済が後日失敗する時の注文ステータス更新対処

WooCommerceのStripe SEPA決済が後日失敗する時の注文ステータス更新対処

WooCommerceのStripe決済でSEPAダイレクトデビットを利用する場合、完了ステータスのままだと後日の支払い不成立を注文に反映できない。SEPAは数日後に引き落としが確定する支払い方式なので、注文は保留中で開始し、StripeのWebhook通知でステータスを同期するのが基本だ。

SEPAダイレクトデビットはなぜ後日失敗するのか

SEPAダイレクトデビットはなぜ後日失敗するのか

SEPA(Single Euro Payments Area)のダイレクトデビットは、欧州の銀行口座から代金を引き落とす後日確定型の支払いだ。日本の口座振替に近く、注文時点では「引き落としの依頼」が受理されただけであり、銀行口座から実際に資金が移動したわけではない。

このため注文確定直後はStripeの決済ステータスが「処理中」や「成功」と表示されることがあっても、数日から数週間後に銀行が引き落としを実行した段階で残高不足や口座相違、口座閉鎖、顧客の同意撤回などが判明し、その時点で初めて支払い失敗が確定する。

つまりSEPAでは「注文時に成功していたように見える」状態と「実際の入金が完了した」状態が時間差で分かれる。この時間差が、後から失敗した注文を見つけにくくする根本的な要因だ。

STEP 1 顧客がSEPAダイレクトデビットで注文を確定する
STEP 2 Stripeが決済処理中と表示し、WooCommerceは注文を完了にする
STEP 3 数日から数週間後、銀行の引き落としが実行される
結果 残高不足や口座相違で銀行が拒否し、Stripe上は失敗になる
支払い失敗に切り替わる  WooCommerce側は完了のまま残ってしまう

この流れで後日失敗が起きても、WooCommerceの注文は完了のまま残るため、店舗側からは売上確定後に消える注文のように見える。

WooCommerceの注文ステータスはなぜ変わらないのか

WooCommerceの注文ステータスはなぜ変わらないのか

一番の原因は、WooCommerceの注文ステータス「完了」が終端状態である点だ。完了になった注文は、標準の状態遷移では処理中や保留中へ戻せない。後からStripeが支払い失敗を通知しても、すでに完了になっている注文を自動で失敗に切り替える動作は発生しない。

StripeプラグインはWebhookイベントを受け取って注文ステータスを更新する。しかしWebhookで支払い失敗を受け取っても、対象の注文が完了の場合、状態遷移がブロックされる。逆に注文が保留中や処理中のままなら、失敗ステータスへ更新できる余地がある。

加えて、Webhookエンドポイントの設定漏れやシークレットキーの不一致があると、Stripeからの通知そのものがWooCommerceに届かない。この状態では支払い失敗だけでなく、成功通知も正しく反映されなくなる。

Before(完了のまま運用)
注文を完了にして発送まで進める
数日後にStripeが支払い失敗を通知する
完了は終端状態のため注文ステータスが変わらない
After(保留中から開始する運用)
注文を保留中にする
Stripeが支払い失敗を通知する
保留中なら注文を失敗ステータスに変更できる
完了のままでは通知を受けても動かない  保留中なら後日の失敗を反映しやすい

このように、WooCommerceの注文ステータスは「完了」を途中で覆す前提で設計されていない。SEPAのような後日確定の支払いでは、注文ステータスを保留中に保つのが安全だ。

後日失敗を検知するにはどう設定すればよいか

後日失敗を検知するにはどう設定すればよいか

対策は大きく2つある。1つはStripeとWooCommerceの間でWebhook通知を正しく受け取れる状態にすること、もう1つはSEPA注文の初期ステータスを保留中にして後から失敗に変更できる余地を残すことだ。

STEP 1 StripeダッシュボードでWebhookエンドポイントを追加する
STEP 2 WooCommerceのStripe設定にWebhookシークレットを登録する
STEP 3 SEPA注文の初期ステータスを保留中に変更する
STEP 4 入金確定後にだけ手動で完了へ進める運用にする
Stripe側の通知設定  WooCommerce側の受け取り設定  注文の初期ステータス変更

上記の流れを1つずつ設定していけば、後日失敗した注文をWooCommerce側で検知しやすくなる。

Stripe側でWebhookエンドポイントを新規作成する

Stripeのダッシュボードで「開発者」→「Webhooks」を開き、エンドポイントを追加する。エンドポイントURLにはWooCommerceが用意する受信先(通常は example.com/?wc-api=wc_gateway_stripe に相当する自サイトのアドレス)を指定する。イベントには payment_intent.processing、payment_intent.payment_failed、charge.failed を最低限有効にする。

WooCommerce側にWebhookシークレットを登録する

WooCommerceの管理画面で「WooCommerce」→「設定」→「決済」→「Stripe」を開き、詳細設定にあるWebhook Secret欄にStripeから発行された署名シークレットを貼り付ける。これはStripeからの通知が本物であることを検証する鍵で、一致しない場合はイベントが受け付けられない。

SEPA注文の初期ステータスを保留中にする

WooCommerceのStripe決済設定には、支払い方法ごとに注文ステータスを割り当てる項目がある。SEPAダイレクトデビットを「処理中」または「保留中」にしておくと、支払い失敗時の自動更新が効きやすい。完了への変更は入金確定後に行う。

自動で完了にする運用をやめる

注文を一括で完了に変更する自動化プラグインやカスタムコードを使っている場合、SEPA注文には適用しないよう除外する。対象を前払いのカード決済や銀行振込に限定し、後日確定の支払い方法は人による確認を挟む。

再発を防ぐには何を監視すべきか

再発を防ぐには何を監視すべきか

Webhookとステータス設定を整えても、銀行側の事情で通知が遅れたり不達になるケースは残る。店舗側ではStripeダッシュボードの支払い失敗一覧とWooCommerceの注文リストを週次で突き合わせる運用が現実的だ。

  • Stripeダッシュボードの支払い失敗イベントを定期確認する
  • WooCommerceのWebhookログにエラーが出ていないか確認する
  • 保留中のまま長期滞留している注文を抽出する
  • 完了済み注文の中から支払い失敗に切り替わったものを洗い出す

WooCommerceは「WooCommerce」→「システムステータス」→「ログ」にStripeのWebhook受信ログを残す。日付が新しいログに対象注文が見つからないなどのエラーが記録されている場合は、該当する注文の状態を手動で修正する。自動化に頼りきらず、最終確認として人の目を挟むのが安全だ。

よくある質問

SEPAの支払いが失敗した場合、顧客には自動で通知される?

Stripeからは顧客へメール通知が送られるが、WooCommerce側の注文メールはステータス変更を基に動作する。失敗を検知したら店舗側から個別に連絡する運用にしておくと、顧客対応が安定する。

StripeのWebhookが受信されているか確認するには?

WooCommerceのシステムステータスにあるログ一覧でStripe Gatewayのログを開く。日付が新しいログにエラーがなければ受信できている。不安な場合はStripeダッシュボードでテストイベントを送信して確認する。

既に完了にしている注文を後から失敗に変更できるか?

WooCommerceの標準画面では、完了から失敗への直接変更はできない。手動で注文ステータスドロップダウンから変更を試みても反映されないことが多い。必要な場合は対象注文を返金処理するか、カスタムコードでステータスを書き換えることになる。

SEPA以外の後払い決済でも同じ問題は起きる?

後日確定型の支払い方法であれば同様の問題が起きる。具体的には銀行振込や口座振替、一部の後払いサービスなどが該当する。支払い方法ごとに注文ステータスの初期値を確認しておくとよい。

Stripeの公式プラグイン以外でもWebhook設定は必要?

他のStripe連携プラグインでも、Stripeのイベントを受け取る仕組みが備わっている。プラグインの設定画面にWebhook URLやシークレットキーの項目があるかを確認し、なければ手動でエンドポイントを追加する。

この記事のポイント

  • SEPAダイレクトデビットは後日確定するため注文時の成功は最終結果ではない
  • WooCommerceの完了ステータスは終端状態で失敗へ自動変更できない
  • 注文は保留中で開始し入金確定後にのみ完了へ移す
  • StripeのWebhookとWooCommerceのシークレット設定を同期させる
  • StripeダッシュボードとWooCommerceのログを定期的に突き合わせる
REST APIに非ログイン状態でアクセスできなくなった時の原因と解決手順

REST APIに非ログイン状態でアクセスできなくなった時の原因と解決手順

プラグインや本体のアップデートを機に、外部サービスからのREST APIリクエストが「Only authenticated users can access the REST API.」というエラーで拒否されるようになった場合、多くのケースではプラグインの認証設定が更新によって変更されている。まずは該当プラグインの「REST APIアクセスを許可する」設定を見直し、それでも改善しなければバージョン固有の不具合を疑う。

なぜアップデート後にREST APIが突然使えなくなるのか

なぜアップデート後にREST APIが突然使えなくなるのか

WordPressのREST APIは、外部アプリやサービスとサイトがデータをやり取りするための共通の窓口だ。決済ゲートウェイの通知(ウェブフック)、モバイルアプリからの記事取得、別サーバーとの在庫連携など、多様な自動処理がREST APIを通じて動いている。

プラグインのバージョンアップでアクセスが遮断される原因は、大きく分けて二つある。ひとつはセキュリティ強化を目的とした仕様変更で、非ログインユーザー(未認証リクエスト)に対する制限が新たに追加、あるいは既定で有効化されたケースだ。もうひとつは、アップデート時のコードの不具合で「REST APIを許可する」設定が内部的に無視されてしまうケースである。

REST API遮断の主な発生パターン
ケースA セキュリティ機能の新設・既定値変更
新バージョンで「未認証ユーザーのREST APIアクセスをブロック」が既定でオンになった
ケースB バージョン固有のコード不具合
管理画面の設定は「許可」のままでも内部処理が効かず拒否される
仕様変更による遮断  不具合による遮断

いずれの場合も、ウェブフックを受け取るサイト側では「ログインしていない外部からのPOSTリクエスト」として扱われるため、認証エラーが返ってしまう。ECサイトの決済通知や予約システムの在庫更新など、リアルタイム性が求められる連携ほど被害が大きい。

プラグイン設定でREST APIのアクセス制御を確認する

プラグイン設定でREST APIのアクセス制御を確認する

最初に行うべきは、該当プラグインの設定画面にREST API関連の項目が存在するかどうかの確認だ。多くのセキュリティ系プラグインやユーザー管理プラグインには「REST APIへのアクセスを制限する」「未認証ユーザーをブロックする」といったチェックボックスが用意されている。

管理画面から該当プラグインの設定ページを開き、「REST API」「APIアクセス」「外部リクエスト」「認証」などのキーワードを含む項目を探す。もし「未認証ユーザーのREST APIアクセスを無効にする」といった設定がオンになっていれば、これをオフに切り替えて保存し、外部からのリクエストが再び通るかをテストする。

設定項目の名称や位置はプラグインによって異なる。セキュリティタブの中にあったり、詳細設定の一番下に隠れていたりすることも多い。見つからない場合はプラグインのドキュメントや公式サポートフォーラムで「REST API permission」をキーに検索する。

設定確認から解決までのフロー
STEP 1 プラグイン設定でREST API許可のチェックボックスを探す
STEP 2 無効化されていればONに変更して保存
STEP 3 外部からAPIリクエストを送信して動作確認
STEP 4 改善しなければバージョンの切り戻しを検討

プラグインのバージョンを切り戻して検証する

プラグインのバージョンを切り戻して検証する

設定が正しく「許可」になっているにもかかわらずAPIが機能しない場合、プラグイン自体の不具合を疑う段階に入る。管理画面上は許可しているように見えて、内部的な処理では設定値を正しく読み取れていない可能性がある。

まずは該当プラグインの安定していた旧バージョンを入手し、手動でインストールし直す。公式プラグインディレクトリの「以前のバージョン」セクションや、プラグイン開発者がGitHubでリリースしているアーカイブからダウンロードできる。

切り戻しは次の手順で進める。プラグイン一覧画面で問題のプラグインを一度無効化し、削除する(設定データは残るため心配は不要)。続いて旧バージョンのZIPファイルを「プラグイン」→「新規追加」→「プラグインのアップロード」からインストールし有効化する。この状態で外部からのAPIリクエストが正常に処理されるかテストし、復旧を確認したら開発元に不具合報告を送る。

どうしても旧バージョンが入手できない場合は、WP Rollbackプラグインを使って管理画面から直接ダウングレードする方法もある。ただし本番サイトでの使用は慎重に行い、必ず事前にバックアップを取得しておく。

特定エンドポイントだけを許可するカスタム対応

特定エンドポイントだけを許可するカスタム対応

セキュリティ上の理由からREST API全体を無制限に開放したくない場合は、必要なエンドポイントだけを選択的に許可する方法が有効だ。たとえば決済ゲートウェイのウェブフックは特定のルート(/wp-json/wc/v3/ordersなど)だけ通ればよい。

テーマのfunctions.phpに以下のようなフィルターを追加すれば、特定のRESTルートに対して認証要件を緩和できる。コードを直接書く場合は必ず子テーマを利用する。

add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! empty( $result ) ) {
        return $result;
    }
    if ( strpos( $_SERVER['REQUEST_URI'], '/wp-json/my-plugin/v1/webhook' ) !== false ) {
        return true;
    }
    return $result;
});

このコードは、指定したパス(上の例では/my-plugin/v1/webhook)へのアクセスに対して認証チェックをスキップし、それ以外のエンドポイントは通常の認証を維持する。プラグイン本体を修正せずに済むため、アップデートが来ても上書きされる心配がない。

フィルターを追加した後は必ず、許可したエンドポイントに外部からcurlコマンドやPostmanでテストリクエストを送り、意図したとおりに動作することを確認する。想定外のエンドポイントが開放されていないかも併せてチェックする。

リバースプロキシやWAFがリクエストを遮断していないか調べる

リバースプロキシやWAFがリクエストを遮断していないか調べる

プラグインの設定もバージョンも問題ないのにAPIが機能しない場合、サーバー環境側でリクエストが遮断されている可能性がある。CDNのWAF(ウェブアプリケーションファイアウォール)、ホスティング側のセキュリティモジュール、あるいは.htaccessの記述が原因で、外部からのPOSTリクエストがブロックされているケースは意外に多い。

確認すべきはログだ。WAFを導入している場合はその管理画面で遮断ログを検索し、APIリクエストが誤検知でブロックされていないか調べる。サーバーのアクセスログでは、対象のエンドポイントにリクエストが到達しているかどうか、到達している場合のHTTPステータスコード(401や403なら認証・権限の問題、200系ならアプリケーション側で正常処理後にエラーが発生している)をチェックする。

とくに管理画面のURLを変更するプラグインや、xmlrpc.phpを無効化する設定が、間接的にREST APIのエンドポイントにまで影響を与えていることもある。これらの設定も一時的に解除してテストを行う。

よくある質問

どのプラグインがREST APIに影響を与えているか特定するには

全プラグインを一度無効化し、問題のエンドポイントに外部からアクセスして正常応答を確認する。その後、プラグインを1つずつ有効化しながら再テストすれば、原因のプラグインを絞り込める。テーマのfunctions.phpのカスタムコードも疑わしい場合は、標準テーマに一時的に切り替えて検証する。

外部サービスが受け取るエラーの内容を詳しく知るには

WordPressのREST APIは認証エラー時にJSON形式のエラーオブジェクトを返す。外部サービス側でHTTPレスポンスボディをログに残せるなら、codemessageの値を取得すれば原因の手がかりになる。ログが取れない場合は、curlで手動リクエストを送り、curl -vでレスポンスボディを直接確認する。

REST API全体を無効化せずにセキュリティを保つ方法はあるか

特定のIPアドレスからのみアクセスを許可する.htaccessの設定、APIキーやアプリケーションパスワードを使った認証の義務付け、あるいは必要なエンドポイントだけをホワイトリスト登録するカスタムコードで対応できる。無制限の全面開放は避け、必要最小限の権限に絞ることが安全面でも推奨される。

プラグインをダウングレードしても問題はないのか

セキュリティ修正や脆弱性対策を含むアップデートを巻き戻すことになるため、ダウングレードはあくまで一時的な回避策と位置づける。復旧を確認したら速やかに開発元へ報告し、修正バージョンがリリースされたらすぐに更新する。ダウングレード期間中はサイト全体の監視を強化する。

アップデート前のバージョンが不明な場合はどうするか

プラグイン一覧画面の「詳細を表示」から「開発」タブを開くと、過去のバージョン履歴が参照できる。または公式プラグインディレクトリの「Advanced View」に「Previous Version」のリンクが用意されている。どうしてもわからない場合は、バックアップから前回正常に動作していたプラグインファイルを復元する。

この記事のポイント

  • プラグイン更新後にREST APIが遮断されたら、まず設定画面のアクセス制御項目を確認する
  • 設定が正しくても動かない場合は、旧バージョンに切り戻して不具合を検証する
  • 必要なエンドポイントだけをfunctions.phpのフィルターで選択的に開放できる
  • WAFやサーバー設定がリクエストをブロックしていないかログで確認する
  • ダウングレードは一時的な対策とし、修正版のリリースを待って更新する
GiveWPアップデート後にStripeの寄付が完了しない原因と直し方

GiveWPアップデート後にStripeの寄付が完了しない原因と直し方

Stripeの決済は成功しているのにGiveWPで寄付が「完了」にならない。管理画面に寄付データが作成されず、Webhookだけが延々と失敗し続ける。この症状は、GiveWP 4.16のアップデート後にStripeから送られてくるWebhookの中身が空(null)になっていることが原因だ。PHPの致命的エラー「array_keys(): Argument #1 ($array) must be of type array, null given」が記録されているならなおさらで、GiveWPがイベントデータを正しく読み取れていない。

対処の核心はGiveWPとStripeの接続を完全に再確立し、Webhookの登録から正しくやり直すことにある。加えて、サーバー側のキャッシュがWebhookの受信を阻害しているケースも多いため、キャッシュの全削除とWebhookエンドポイントの除外設定が必要だ。

なぜStripeの決済は成功するのにGiveWPの寄付は未完了になるのか

なぜStripeの決済は成功するのにGiveWPの寄付は未完了になるのか

この問題のややこしい点は、Stripe上では決済が正常に完了して見えることだ。PaymentIntentのステータスは「succeeded」になり、クレジットカードの引き落としも問題なく行われる。しかしGiveWP側では寄付レコードが作成されず、寄付者にも完了メールが届かない。

仕組みをたどると、GiveWPは次の流れで寄付を確定させている。

① 寄付者がフォームで決済を実行
Stripeがクレジットカード情報を処理し、PaymentIntentが作成される
② StripeがWebhookをGiveWPのエンドポイントに送信
エンドポイントURLの例 https://example.com/?give-listener=stripe
③ GiveWPがWebhookを受け取り、署名を検証
署名検証に成功するとイベントデータを内部処理に回す
④ GiveWPが寄付レコードを作成し、ステータスを「完了」に変更
寄付者に完了メールが送信される

この流れのうち、手順③の段階でコケているのが今回の症状だ。StripeからのWebhookはGiveWPのエンドポイントに届いているのに、GiveWPがその中身を処理できない。結果として手順④に進めず、寄付は永遠に「処理中」のまま取り残される。

「array_keys null given」エラーが示す根本原因

「array_keys null given」エラーが示す根本原因

GiveWPのデバッグログに次のような致命的エラーが記録されている場合、原因の特定はかなり絞り込める。

Uncaught TypeError: array_keys(): Argument #1 ($array) must be of type array, null given
in vendor/stripe/stripe-php/lib/StripeObject.php

このエラーは、GiveWPがStripeの公式PHPライブラリ(stripe-php)を使ってWebhookイベントのデータを読み取ろうとしたとき、肝心のイベントオブジェクトの中身がnullになっていることを意味する。本来なら配列として渡されるべきデータが空っぽなのだ。

なぜデータが空になるのか。主な原因は次の3つに集約される。

  • GiveWPのアップデートで内部のWebhook処理ロジックが変わり、既存の接続設定との整合性が崩れた
  • サーバーレベルのキャッシュ(LiteSpeedやホスティング側のキャッシュ)がWebhookリクエストを変形させている
  • StripeダッシュボードのWebhook設定とGiveWPが自動管理する署名シークレットとの間にずれが生じている

4.16より前のバージョンではWebhookのデータ取得方法が異なっていた可能性があり、アップデートによって従来の接続状態に不整合が発生したと見るのが自然だ。事実、GiveWP 4.16がリリースされる直前の6月23日までは正常に動作していたという報告は、この仮説を裏付けている。

GiveWPとStripeの接続を完全に再確立する手順

GiveWPとStripeの接続を完全に再確立する手順

部分的な修正では直らない。GiveWPとStripeの間の信頼関係をゼロから組み直すつもりで、以下の手順を上から順に実行する。

STEP 1 GiveWPを最新バージョンに更新する
4.16.0で問題が発生した場合も、まず4.16.1以降への更新を試みる。GiveWPは不具合修正を迅速にリリースすることが多い。
STEP 2 GiveWP管理画面でStripeとの接続を解除する
「寄付」→「設定」→「支払いゲートウェイ」→「Stripe」から「接続を解除」を実行する。
STEP 3 StripeダッシュボードのWebhookを完全に削除する
Stripeダッシュボードの「開発者」→「Webhook」から、GiveWP用のエンドポイントをすべて削除する。古いものや重複しているものも含めて、すべて消す。
STEP 4 WordPressのキャッシュをすべて削除する
プラグインキャッシュ、サーバーキャッシュ(LiteSpeed等)、ホスティングキャッシュの3層すべてをクリアする。キャッシュ系プラグインを一時的に無効化してもよい。
STEP 5 GiveWPでStripeに再接続する
「寄付」→「設定」→「支払いゲートウェイ」→「Stripe」から「Stripeと接続」を実行し、Stripeの認証画面で許可する。
STEP 6 Webhookが自動再作成されるのを確認する
GiveWPが再接続時にStripeへWebhookエンドポイントを自動登録する。StripeダッシュボードのWebhook一覧を開き、新しいエンドポイントが作成されていること、必要なイベントが有効になっていることを確認する。

GiveWP管理画面でのStripe接続解除と再接続の落とし穴

接続解除ボタンを押しても、内部的に完全にクリーンアップされるとは限らない。GiveWPは接続情報をデータベースのoptionsテーブルに保存しているため、万が一解除がうまくいかない場合は、データベースを直接確認する方法も検討する。

再接続時は必ず本番モードで認証を通すこと。テストモードで接続したあとに本番モードに切り替えても、Webhookエンドポイントはテスト用のものが残ったままになり、本番決済のWebhookが正しく処理されない原因になる。

Stripe Webhookエンドポイントに必要なイベントを確認する

GiveWPが自動登録するWebhookには、以下の8つのイベントが最低限有効になっている必要がある。Stripeダッシュボードでエンドポイントを開き、「受信イベント」欄を目視で確認する。

  • charge.refunded(返金処理)
  • checkout.session.completed(チェックアウトセッション完了)
  • customer.subscription.created(定期寄付の作成)
  • customer.subscription.deleted(定期寄付の削除)
  • invoice.payment_failed(請求書の支払い失敗)
  • invoice.payment_succeeded(請求書の支払い成功)
  • payment_intent.payment_failed(支払い意図の失敗)
  • payment_intent.succeeded(支払い意図の成功)

いずれかが欠けている場合は手動で追加する。GiveWPがイベントを自動追加する仕様はバージョンによって変わるため、再接続後に必ず確認する習慣をつけるとよい。

キャッシュがWebhookを壊す仕組みと確実な対処

キャッシュがWebhookを壊す仕組みと確実な対処

Webhookはサーバー間のHTTP POSTリクエストだ。ところが一部のキャッシュプラグインやホスティング側のキャッシュ機構は、このPOSTリクエストに対して予期せぬ挙動を示す。具体的には、リクエストボディを空にしたり、ヘッダー情報を削除したり、レスポンスをキャッシュしてしまったりする。

GiveWPが正しく署名を検証し、イベントデータを読み取るためには、StripeからのPOSTリクエストが一切加工されずに届かなければならない。次の対応を必ず実施する。

Before(キャッシュがWebhookを加工している状態)
Stripe → キャッシュを通過リクエストボディが変形・空になる → GiveWPが処理失敗
After(キャッシュからWebhookエンドポイントを除外した状態)
Stripe → キャッシュをバイパスリクエストボディが完全なまま届く → GiveWPが正常に処理
キャッシュがリクエストを加工している状態  キャッシュから除外した状態

LiteSpeedキャッシュが原因のケース

LiteSpeedサーバー環境では、LiteSpeed Cacheプラグインの設定画面から「キャッシュ」→「除外」タブを開き、「URLの除外」にGiveWPのWebhookエンドポイントパスを追加する。具体的には「give-listener=stripe」を含むURLパターンを指定する。正規表現が使える場合は次のように記述する。

give-listener=stripe

また、LiteSpeedの「オブジェクトキャッシュ」や「ブラウザキャッシュ」も合わせて無効化した状態でテストすることを推奨する。テストが終わったら再度有効化しても問題はないが、少なくともWebhookエンドポイントだけは常にキャッシュの対象外にしておく。

ホスティング側のキャッシュが原因のケース

一部の共用サーバーやマネージドホスティングでは、サーバーレベルでリバースプロキシキャッシュが動作している。管理パネルからキャッシュを手動でクリアしたあと、一時的にキャッシュ機能を停止してWebhookが正常に処理されるかテストする。

恒常的な解決策としては、ホスティングのサポートに依頼して「https://example.com/?give-listener=stripe」をキャッシュの除外リストに追加してもらう必要がある。

署名シークレットの誤設定が引き起こす症状と修正

署名シークレットの誤設定が引き起こす症状と修正

GiveWP 4.16以降、署名シークレットの管理方法が変わり、手動での設定が不要になった。GiveWPがStripeに接続する際、自動的にWebhookエンドポイントを作成し、署名シークレットもGiveWP内部で管理する。そのため、Stripeダッシュボードから取得した署名シークレットをGiveWPの設定画面に入力する欄は存在しない。

もし過去に手動でWebhookを作成し、その署名シークレットを何らかの方法でGiveWPに設定していた場合、バージョンアップ後にその情報が無視されるか、あるいは競合を起こす可能性がある。そのため、手順としては次のように徹底する。

  1. Stripeダッシュボードから古いWebhookをすべて削除する(手動で作成したものも含む)
  2. GiveWP管理画面でStripeとの接続を完全に解除する
  3. GiveWP管理画面でStripeに再接続する(このとき新しいWebhookと署名シークレットが自動作成される)

署名シークレットに関するエラーがStripeダッシュボードに表示されている場合、ほぼ間違いなく新旧のWebhookが混在しているか、手動設定の名残が残っている。上記の手順で完全にリセットすれば、署名検証エラーは解消する。

それでも直らないときの最終確認リスト

それでも直らないときの最終確認リスト

上記の手順をすべて実行しても症状が改善しない場合、以下のポイントを順に再チェックする。

チェック1 サーバーの時刻が大幅にずれていないか
SSL証明書の評価がAランクでもNTPの同期が外れていると署名検証に失敗する。ホスティングに確認する。
チェック2 .htaccessやNginx設定にWebhookを妨害するルールが入っていないか
特定のクエリ文字列をブロックする設定や、POSTリクエストをGETに変換するリダイレクトルールがないか確認する。
チェック3 セキュリティプラグインがWebhookエンドポイントをブロックしていないか
WordfenceやSucuriなどのWAFがStripeのIPを遮断しているケースがある。一時的に無効化してテストする。
チェック4 StripeのAPIバージョンが極端に新しくなっていないか
Stripeダッシュボードの「開発者」→「APIのバージョン管理」で、使用中のAPIバージョンがGiveWPの対応範囲内か確認する。

よくある質問

GiveWPを最新版に更新したあとにStripeのWebhookが失敗し始めた。ロールバックするべきか

ロールバックは推奨しない。4.16系にはWebhook処理まわりの重要な変更が含まれており、古いバージョンに戻すと将来的にStripe APIの更新に追随できず、より深刻な不具合を引き起こす。まずは本記事の再接続手順を試し、それでも解決しない場合はGiveWPのサポートにシステムレポートを送って調査を依頼するほうが安全だ。

StripeのダッシュボードでWebhookが「失敗」と表示されるが、GiveWP側にエラーログが出ない

GiveWPのデバッグモードが有効になっていない可能性が高い。「寄付」→「設定」→「詳細」→「デバッグモード」を有効にすると、Webhook処理のエラーログが記録されるようになる。ログは「寄付」→「ツール」→「ログ」で確認できる。

再接続してもWebhookがStripeダッシュボードに自動作成されない

GiveWPの接続プロセスの中で、WordPressのREST APIが正しく動作していない可能性がある。パーマリンク設定を「基本」以外に変更して保存し直す。また、セキュリティプラグインがREST APIを制限していないか確認する。

WebhookエンドポイントのURLは手動で変更してもよいか

原則として不要であり、変更すべきではない。GiveWPが自動生成するエンドポイントURLは「https://(サイトURL)/?give-listener=stripe」で固定されており、これをStripeに正しく登録している。URLを手動で変更すると、署名の不一致が発生してすべてのWebhookが失敗する。

GiveWPのシステムレポートはどこで確認できるか

WordPress管理画面の「寄付」→「ツール」→「システム情報」タブを開き、「システムレポートを取得」ボタンをクリックすると、サーバー環境やGiveWPの設定情報がテキスト形式で表示される。サポートに問い合わせる際はこのレポートを添付するとスムーズに調査が進む。

この記事のポイント

  • Stripe決済成功後に寄付が未完了になるのは、Webhook処理の段階でGiveWPがイベントデータを読み取れていないから
  • 致命的エラー「array_keys null given」はWebhookの中身が空であることを示す決定的な手がかり
  • GiveWPとStripeの接続解除からWebhook全削除、再接続までを一気に行い、署名シークレットを完全に再生成する
  • LiteSpeedやホスティングのキャッシュからWebhookエンドポイントを除外し、POSTリクエストが加工されないようにする
  • 署名シークレットはGiveWPが自動管理するため、手動設定は不要であり、むしろ競合の原因になる