WordPress(以下wp)とWooCommerce(以下wc)でSquareを使ってオンラインショップを作るメモ。
下記日本語化の入力チェックについてのメモ。
カード番号が未入力などの入力チェックのエラーメッセージは、javascriptで出力されている。

エラーメッセージをどのように出力しているのか表示の方から追ってみた。
解析
まず、出力しているのは下記ソース。
/plugins/woocommerce-square/assets/js/frontend/wc-square.min.js
コンパイル前のソースは、
/plugins/woocommerce-square/assets/js/frontend/wc-square.coffee
530行目以降のrender_errors()にて、引数で渡されたエラーメッセージの配列を、liタグで繋いでulタグで囲って出力している。
# Public: Render any new errors and bring them into the viewport
#
# Returns nothing.
render_errors: (errors) ->
# hide and remove any previous errors
$( '.woocommerce-error, .woocommerce-message' ).remove()
# add errors
@form.prepend '<ul class="woocommerce-error"><li>' + errors.join( '</li><li>' ) + '</li></ul>'
# unblock UI
@form.removeClass( 'processing' ).unblock()
@form.find( '.input-text, select' ).blur()
# scroll to top
$( 'html, body' ).animate( { scrollTop: @form.offset().top - 100 }, 1000 )
このrender_errors()が呼ばれるのは493行目のhandle_errors()。
引数で渡されたエラーメッセージの配列を一つずつ、エラーの種類で判断して変数(messages)に入れ、render_errors()に渡している。
# Handle error data.
#
# @since 2.0.0
# @param Object[]
handle_errors: ( errors = null ) ->
this.log 'Error getting payment data', 'error'
# clear any previous nonces
$( "input[name=wc-square-credit-card-payment-nonce]" ).val( '' )
$( "input[name=wc-square-credit-card-buyer-verification-token]" ).val( '' )
messages = []
if errors
console.error errors
$( errors ).each ( index, error ) =>
# only display the errors that can be helped by the customer
if error.type in [ 'UNSUPPORTED_CARD_BRAND', 'VALIDATION_ERROR' ]
messages.push( error.message )
# otherwise, log more serious errors to the debug log
else
this.log_data( errors, 'response' )
# if no specific messages are set, display a general error
if messages.length is 0
messages.push( @general_error )
this.render_errors( messages )
this.unblock_ui()
handle_errors()が呼ばれているのは数箇所。
入力チェックで通るのは、400行目のhandle_verify_buyer_response()内。
引数で渡された内容がエラーだったらhandle_errors()を呼ぶ。
エラーが無ければ結果のトークンをセットしてsubmit()する。
# Handles the response from a call to verifyBuyer()
#
# @since 2.1.0
#
# @param Object[] errors verification errors, if any
# @param Object verification_result the results of verification
handle_verify_buyer_response: ( errors, verification_result ) =>
if errors
return this.handle_errors( errors )
# no errors, but also no verification token
if not verification_result or not verification_result.token
message = 'Verification token is missing from the Square response'
this.log message, 'error'
this.log_data message, 'response'
return this.handle_errors()
this.log 'Verification result received'
this.log verification_result
$( "input[name=wc-#{@id_dasherized}-buyer-verification-token]" ).val( verification_result.token )
@form.submit()
handle_verify_buyer_response()が呼ばれる2箇所のうち、入力チェックは318行目のvalidate_payment_data()内。
それっぽい関数名になったw
@payment_form.verifyBuyer()の引数でhandle_verify_buyer_response()が渡されている。
# Used to request a card nonce and submit the form.
#
# @since 2.0.0
validate_payment_data: ->
# bail when already processing
return false if @form.is( '.processing' )
# let through if nonce is already present - nonce is only present on non-tokenized payments
if this.has_nonce()
this.log 'Payment nonce present, placing order'
return true
tokenized_card_id = this.get_tokenized_payment_method_id()
if tokenized_card_id
# if 3DS is disabled and paying with a saved method, no further validation needed
return true unless @is_3ds_enabled
if this.has_verification_token()
this.log 'Tokenized payment verification token present, placing order'
return true
this.log 'Requesting verification token for tokenized payment'
this.block_ui()
@payment_form.verifyBuyer tokenized_card_id, this.get_verification_details(), this.handle_verify_buyer_response
return false
this.log 'Requesting payment nonce'
this.block_ui()
@payment_form.requestCardNonce()
return false
payment_formは、190行目で作成されているSqPaymentFormクラス。
# Sets up the Square payment fields
#
# @since 2.0.0
set_payment_fields: =>
if $( "#wc-#{@id_dasherized}-account-number-hosted" ).is( 'iframe' )
this.log 'Re-adding payment form'
for _, field of @form_fields
$( field.attr( 'id' ) ).replaceWith( field )
this.handle_form_loaded()
else
if @payment_form
this.log 'Destroying payment form'
@payment_form.destroy()
this.log 'Building payment form'
@payment_form = new SqPaymentForm( this.get_form_params() )
@payment_form.build()
SqPaymentFormクラスは、下記外部サーバーのjavascriptファイルにて定義されている。
https://js.squareup.com/v2/paymentform/ver=...
ソースを確認するには、chromeであれば右クリックで”検証”、または右上のメニューから”その他のツール”→デベロッパーツールを開く。
Sources を選ぶ。

