WordCampを運営する中で気づいた不具合を、自分で直した話
WordCamp Kansai 2024を運営中に、決済エラーの問題に遭遇。Stripeのmetadata処理に関する不具合を発見し、修正に挑戦。エラーの原因はmetadataの値にオブジェクトが含まれることで、keyの置換で解決。修正パッチをPull requestで送信し、コミュニティに貢献。WordCampのコード修正を経験し、今後も関わりたいと考えている。WordPressのコミュニティ活動が成長に繋がる良い経験となった。
目次
WordCamp Kansai 2024を運営する中で、ちょっとした不具合に遭遇することがありました。カンファレンスの中でWordCampのサイトをローカル環境で実行する方法を知ることができたので、イベント終了後に自分で再現とパッチの作成に挑戦したので、その時の経験を簡単に紹介します。
WordPressのコミュニティカンファレンス、「WordCamp」はもちろんWordPressで作られています。そしてOSSコミュニティならではの取り組みだと思うのですが、ほぼ全てのシステムがOSSとして公開されています。
遭遇した不具合とその検証
チケットを販売する際、一部のチケットを購入しようとすると、必ず決済エラーが発生する現象が発生しました。チケットの名前を変更することでその場の問題は解決したのですが、原因が気になったので調べてみました。
調べる中で見つかったのが、public_html/wp-content/plugins/camptix/addons/payment-stripe.php
L:910-にあるこの関数です。コードをざっと読む限りでは、StripeやPayPalに送信するデータのmetadataを綺麗にすることを目的としている様子でした。具体的には、「キー名、値どちらも一定の長さを超えている場合、文字列をカットする」処理と「metadataの数が21以上にならないようにする」処理をしているように見えます。
protected function clean_metadata( $metadata = array() ) {
$cleaned = array();
foreach ( $metadata as $key => $val ) {
// A Stripe transaction can only have 20 metadata keys.
if ( count( $cleaned ) > 20 ) {
return $cleaned;
}
// Trim the key to 40 chars.
$key = $this->trim_string( $key, 40, '' );
// Trim the val to 500 chars.
$val = $this->trim_string( $val );
$cleaned[ $key ] = $val;
}
return $cleaned;
}
この処理の実行結果をデバッグすると、metadataのキーが6/2 – Micro Sponsor [ 10USD
になっていることが判明しました。
if ( is_array( $metadata ) && ! empty( $metadata ) ) {
//$args['payment_intent_data']['metadata'] = $this->clean_metadata( $metadata );
$args['payment_intent_data']['metadata']['6/2 – Micro Sponsor [ 10USD'] = '1';
}
ここから処理を深堀していくと、StripeのAPIが返しているエラーメッセージともつながってきます。metadata
のkey
に[
が入っている場合、StripeへのAPIリクエストで、ネストしたオブジェクトとして解釈されている可能性が出てきました。エラーメッセージがInvalid value type
なのは、key – valueで構成されるべきmetadataにオブジェクトが挿入されようとしているからだということになります。
(
wordcamptest-wordcamp.test-1 | [error] => Array
wordcamptest-wordcamp.test-1 | (
wordcamptest-wordcamp.test-1 | [message] => Invalid value type: {:" 10USD"=>"1"} must be a string
wordcamptest-wordcamp.test-1 | [param] => payment_intent_data[metadata]
wordcamptest-wordcamp.test-1 | [request_log_url] => https://dashboard.stripe.com/test/logs/req_gnITaqetb4eMlK?t=1710744763
wordcamptest-wordcamp.test-1 | [type] => invalid_request_error
wordcamptest-wordcamp.test-1 | )
wordcamptest-wordcamp.test-1 | )
現象の再現を試みる
現象の再現を試みるため、clean_metadata
の代わりにデータを直接挿入してみました。
if ( is_array( $metadata ) && ! empty( $metadata ) ) {
//$args['payment_intent_data']['metadata'] = $this->clean_metadata( $metadata );
$args['payment_intent_data']['metadata']['6/2 [Sponsor ticket]'] = '1';
}
エラーログを監視していると、同様のエラーが発生していることが確認できます。やはりvalueに{“Sponsor ticket”: “1”}
というオブジェクトが入っている判定になっていました。
wordcamptest-wordcamp.test-1 | (
wordcamptest-wordcamp.test-1 | [error] => Array
wordcamptest-wordcamp.test-1 | (
wordcamptest-wordcamp.test-1 | [message] => Invalid value type: {:"Sponsor ticket"=>"1"} must be a string
wordcamptest-wordcamp.test-1 | [param] => payment_intent_data[metadata]
wordcamptest-wordcamp.test-1 | [request_log_url] => https://dashboard.stripe.com/test/logs/req_zORHubPRNZCGkc?t=1710744848
wordcamptest-wordcamp.test-1 | [type] => invalid_request_error
wordcamptest-wordcamp.test-1 | )
wordcamptest-wordcamp.test-1 | )
これはStripeのAPIが、APIリクエストの本文をapplication/x-www-form-urlencoded
で受け付けることが関連しているかもしれません。
metadataの値がオブジェクトにならないようにする
原因がわかったので対応を考えます。少なくとも[
と]
をmetadetaのキーに含まないよう、clean_metadata
の処理に足せば良さそうです。例えば次のような置換処理を入れてみても良さそうです。
$key = $this->trim_string( $key, 40, '' );
$key = str_replace( '[', '(', str_replace( ']', ')', $key ) );
こちらですと、StripeのAPIもエラーを返さずに処理が成功しました。
"payment_intent_data": {
"description": "New Site 2020",
"metadata": {
"6/2 – Micro Sponsor : マイクロスポンサーチケット ( ¥1": "1"
},
"statement_descriptor": "New Site 2020"
},
Pull requestで修正パッチを送信する
対処法がわかったので、あとはコードの提案をpull requestで行います。コードの提案がメンテナーからありましたので、それに従う形に更新した結果、無事マージされました。
やってみて
コミュニティ系のツールなどは、こうやってオープンにテストや検証、そしてコードの提案ができるのがいいですね。すぐに修正が反映されるとは限らないため、「今取り組んでいるイベント」に反映されるかの保証はありませんが、それでも次以降にやる人たちが、同じ問題に遭遇しなくなるというのは、コミュニティに対しても良い貢献になったのではないかと思います。
これをきっかけに、少しずつですがWordCampまわりのコードを触ったりもしているので、また何か進捗が出たら紹介します。