File "Process-20250523014439.php"
Full path: C:/Inetpub/vhosts/drshti.com/httpdocs/wp-content/plugins/wpforms-lite/src/Integrations/Square/Process-20250523014439.php
File
size: 31.23 B (31.23 KB bytes)
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor &nnbsp; Back
<?php
namespace WPForms\Integrations\Square;
use WP_Post;
use WPForms\Integrations\Square\Api\Api;
use WPForms\Vendor\Square\Models\Card;
use WPForms\Vendor\Square\Models\ErrorCode;
/**
* Square payment processing.
*
* @since 1.9.5
*/
class Process {
/**
* Form ID.
*
* @since 1.9.5
*
* @var int
*/
public $form_id = 0;
/**
* Sanitized submitted field values and data.
*
* @since 1.9.5
*
* @var array
*/
public $fields = [];
/**
* Form submission raw data ($_POST).
*
* @since 1.9.5
*
* @var array
*/
public $entry = [];
/**
* Form data and settings.
*
* @since 1.9.5
*
* @var array
*/
public $form_data = [];
/**
* Square payment settings.
*
* @since 1.9.5
*
* @var array
*/
public $settings = [];
/**
* Square credit card field.
*
* @since 1.9.5
*
* @var array
*/
public $cc_field = [];
/**
* Payment amount.
*
* @since 1.9.5
*
* @var string
*/
public $amount = '';
/**
* Payment currency.
*
* @since 1.9.5
*
* @var string
*/
public $currency = '';
/**
* Connection data.
*
* @since 1.9.5
*
* @var Connection
*/
public $connection;
/**
* Main class that communicates with the Square API.
*
* @since 1.9.5
*
* @var Api
*/
protected $api;
/**
* Processing errors.
*
* @since 1.9.5
*
* @var array
*/
protected $errors;
/**
* Save matched subscription settings.
*
* @since 1.9.5
*
* @var array
*/
private $subscription_settings = [];
/**
* Whether the payment has been processed.
*
* @since 1.9.5
*
* @var bool
*/
protected $is_payment_processed = false;
/**
* Initialize.
*
* @since 1.9.5
*/
public function init(): Process {
$this->hooks();
return $this;
}
/**
* Hooks.
*
* @since 1.9.5
*/
protected function hooks() {
add_action( 'wpforms_process', [ $this, 'process_entry' ], 10, 3 );
add_action( 'wpforms_process_complete', [ $this, 'update_entry_meta' ], 10, 4 );
add_filter( 'wpforms_forms_submission_prepare_payment_data', [ $this, 'prepare_payment_data' ], 10, 3 );
add_filter( 'wpforms_forms_submission_prepare_payment_meta', [ $this, 'prepare_payment_meta' ], 10, 3 );
add_action( 'wpforms_process_payment_saved', [ $this, 'process_payment_saved' ], 10, 3 );
add_filter( 'wpforms_process_bypass_captcha', [ $this, 'bypass_captcha' ] );
}
/**
* Check if a payment exists with an entry, if so validate and process.
*
* @since 1.9.5
*
* @param array $fields Final/sanitized submitted fields data.
* @param array $entry Copy of original $_POST.
* @param array $form_data Form data and settings.
*/
public function process_entry( $fields, array $entry, array $form_data ) {
$fields = (array) $fields;
// Check if payment method exists and is enabled.
if ( ! Helpers::is_payments_enabled( $form_data ) ) {
return;
}
$this->fields = $fields;
$this->entry = $entry;
$this->form_data = $form_data;
$this->form_id = isset( $form_data['id'] ) ? (int) $form_data['id'] : 0;
$this->settings = $form_data['payments']['square'];
$this->cc_field = $this->get_credit_card_field();
$this->currency = $this->get_currency();
$this->amount = $this->get_amount();
$this->connection = Connection::get();
// Before proceeding, check if any basic errors were detected.
if ( ! $this->is_form_processed() ) {
$this->display_errors();
return;
}
// Set an API instance.
$this->api = new Api( $this->connection );
// Set tokens provided by Web Payments SDK.
$this->api->set_payment_tokens( $entry );
// Proceed to executing the purchase.
$this->process_payment();
// Update the card field value to contain basic details.
$this->update_credit_card_field_value();
}
/**
* Bypass captcha if payment has been processed.
*
* @since 1.9.5
*
* @param bool $bypass_captcha Whether to bypass captcha.
*
* @return bool
*/
public function bypass_captcha( $bypass_captcha ): bool {
if ( (bool) $bypass_captcha ) {
return true;
}
return $this->is_payment_processed;
}
/**
* Check if form has errors before payment processing.
*
* @since 1.9.5
*
* @return bool
*/
private function is_form_processed(): bool {
// Bail in case there are form processing errors.
if ( ! empty( wpforms()->obj( 'process' )->errors[ $this->form_id ] ) ) {
return false;
}
if ( ! $this->is_card_field_visibility_ok() ) {
return false;
}
return $this->is_form_ok();
}
/**
* Check form settings, fields, etc.
*
* @since 1.9.5
*
* @return bool
*/
private function is_form_ok(): bool {
// Check for Square connection.
if ( ! $this->is_connection_ok() ) {
$error_title = esc_html__( 'Square payment stopped, account connection is missing.', 'wpforms-lite' );
$this->errors[] = $error_title;
$this->log_errors( $error_title );
return false;
}
// Check total charge amount.
// Square has different minimum amount limits by country.
if ( ! $this->is_amount_ok() ) {
$error_title = esc_html__( 'Square payment stopped, amount is smaller than the allowed minimum amount for a payment.', 'wpforms-lite' );
$this->errors[] = $error_title;
$this->log_errors(
$error_title,
[
'amount' => $this->amount,
'currency' => $this->currency,
]
);
return false;
}
// Check that, despite how the form is configured, the form and
// entry actually contain payment fields, otherwise no need to proceed.
if ( empty( $this->cc_field ) || ! wpforms_has_payment( 'form', $this->fields ) ) {
$error_title = esc_html__( 'Square payment stopped, missing payment fields.', 'wpforms-lite' );
$this->errors[] = $error_title;
$this->log_errors( $error_title );
return false;
}
return true;
}
/**
* Check if the Square credit card field in the form is visible (not hidden by conditional logic).
*
* @since 1.9.5
*
* @return bool
*/
private function is_card_field_visibility_ok(): bool {
// If the form doesn't contain the credit card field.
if ( empty( $this->cc_field ) ) {
return false;
}
// If the form contains no fields with conditional logic, the credit card field is visible by default.
if ( empty( $this->form_data['conditional_fields'] ) ) {
return true;
}
// If the credit card field is NOT in array of conditional fields, it's visible.
if ( ! in_array( $this->cc_field['id'], $this->form_data['conditional_fields'], true ) ) {
return true;
}
// If the credit card field IS in array of conditional fields and marked as visible, it's visible.
if ( ! empty( $this->cc_field['visible'] ) ) {
return true;
}
return false;
}
/**
* Check if connection exists, configured and valid.
*
* @since 1.9.5
*
* @return bool
*/
private function is_connection_ok(): bool {
return $this->connection !== null && $this->connection->is_usable();
}
/**
* Check if an amount is greater than the minimum amount.
*
* @since 1.9.5
*
* @link https://developer.squareup.com/docs/build-basics/working-with-monetary-amounts#monetary-amount-limits
*
* @return bool
*/
private function is_amount_ok(): bool {
$amount = Helpers::format_amount( $this->amount );
if ( $amount < 1 && in_array( $this->currency, [ 'USD', 'CAD' ], true ) ) {
return false;
}
if ( $amount < 100 && in_array( $this->currency, [ 'EUR', 'GBP', 'AUD', 'JPY' ], true ) ) {
return false;
}
return true;
}
/**
* Process a payment.
*
* @since 1.9.5
*/
private function process_payment() {
if ( ! empty( $this->settings['enable_recurring'] ) ) {
$this->process_payment_subscription();
return;
}
$this->process_payment_single();
}
/**
* Process a single payment.
*
* @since 1.9.5
*/
protected function process_payment_single() {
$args = $this->get_payment_args_single();
$this->api->process_single_transaction( $args );
// Set payment processing flag.
$this->is_payment_processed = true;
$this->process_api_errors( 'single' );
}
/**
* Process a subscription payment.
*
* @since 1.9.5
*/
private function process_payment_subscription() {
$args = $this->get_payment_args_general();
foreach ( $this->settings['recurring'] as $recurring ) {
if ( ! $this->is_subscription_plan_valid( $recurring ) ) {
continue;
}
// Put subscription arguments into its own key.
$args['subscription'] = $this->get_payment_args_subscription( $recurring );
$this->subscription_settings = $args['subscription'];
$this->api->process_subscription_transaction( $args );
// Set payment processing flag.
$this->is_payment_processed = true;
$this->process_api_errors( 'subscription' );
return;
}
if ( ! empty( $this->settings['enable_one_time'] ) ) {
$this->process_payment_single();
return;
}
$this->log_errors(
esc_html__( 'Square Subscription payment stopped validation error.', 'wpforms-lite' ),
$this->fields,
'conditional_logic'
);
}
/**
* Retrieve subscription payment args.
*
* @since 1.9.5
*
* @param array $plan Plan settings.
*
* @return array
*/
private function get_payment_args_subscription( array $plan ): array {
$args_sub['customer']['email'] = sanitize_email( $this->fields[ $plan['customer_email'] ]['value'] );
$args_sub['customer']['first_name'] = sanitize_text_field( $this->fields[ $plan['customer_name'] ]['first'] );
$args_sub['customer']['last_name'] = sanitize_text_field( $this->fields[ $plan['customer_name'] ]['last'] );
// If a Name field has the `Simple` format.
if (
empty( $args_sub['customer']['first_name'] ) &&
empty( $args_sub['customer']['last_name'] ) &&
! empty( $this->fields[ $plan['customer_name'] ]['value'] )
) {
$args_sub['customer']['last_name'] = sanitize_text_field( $this->fields[ $plan['customer_name'] ]['value'] );
}
// Customer address.
if ( isset( $plan['customer_address'] ) && $plan['customer_address'] !== '' && wpforms()->is_pro() ) {
$args_sub['customer']['address'] = $this->fields[ $plan['customer_address'] ];
}
$cadences_list = Helpers::get_subscription_cadences();
$phase_cadence = $cadences_list[ $plan['phase_cadence'] ] ?? $cadences_list['yearly'];
// Subscription cadence.
$args_sub['phase_cadence'] = $phase_cadence;
$plan_name = $this->get_form_name();
$plan_name .= empty( $plan['name'] ) ? '' : ': ' . $plan['name'];
$args_sub['plan_name'] = sprintf( '%s (%s)', $plan_name, $phase_cadence['name'] );
$args_sub['plan_variation_name'] = sprintf( '%s (%s %s %s)', $plan['name'], $this->amount, $this->currency, $phase_cadence['name'] );
// Card holder.
$args_sub['card_name'] = empty( $this->fields[ $this->cc_field['id'] ]['cardname'] ) ? '' : sanitize_text_field( $this->fields[ $this->cc_field['id'] ]['cardname'] );
/**
* Filter subscription payment arguments.
*
* @since 1.9.5
*
* @param array $args The subscription payment arguments.
* @param Process $process The Process instance.
*/
return (array) apply_filters( 'wpforms_integrations_square_process_get_payment_args_subscription', $args_sub, $this );
}
/**
* Validate plan before process.
*
* @since 1.9.5
*
* @param array $plan Plan settings.
*
* @return bool
*/
protected function is_subscription_plan_valid( array $plan ): bool {
return ! empty( $plan['customer_email'] ) && $this->is_recurring_settings_ok( $plan );
}
/**
* Check if recurring settings is configured correctly.
*
* @since 1.9.5
*
* @param array $settings Settings data.
*
* @return bool
*/
protected function is_recurring_settings_ok( array $settings ): bool {
$error = '';
// Check subscription settings are provided.
if ( empty( $settings['phase_cadence'] ) || empty( $settings['customer_email'] ) || empty( $settings['customer_name'] ) ) {
$error = esc_html__( 'Square subscription payment stopped, missing form settings.', 'wpforms-lite' );
}
// Check for required customer email.
if ( ! $error && empty( $this->fields[ $settings['customer_email'] ]['value'] ) ) {
$error = esc_html__( 'Square subscription payment stopped, customer email not found.', 'wpforms-lite' );
}
// Check for required customer name.
if ( ! $error && empty( $this->fields[ $settings['customer_name'] ]['value'] ) ) {
$error = esc_html__( 'Square subscription payment stopped, customer name not found.', 'wpforms-lite' );
}
// Before proceeding, check if any basic errors were detected.
if ( $error ) {
$this->log_errors( $error, $settings );
return false;
}
return true;
}
/**
* Retrieve single payment args.
*
* @since 1.9.5
*
* @return array
*/
private function get_payment_args_single(): array {
$args = $this->get_payment_args_general();
$customer_name = $this->get_customer_name();
$customer_email = $this->get_customer_email();
// Billing Name.
if ( isset( $customer_name['first_name'] ) ) {
$args['billing']['first_name'] = sanitize_text_field( $customer_name['first_name'] );
}
if ( isset( $customer_name['last_name'] ) ) {
$args['billing']['last_name'] = sanitize_text_field( $customer_name['last_name'] );
}
// Billing Address.
if ( ! empty( $this->fields[ $this->settings['billing_address'] ] ) ) {
$args['billing']['address'] = $this->fields[ $this->settings['billing_address'] ];
}
// Buyer Email.
if ( ! empty( $customer_email ) ) {
$args['buyer_email'] = sanitize_email( $customer_email );
}
// Payment description.
$description = empty( $this->settings['payment_description'] ) ? $this->get_form_name() : html_entity_decode( $this->settings['payment_description'], ENT_COMPAT, 'UTF-8' );
// The maximum length for the Square notes field is 500 characters.
$args['note'] = wp_html_excerpt( Square::APP_NAME . ': ' . $description, 500 );
// Order items.
$args['order_items'] = $this->get_order_items();
/**
* Filter single payment arguments.
*
* @param array $args The single payment arguments.
* @param Process $process The Process instance.
*
*@since 1.9.5
*/
return (array) apply_filters( 'wpforms_square_process_get_payment_args_single', $args, $this ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
}
/**
* Retrieve arguments for any type of payment.
*
* @since 1.9.5
*
* @return array
*/
private function get_payment_args_general(): array {
/**
* Filter arguments for any type of payment.
*
* @since 1.9.5
*
* @param array $args The general payment arguments.
* @param Process $process The Process instance.
*/
return (array) apply_filters( // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
'wpforms_square_process_get_payment_args_general',
[
'amount' => Helpers::format_amount( $this->amount ),
'currency' => $this->currency,
'location_id' => Helpers::get_location_id(),
],
$this
);
}
/**
* Retrieve a payment currency.
*
* @since 1.9.5
*
* @return string
*/
private function get_currency(): string {
return strtoupper( wpforms_get_currency() );
}
/**
* Retrieve a payment amount.
*
* @since 1.9.5
*
* @return string
*/
private function get_amount(): string {
$amount = wpforms_get_total_payment( $this->fields );
return $amount === false ? wpforms_sanitize_amount( 0 ) : $amount;
}
/**
* Retrieve order items.
*
* @since 1.9.5
*
* @return array
*/
private function get_order_items(): array {
/**
* Filter order items types.
*
* @since 1.9.5
*
* @param array $types The order items types.
*/
$types = (array) apply_filters( 'wpforms_square_process_get_order_items_types', wpforms_payment_fields() ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
$items = [];
foreach ( $this->fields as $field_id => $field ) {
if (
empty( $field['type'] ) ||
! in_array( $field['type'], $types, true )
) {
continue;
}
// Skip payment field that is not filled in.
if (
! isset( $this->entry['fields'][ $field_id ] ) ||
wpforms_is_empty_string( $this->entry['fields'][ $field_id ] )
) {
continue;
}
$items[] = $this->prepare_order_line_item( $field );
}
return $items;
}
/**
* Retrieve a Form Name.
*
* @since 1.9.5
*
* @return string
*/
private function get_form_name(): string {
if ( ! empty( $this->form_data['settings']['form_title'] ) ) {
return sanitize_text_field( $this->form_data['settings']['form_title'] );
}
$fallback = sprintf( /* translators: %d - Form ID. */
esc_html__( 'Form #%d', 'wpforms-lite' ),
$this->form_id
);
$form_obj = wpforms()->obj( 'form' );
if ( ! $form_obj ) {
return $fallback;
}
$form = $form_obj->get( $this->form_id );
return $form instanceof WP_Post ? $form->post_title : $fallback;
}
/**
* Retrieve a Square credit card field.
*
* @since 1.9.5
*
* @return array
*/
private function get_credit_card_field(): array {
if ( ! is_array( $this->fields ) ) {
return [];
}
foreach ( $this->fields as $field ) {
if ( ! empty( $field['type'] ) && $field['type'] === 'square' ) {
return $field;
}
}
return [];
}
/**
* Prepare order line item.
*
* @since 1.9.5
*
* @param array $field Field data.
*
* @return array
*/
private function prepare_order_line_item( array $field ): array {
$field_id = absint( $field['id'] );
$quantity = isset( $field['quantity'] ) ? (int) $field['quantity'] : 1;
$name = empty( $field['name'] ) ? sprintf( /* translators: %d - Field ID. */ esc_html__( 'Field #%d', 'wpforms-lite' ), $field_id ) : $field['name'];
$item = [
'name' => $name,
'quantity' => $quantity,
];
if ( empty( $field['value_raw'] ) ) {
$item['amount'] = Helpers::format_amount( $field['amount_raw'] );
return $item;
}
return $this->prepare_order_line_item_variations( $item, $field, $field_id );
}
/**
* Prepare order line item variations.
*
* @since 1.9.5
*
* @param array $item Item data.
* @param array $field Field data.
* @param int $field_id Field ID.
*
* @return array
*/
private function prepare_order_line_item_variations( array $item, array $field, int $field_id ): array {
$values = explode( ',', $field['value_raw'] );
foreach ( $values as $value ) {
if ( empty( $this->form_data['fields'][ $field_id ]['choices'][ $value ] ) ) {
continue;
}
$choice = $this->form_data['fields'][ $field_id ]['choices'][ $value ];
$item['variations'][] = [
'name' => $item['name'],
'quantity' => $item['quantity'],
'variation_name' => empty( $choice['label'] ) ? sprintf( /* translators: %d - Choice ID. */ esc_html__( 'Choice %d', 'wpforms-lite' ), absint( $value ) ) : $choice['label'],
'amount' => Helpers::format_amount( $choice['value'] ),
];
}
return $item;
}
/**
* Display form errors.
*
* @since 1.9.5
*
* @param array $errors Errors to display.
*/
private function display_errors( array $errors = [] ) {
if ( ! $errors ) {
$errors = $this->errors;
}
if ( ! $errors || ! is_array( $errors ) ) {
return;
}
// Check if the form contains a required credit card. If it does
// and there was an error, return the error to the user and prevent
// the form from being submitted. This should not occur under normal
// circumstances.
if ( empty( $this->cc_field ) || empty( $this->form_data['fields'][ $this->cc_field['id'] ] ) ) {
return;
}
if ( ! empty( $this->form_data['fields'][ $this->cc_field['id'] ]['required'] ) ) {
wpforms()->obj( 'process' )->errors[ $this->form_id ]['footer'] = implode( '<br>', $errors );
}
}
/**
* Collect errors from API and turn it into form errors.
*
* @since 1.9.5
*
* @param string $type Payment type (e.g. 'single').
*/
private function process_api_errors( string $type ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
$errors = $this->api->get_errors();
if ( empty( $errors ) || ! is_array( $errors ) ) {
return;
}
$this->display_errors( $errors );
if ( $type === 'subscription' ) {
$title = esc_html__( 'Square subscription payment stopped', 'wpforms-lite' );
} else {
$title = esc_html__( 'Square payment stopped', 'wpforms-lite' );
}
$_errors = $this->api->get_response_errors();
if ( ! empty( $_errors ) ) {
$this->process_api_errors_codes( $_errors );
$errors[] = $_errors;
}
// Log transaction specific errors.
$this->log_errors( $title, $errors );
}
/**
* Check specific error codes.
*
* @since 1.9.5
*
* @param array $errors The last API call errors.
*/
private function process_api_errors_codes( array $errors ) {
$codes = $this->get_oauth_error_codes();
foreach ( $errors as $error ) {
if (
empty( $error['code'] ) ||
! in_array( $error['code'], $codes, true )
) {
continue;
}
// If the error indicates that access token is bad, set a connection as invalid.
$this->connection
->set_status( Connection::STATUS_INVALID )
->save();
}
}
/**
* Retrieve OAuth-related errors.
*
* @since 1.9.5
*
* @link https://developer.squareup.com/docs/oauth-api/best-practices#ensure-api-calls-made-with-oauth-tokens-handle-token-based-errors-appropriately
*
* @return array
*/
private function get_oauth_error_codes(): array {
return [ ErrorCode::ACCESS_TOKEN_EXPIRED, ErrorCode::ACCESS_TOKEN_REVOKED, ErrorCode::UNAUTHORIZED ];
}
/**
* Log payment errors.
*
* @since 1.9.5
*
* @param string $title Error title.
* @param array|string $messages Error messages.
* @param string $level Error level to add to 'payment' error level.
*/
protected function log_errors( string $title, $messages = [], string $level = 'error' ) {
wpforms_log(
$title,
$messages,
[
'type' => [ 'payment', $level ],
'form_id' => $this->form_id,
]
);
}
/**
* Update the credit card field value to contain basic details.
*
* @since 1.9.5
*/
private function update_credit_card_field_value() {
if ( $this->errors || ! $this->api ) {
return;
}
// Get a card.
$card = $this->get_card();
if ( empty( $card ) ) {
return;
}
$details = [
'brand' => $card->getCardBrand(),
'last4' => $card->getLast4(),
'holder' => $this->get_card_holder( $card ),
];
$details = implode( "\n", array_filter( $details ) );
/**
* Filter a credit card field value by card details.
*
* @since 1.9.5
*
* @param string $details Card details.
* @param Process $process Process object.
*/
$details = apply_filters( // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
'wpforms_square_process_update_credit_card_field_value',
$details,
$this
);
wpforms()->obj( 'process' )->fields[ $this->cc_field['id'] ]['value'] = $details;
}
/**
* Get card object.
*
* @since 1.9.5
*
* @return Card|array
*/
private function get_card() {
$resource = $this->api->get_response_resource();
if ( empty( $resource ) ) {
return [];
}
$type = Helpers::array_key_first( $resource );
return $type === 'subscription' ? $this->api->get_subscription_card( $resource[ $type ] ) : $resource[ $type ]->getCardDetails()->getCard();
}
/**
* Update entry details and add meta for a successful payment.
*
* @since 1.9.5
*
* @param array $fields Final/sanitized submitted field data.
* @param array $entry Copy of original $_POST.
* @param array $form_data Form data and settings.
* @param string $entry_id Entry ID.
*/
public function update_entry_meta( $fields, array $entry, array $form_data, string $entry_id ) {
$fields = (array) $fields;
if ( empty( $entry_id ) || $this->errors || ! $this->api ) {
return;
}
$resource = $this->api->get_response_resource();
if ( empty( $resource ) ) {
return;
}
wpforms()->obj( 'entry' )->update(
$entry_id,
[
'type' => 'payment',
],
'',
'',
[ 'cap' => false ]
);
/**
* Fire when entry details and add meta was successfully updated.
*
* @since 1.9.5
*
* @param array $fields Final/sanitized submitted field data.
* @param array $form_data Form data and settings.
* @param string $entry_id Entry ID.
* @param array $resource Response resource data.
* @param Process $process Process class instance.
*/
do_action( 'wpforms_square_process_update_entry_meta', $fields, $form_data, $entry_id, $resource, $this ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
}
/**
* Add details to payment data.
*
* @since 1.9.5
*
* @param array $payment_data Payment data args.
* @param array $fields Final/sanitized submitted field data.
* @param array $form_data Form data and settings.
*
* @return array
*/
public function prepare_payment_data( $payment_data, array $fields, array $form_data ): array { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
$payment_data = (array) $payment_data;
// If there are errors or API is not initialized, return the original payment data.
if ( $this->errors || ! $this->api ) {
return $payment_data;
}
$resource = $this->api->get_response_resource();
// If the resource is empty, return the original payment meta.
if ( empty( $resource ) ) {
return $payment_data;
}
$type = Helpers::array_key_first( $resource );
$payment = $resource[ $type ];
$is_subscription = $type === 'subscription';
$payment_data['status'] = 'processed';
$payment_data['gateway'] = 'square';
$payment_data['mode'] = Helpers::is_sandbox_mode() ? 'test' : 'live';
$payment_data['customer_id'] = sanitize_text_field( $payment->getCustomerId() );
$payment_data['title'] = $this->get_payment_title( $payment );
if ( $is_subscription ) {
$payment_data['subscription_id'] = sanitize_text_field( $payment->getId() );
$payment_data['subscription_status'] = 'not-synced';
return $payment_data;
}
$payment_data['transaction_id'] = sanitize_text_field( $payment->getId() );
return $payment_data;
}
/**
* Get Payment title.
*
* @since 1.9.5
*
* @param object $payment Payment object.
*
* @return string Payment title.
*/
private function get_payment_title( $payment ): string {
// Look for the cardholder name.
$card = $this->get_card();
$customer_name = $card ? $this->get_card_holder( $card ) : '';
if ( $customer_name ) {
return sanitize_text_field( $customer_name );
}
$customer_name = $this->get_customer_name();
if ( $customer_name ) {
return sanitize_text_field( implode( ' ', array_values( $customer_name ) ) );
}
$customer_email = $this->get_customer_email();
if ( $customer_email ) {
return sanitize_email( $customer_email );
}
return '';
}
/**
* Add payment meta for a successful one-time or subscription payment.
*
* @since 1.9.5
*
* @param array $payment_meta Payment meta.
* @param array $fields Final/sanitized submitted field data.
* @param array $form_data Form data and settings.
*
* @return array
*/
public function prepare_payment_meta( $payment_meta, array $fields, array $form_data ): array { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
$payment_meta = (array) $payment_meta;
// If there are errors or API is not initialized, return the original payment meta.
if ( $this->errors || ! $this->api ) {
return $payment_meta;
}
$resource = $this->api->get_response_resource();
// If the resource is empty, return the original payment meta.
if ( empty( $resource ) ) {
return $payment_meta;
}
$type = Helpers::array_key_first( $resource );
$credit_card_details = $this->get_card();
$is_subscription = $type === 'subscription';
if ( $is_subscription ) {
$payment_meta['subscription_period'] = $this->subscription_settings['phase_cadence']['slug'];
}
$payment_meta['method_type'] = 'card';
if ( ! empty( $credit_card_details ) ) {
$payment_meta['credit_card_last4'] = $credit_card_details->getLast4();
$payment_meta['credit_card_expires'] = $credit_card_details->getExpMonth() . '/' . $credit_card_details->getExpYear();
$payment_meta['credit_card_method'] = strtolower( $credit_card_details->getCardBrand() );
$payment_meta['credit_card_name'] = $this->get_card_holder( $credit_card_details );
}
// Add a log indicating that the charge was successful.
$payment_meta['log'] = $this->format_payment_log( 'Square payment was created.' );
return $payment_meta;
}
/**
* Add payment info for successful payment.
*
* @since 1.9.5
*
* @param string $payment_id Payment ID.
* @param array $fields Final/sanitized submitted field data.
* @param array $form_data Form data and settings.
*/
public function process_payment_saved( $payment_id, array $fields, array $form_data ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
$payment_id = (string) $payment_id;
// If there are errors or API is not initialized, return the original payment meta.
if ( $this->errors || ! $this->api ) {
return;
}
$resource = $this->api->get_response_resource();
// If the resource is empty, return the original payment meta.
if ( empty( $resource ) ) {
return;
}
$type = Helpers::array_key_first( $resource );
if ( $type === 'subscription' ) {
$this->api->update_subscription(
[
'id' => $resource[ $type ]->getId(),
'payment_id' => $payment_id,
]
);
return;
}
wpforms()->obj( 'payment_meta' )->add_log(
$payment_id,
sprintf(
'Square payment was processed. (Receipt ID: %s)',
$resource[ $type ]->getReceiptNumber()
)
);
}
/**
* Return payment log value.
*
* @since 1.9.5
*
* @param string $value Log value.
*
* @return string
*/
private function format_payment_log( string $value ): string {
return wp_json_encode(
[
'value' => sanitize_text_field( $value ),
'date' => gmdate( 'Y-m-d H:i:s' ),
]
);
}
/**
* Get Customer name.
*
* @since 1.9.5
*
* @return array
*/
private function get_customer_name(): array {
$customer_name = [];
// Billing first name.
if ( ! empty( $this->fields[ $this->settings['billing_name'] ]['first'] ) ) {
$customer_name['first_name'] = $this->fields[ $this->settings['billing_name'] ]['first'];
}
// Billing last name.
if ( ! empty( $this->fields[ $this->settings['billing_name'] ]['last'] ) ) {
$customer_name['last_name'] = $this->fields[ $this->settings['billing_name'] ]['last'];
}
// If a Name field has the `Simple` format.
if (
empty( $customer_name['first_name'] ) &&
empty( $customer_name['last_name'] ) &&
! empty( $this->fields[ $this->settings['billing_name'] ]['value'] )
) {
$customer_name['first_name'] = $this->fields[ $this->settings['billing_name'] ]['value'];
}
return $customer_name;
}
/**
* Get Customer email.
*
* @since 1.9.5
*
* @return string
*/
private function get_customer_email(): string {
return ! empty( $this->fields[ $this->settings['buyer_email'] ]['value'] ) ? $this->fields[ $this->settings['buyer_email'] ]['value'] : '';
}
/**
* Retrieve a Cardholder Name.
*
* @since 1.9.5
*
* @param Card $card Card object.
*
* @return string
*/
private function get_card_holder( $card ): string {
$holder = '';
if ( $card instanceof Card ) {
$holder = $card->getCardholderName();
}
if ( empty( $holder ) && isset( $this->cc_field['cardname'] ) ) {
$holder = $this->cc_field['cardname'];
}
return $holder;
}
}