該当のファイルをクリックし、左下の {} を押す。

Ctrl (⌘)+ F で検索窓を開き”SqPaymentForm”と入力するとたくさん出てくるが、一番下で定義されている。
}
}
}
, Tt = Et;
window.SqPaymentForm = Tt
}
]);
Tt は、その上の行で Et が代入されてるため実態はEt。
Etは7340行目から定義されている。
function Et(t) {
this.options = t;
try {
this._initialize()
} catch (t) {
throw this.eventstream && this.eventstream.track(B.a.GENERAL_EVENT, Pt(t)),
this.errorLogger && this.errorLogger.capture(t),
t
}
}
@payment_form.verifyBuyer()の実態は、7456行目にある。
引数で渡したhandle_verify_buyer_response()はnとなり、7473行目で実行される。
Et.prototype.verifyBuyer = function(t, e, n) {
var i = this;
if (this._trackVerificationRequested(),
!this.options.locationId && !this.options.accountId)
throw this._trackVerificationError("No location id given"),
new TypeError("`locationId` is required");
if (!e.billingContact || "object" !== _t(e.billingContact))
throw this._trackVerificationError("billingContact not given"),
new TypeError("`verificationDetails.billingContact` is required and must be an object");
var r = {
applicationId: this.options.applicationId,
locationId: this.options.locationId,
accountId: this.options.accountId
};
d.verifyBuyer(r, t, e, function(t, e) {
t && i._trackVerificationError(t.message),
e ? i._trackVerificationSuccess() : i._trackVerificationError("No token generated"),
n(t, e)
})
}
n(t, e)にメッセージが渡ってくるはず。
しかし、もうここまで来ると解析も面倒・・・。
諦めてメッセージから逆検索することにする。
その結果見つけたのは下記の中。
https://pci-connect.squareup.com/v2/iframe?type=main&app_id~

下の検索窓に Credit card number is not valid を入れると該当箇所がわかる。
2か所該当した。

Squareはこの辺りのスクリプトを経由してメッセージを出してるようだ。
対策
外部サーバーにあるのはどうしようもない。
仕方ない、プラグイン内のファイルを上書きするか・・・。
これを参考にする人は自己責任でお願いします。
といっても、直接上書きするのは危険すぎるので、テーマ内にjavascriptを複製し読み込み先を変えることにする。
複製するのは、メッセージを出力している下記ファイル。
/plugins/woocommerce-square/assets/js/frontend/wc-square.coffee
テーマ内に、custom-square.coffeeなどの名前にしておく。
coffeeスクリプトなので、gulp-coffeeでcustom-square.min.jsなどに変換する。
修正したのは512行目辺りのメッセージを代入しているところ。
$( errors ).each ( index, error ) =>
# only display the errors that can be helped by the customer
if error.type in [ 'UNSUPPORTED_CARD_BRAND', 'VALIDATION_ERROR' ]
messages.push( error.message )
# otherwise, log more serious errors to the debug log
error.messageの内容で変換してから代入するように変える。
$( errors ).each ( index, error ) =>
# only display the errors that can be helped by the customer
if error.type in [ 'UNSUPPORTED_CARD_BRAND', 'VALIDATION_ERROR' ]
switch error.message
when 'Credit card number is not valid'
message_jp = 'クレジットカード番号が不正です'
when 'CVV is not valid'
message_jp = 'セキュリティコードが不正です'
when 'Expiration date is not valid'
message_jp = '有効期限が不正です'
when 'Postal code is not valid'
message_jp = '郵便番号が不正です'
when 'The provided card was declined, please use an alternate card or other form of payment.'
message_jp = 'カードは拒否されました。別のカードまたは他のお支払い方法をご利用ください'
when 'An error occurred, please try again or try an alternate form of payment.'
message_jp = 'エラーが発生しました。もう一度試すか、別のお支払い方法をお試しください'
else
message_jp = error.message
messages.push( message_jp )
# otherwise, log more serious errors to the debug log
そしてfuncstions.phpにて、wc-square.min.js を出力しないようにする。
function custom_print_scripts() {
wp_dequeue_script('wc-square');
}
add_action('wp_print_scripts', 'custom_print_scripts', 100);
代わりに、custom-square.min.jsを読み込ませる。
/**
* footer
*/
function custom_footer() {
// 決済ページ
if (get_the_ID() === 7) {
wp_enqueue_script( 'square-script', get_stylesheet_directory_uri() . '/js/custom-square.min.js' );
}
}
add_action( 'wp_footer', 'custom_footer');
これで下記のように日本語化される。

ただし、woocommerce-squareのバージョンが上がった場合は、変更箇所を確認し、必要に応じ再度同じ作業をする。