File "Frontend.php"

Full Path: /home/buyiwexj/public_html/wp-content/plugins/wpforms-lite/src/Integrations/PayPalCommerce/Frontend/Frontend.php
File size: 23.37 KB
MIME-type: text/x-php
Charset: utf-8

<?php

namespace WPForms\Integrations\PayPalCommerce\Frontend;

use WP_Post;
use WPForms\Integrations\PayPalCommerce\Connection;
use WPForms\Integrations\PayPalCommerce\Helpers;
use WPForms\Integrations\PayPalCommerce\PaypalCommerce; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement
use Generator;

/**
 * Frontend-related functionality.
 *
 * @since 1.10.0
 */
class Frontend {

	/**
	 * An array to hold the enabled funding sources for a specific configuration or operation.
	 *
	 * @since 1.10.0
	 *
	 * @var PaymentMethodInterface[]
	 */
	private $payment_methods = [];

	/**
	 * Represents the currency associated with a particular transaction or operation.
	 *
	 * @since 1.10.0
	 *
	 * @var string
	 */
	private $currency = '';

	/**
	 * Initialize the payment methods array and fire the init action hook.
	 *
	 * This method resets the payment methods array and triggers an action hook that allows
	 * payment method modules to register themselves using the add_payment_method() method.
	 *
	 * @since 1.10.0
	 *
	 * @see add_payment_method() For adding payment methods to the registration.
	 */
	public function init(): void {

		$this->currency = strtoupper( wpforms_get_currency() );

		$this->hooks();

		/**
		 * Fires after the Enqueues class is initialized, allowing payment methods to register.
		 *
		 * Payment method modules (Apple Pay, Google Pay, RegionalPayments, etc.) should hook into
		 * this action to add their PaymentMethod instances to the Enqueues class using the
		 * add_payment_method() method.
		 *
		 * @since 1.10.0
		 *
		 * @param Frontend $enqueues The Enqueues instance for adding payment methods.
		 */
		do_action( 'wpforms_integrations_paypal_commerce_frontend_init', $this ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
	}

	/**
	 * Register hooks.
	 *
	 * @since 1.10.0
	 */
	private function hooks(): void {

		add_action( 'wpforms_frontend_container_class', [ $this, 'form_container_class' ], 10, 2 );
		add_action( 'wpforms_frontend_output_form_before', [ $this, 'maybe_refresh_tokens' ], 10, 2 );

		// Load assets on later stage after all our payment addons.
		add_action( 'wpforms_wp_footer', [ $this, 'enqueues' ], PHP_INT_MAX );
		add_filter( 'script_loader_tag', [ $this, 'set_script_attributes' ], 10, 2 );
	}

	/**
	 * Add the class to a form container if PayPal Commerce is enabled.
	 *
	 * @since 1.10.0
	 *
	 * @param array $classes   Array of form classes.
	 * @param array $form_data Form data of current form.
	 *
	 * @return array
	 *
	 * @noinspection PhpMissingParamTypeInspection
	 */
	public function form_container_class( $classes, array $form_data ): array {

		$classes = (array) $classes;

		if ( ! Connection::get() ) {
			return $classes;
		}

		if ( ! Helpers::has_paypal_commerce_field( $form_data ) ) {
			return $classes;
		}

		if ( ! Helpers::is_subscriptions_configured( $form_data ) ) {
			return $classes;
		}

		if ( Helpers::is_paypal_commerce_enabled( $form_data ) ) {
			$classes[] = 'wpforms-paypal-commerce';
		}

		return $classes;
	}

	/**
	 * Enqueue assets in the frontend if PayPal Commerce is in use on the page.
	 *
	 * @since 1.10.0
	 *
	 * @param array $forms Form data of forms on the current page.
	 */
	public function enqueues( $forms ): void {

		$forms = (array) $forms;

		$connection = Connection::get();

		if (
			! $connection ||
			! $connection->is_usable() ||
			! Helpers::has_paypal_commerce_field( $forms, true ) ||
			! Helpers::is_paypal_commerce_forms_enabled( $forms )
		) {
			return;
		}

		$this->enqueues_styles();
		$this->set_payment_methods( $forms );

		$min = wpforms_get_min_suffix();

		wp_enqueue_script(
			'wpforms-paypal-commerce',
			WPFORMS_PLUGIN_URL . "assets/js/integrations/paypal-commerce/wpforms-paypal-commerce{$min}.js",
			[ 'jquery' ],
			WPFORMS_VERSION,
			true
		);

		// Register PaymentHandler class first (required by Apple Pay and Google Pay).
		wp_register_script(
			'wpforms-paypal-commerce-payment-method',
			WPFORMS_PLUGIN_URL . "assets/js/integrations/paypal-commerce/payment-methods/base-payment-method{$min}.js",
			[ 'wpforms-paypal-commerce' ],
			WPFORMS_VERSION,
			true
		);

		// Get enabled payment types to conditional load scripts.
		[ $is_single, $is_recurring ] = $this->get_enabled_payment_types( $forms );

		// Enqueue a single payment script if one-time payments are enabled.
		if ( $is_single ) {
			$this->enqueue_single_sdk_script( $connection );
		}

		// Enqueue subscriptions script if recurring payments are enabled.
		if ( $is_recurring ) {
			$this->enqueue_subscriptions_sdk_script( $connection );
		}

		$this->enqueue_sdk_components(
            [
				'single'    => $is_single,
				'recurring' => $is_recurring,
            ]
        );

		wp_localize_script(
			'wpforms-paypal-commerce',
			'wpforms_paypal_commerce',
			$this->get_localized_strings( $forms )
		);
	}

	/**
	 * Enqueue SDK components for enabled funding sources.
	 *
	 * @since 1.10.0
	 *
	 * @param array $payment_types Array of payment type flags (e.g., ['single' => bool, 'recurring' => bool]).
	 */
	private function enqueue_sdk_components( array $payment_types ): void {

		foreach ( $this->iterate_payment_methods_with_assets() as $sdk_component ) {
			$sdk_component->enqueue( $payment_types );
		}
	}

	/**
	 * Get localized strings for front-end forms.
	 *
	 * This method generates and returns an array of localized strings, payment options,
	 * conditional rules, nonces, and internationalized error messages for form handling.
	 *
	 * @since 1.10.0
	 *
	 * @param array $forms An array of forms data for the current page.
	 *
	 * @return array The array of localized strings, options, and related data.
	 */
	protected function get_localized_strings( array $forms ): array {

		$strings = [
			'payment_options'   => $this->get_payment_options( $forms ),
			'mode'              => Helpers::get_mode(),
			'total_price_label' => esc_html__( 'Total', 'wpforms-lite' ),
			'nonces'            => [
				'create'              => wp_create_nonce( 'wpforms-paypal-commerce-create-order' ),
				'approve'             => wp_create_nonce( 'wpforms-paypal-commerce-approve-order' ),
				'create_subscription' => wp_create_nonce( 'wpforms-paypal-commerce-create-subscription' ),
			],
			'i18n'              => [
				'missing_sdk_script'         => esc_html__( 'PayPal.js failed to load properly.', 'wpforms-lite' ),
				'on_cancel'                  => esc_html__( 'PayPal payment was canceled.', 'wpforms-lite' ),
				'on_error'                   => esc_html__( 'There was an error processing this payment. Please contact the site administrator.', 'wpforms-lite' ),
				'api_error'                  => esc_html__( 'API error:', 'wpforms-lite' ),
				'subscription_error'         => esc_html__( 'There was an error creating this subscription. Please contact the site administrator.', 'wpforms-lite' ),
				'secure_error'               => esc_html__( 'This payment cannot be processed because there was an error with 3D Secure authentication.', 'wpforms-lite' ),
				'card_not_supported'         => esc_html__( 'is not supported. Please enter the details for a supported credit card.', 'wpforms-lite' ),
				'number'                     => esc_html__( 'Please enter a valid card number.', 'wpforms-lite' ),
				'expirationDate'             => esc_html__( 'Please enter a valid date.', 'wpforms-lite' ),
				'cvv'                        => esc_html__( 'Please enter the CVV number.', 'wpforms-lite' ),
				'card_name'                  => esc_html__( 'Please enter the Card Holder Name.', 'wpforms-lite' ),
				'empty_amount'               => esc_html__( 'This payment cannot be processed because the payment amount is not set, or is set to an invalid amount.', 'wpforms-lite' ),
				'fastlane_account_error'     => esc_html__( 'No Fastlane account found with this email.', 'wpforms-lite' ),
				'fastlane_eligibility_error' => esc_html__( 'Please enter a valid Fastlane details.', 'wpforms-lite' ),
				'fastlane_invalid_billing'   => esc_html__( 'Please enter a valid Fastlane billing address.', 'wpforms-lite' ),
			],
		];

		/**
		 * Filter the localized strings for PayPal Commerce payment.
		 *
		 * @since 1.10.0
		 *
		 * @param array $strings An array of localized strings, options, and related data.
		 * @param array $forms   An array of forms data for the current page.
		 */
		return apply_filters( 'wpforms_integrations_paypal_commerce_frontend_localized_strings', $strings, $forms ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
	}

	/**
	 * Enqueue styles in the frontend if PayPal Commerce is in use on the page.
	 *
	 * @since 1.10.0
	 */
	private function enqueues_styles(): void {

		// Include styles if the "Include Form Styling > No Styles" is not set.
		if ( wpforms_setting( 'disable-css', '1' ) === '3' ) {
			return;
		}

		$min = wpforms_get_min_suffix();

		wp_enqueue_style(
			'wpforms-paypal-commerce',
			WPFORMS_PLUGIN_URL . "assets/css/integrations/paypal-commerce/wpforms-paypal-commerce{$min}.css",
			[],
			WPFORMS_VERSION
		);
	}

	/**
	 * Add attributes to PayPal script tags.
	 *
	 * @since 1.10.0
	 *
	 * @param string $tag    HTML for the script tag.
	 * @param string $handle Handle of a script.
	 *
	 * @return string
	 *
	 * @noinspection PhpMissingParamTypeInspection
	 */
	public function set_script_attributes( $tag, string $handle ): string {

		$tag = (string) $tag;

		// Add an async attribute to an external SDK.
		if ( $this->is_async_script( $handle ) ) {
			$new_attr = sprintf( ' async onload="%s" src', "WPFormsPaypalCommerce.onLoadSDK( '$handle' )" );

			return str_replace( ' src', $new_attr, $tag );
		}

		if ( ! in_array( $handle, [ 'wpforms-paypal-single', 'wpforms-paypal-subscriptions' ], true ) ) {
			return $tag;
		}

		$connection = Connection::get();

		if ( ! $connection ) {
			return $tag;
		}

		$attributes  = ' data-namespace="' . esc_attr( str_replace( '-', '_', $handle ) ) . '"';
		$attributes .= ' data-client-token="' . esc_attr( $connection->get_client_token() ) . '"';
		$attributes .= ' data-sdk-client-token="' . esc_attr( $connection->get_sdk_client_token() ) . '"';
		$attributes .= ' data-partner-merchant-id="' . esc_attr( $connection->get_partner_merchant_id() ) . '"';
		$attributes .= ' data-partner-attribution-id="' . esc_attr( $connection->get_partner_id() ) . '"';

		return str_replace( ' src', $attributes . ' src', $tag );
	}

	/**
	 * Process options by payment methods.
	 *
	 * This method processes the provided options and extends them using the localized settings
	 * of each registered payment method.
	 *
	 * @since 1.10.0
	 *
	 * @param array $options Existing payment options configuration.
	 * @param array $field   Field data related to the current payment method.
	 * @param array $form    Form data related to the current payment method.
	 *
	 * @return array Updated payment options with additional localized settings.
	 */
	private function process_options_by_methods( array $options, array $field, array $form ): array {

		$new_options = [];

		foreach ( $this->payment_methods as $payment_method ) {
			if ( ! ( $payment_method instanceof PaymentMethodAssetsInterface ) ) {
				continue;
			}

			$new_options[] = $payment_method->get_localized_settings( $field, $form );
		}

		return array_merge( $options, ...$new_options );
	}

	/**
	 * Get enabled payment types.
	 *
	 * Determines whether single payments and recurring payments are enabled
	 * across the provided forms.
	 *
	 * @since 1.10.0
	 *
	 * @param array $forms Form data of the forms to check for enabled payment types.
	 *
	 * @return array List containing boolean flags:
	 *               - First value indicates if single payments are enabled.
	 *               - Second value indicates if recurring payments are enabled.
	 */
	private function get_enabled_payment_types( array $forms ): array {

		$is_single_enabled    = false;
		$is_recurring_enabled = false;

		foreach ( $forms as $form_data ) {
			if ( Helpers::is_paypal_commerce_single_enabled( $form_data ) ) {
				$is_single_enabled = true;
			}

			if ( Helpers::is_paypal_commerce_subscriptions_enabled( $form_data ) ) {
				$is_recurring_enabled = true;
			}

			// Early exit if both types are enabled.
			if ( $is_single_enabled && $is_recurring_enabled ) {
				break;
			}
		}

		return [ $is_single_enabled, $is_recurring_enabled ];
	}

	/**
	 * Get PayPal SDK components string based on enabled payment methods.
	 *
	 * @since 1.10.0
	 *
	 * @param bool $is_single Whether to consider One-Time Payment or Recurring. Defaults to One-Time.
	 *
	 * @return string Comma-separated list of SDK components.
	 */
	private function get_sdk_components( bool $is_single = true ): string {

		$components = [];

		foreach ( $this->payment_methods as $sdk_component ) {
			$components = array_merge( $components, (array) $sdk_component->get_components( $is_single ) );
		}

		return implode( ',', $components );
	}

	/**
	 * Get PayPal SDK base URL with shared query parameters.
	 *
	 * @since 1.10.0
	 *
	 * @param object $connection Connection object.
	 * @param bool   $is_single  Whether to consider One-Time Payment or Recurring. Defaults to One-Time.
	 *
	 * @return string Base SDK URL with query parameters.
	 */
	private function get_paypal_sdk_base_url( object $connection, bool $is_single = true ): string {

		$query_args = [
			'client-id'       => $connection->get_client_id(),
			'merchant-id'     => $connection->get_merchant_id(),
			'currency'        => $this->currency,
			'disable-funding' => $this->get_disabled_funding_sources( $is_single ),
			'enable-funding'  => $this->get_enabled_funding_sources( $is_single ),
		];

		foreach ( $query_args as $key => $value ) {
			if ( ! empty( $value ) ) {
				continue;
			}

			unset( $query_args[ $key ] );
		}

		return add_query_arg(
			$query_args,
			'https://www.paypal.com/sdk/js'
		);
	}

	/**
	 * Enqueue PayPal SDK script for single payments.
	 *
	 * @since 1.10.0
	 *
	 * @param object $connection Connection object.
	 */
	private function enqueue_single_sdk_script( object $connection ): void {

		// Get dynamic components based on enabled payment methods.
		$components = $this->get_sdk_components();
		// Get base SDK URL with shared parameters.
		$base_url = $this->get_paypal_sdk_base_url( $connection );
		$args     = [ 'components' => $components ];

		// phpcs:disable WordPress.WP.EnqueuedResourceParameters.MissingVersion
		wp_enqueue_script(
			'wpforms-paypal-single',
			add_query_arg( $args, $base_url ),
			[],
			null,
			false
		);
		// phpcs:enable WordPress.WP.EnqueuedResourceParameters.MissingVersion
	}

	/**
	 * Enqueue PayPal SDK script for subscription payments.
	 *
	 * @since 1.10.0
	 *
	 * @param object $connection Connection object.
	 */
	private function enqueue_subscriptions_sdk_script( object $connection ): void {

		// Get dynamic components based on enabled payment methods.
		$components = $this->get_sdk_components( false );
		// Get base SDK URL with shared parameters.
		$base_url = $this->get_paypal_sdk_base_url( $connection, false );
		$args     = [
			'components' => $components,
			'vault'      => 'true',
		];

		if ( Helpers::is_license_ok() ) {
			$args['intent'] = 'subscription';
		}

		// phpcs:disable WordPress.WP.EnqueuedResourceParameters.MissingVersion
		wp_enqueue_script(
			'wpforms-paypal-subscriptions',
			add_query_arg( $args, $base_url ),
			[],
			null,
			false
		);
		// phpcs:enable WordPress.WP.EnqueuedResourceParameters.MissingVersion
	}

	/**
	 * Checks if a script handle is an asynchronous script.
	 *
	 * @since 1.10.0
	 *
	 * @param string $handle Script handle to check.
	 *
	 * @return bool
	 */
	private function is_async_script( string $handle ): bool {

		foreach ( $this->iterate_payment_methods_with_assets() as $sdk_component ) {
			if ( in_array( $handle, $sdk_component->get_async_scripts(), true ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Get disabled funding sources.
	 *
	 * @since 1.10.0
	 *
	 * @param bool $is_single Whether to consider One-Time Payment or Recurring. Defaults to One-Time.
	 *
	 * @return string Comma-separated list of disabled funding sources.
	 */
	private function get_disabled_funding_sources( bool $is_single = true ): string {

		$disabled = $is_single ? [] : [ 'credit', 'card' ];

		foreach ( $this->payment_methods as $payment_method ) {
			if ( ! ( $payment_method instanceof PaymentMethodFundingInterface ) ) {
				continue;
			}

			$disabled = array_merge( $disabled, (array) $payment_method->get_disabled_methods( $is_single ) );
		}

		/**
		 * Filter the disabled funding sources for PayPal Commerce payment.
		 *
		 * @since 1.10.0
		 *
		 * @param array $disabled  An array of the disabled funding sources.
		 * @param bool  $is_single Whether to consider One-Time Payment or Recurring. Defaults to One-Time.
		 */
		$disabled = (array) apply_filters( 'wpforms_integrations_paypal_commerce_frontend_get_disabled_funding_sources', $disabled, $is_single ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

		return implode( ',', $disabled );
	}

	/**
	 * Get enabled funding sources based on field settings.
	 *
	 * @since 1.10.0
	 *
	 * @param bool $is_single Whether to consider One-Time Payment or Recurring. Defaults to One-Time.
	 *
	 * @return string Comma-separated list of enabled funding sources.
	 */
	private function get_enabled_funding_sources( bool $is_single = true ): string {

		$enabled = [];

		foreach ( $this->payment_methods as $payment_method ) {
			if ( ! ( $payment_method instanceof PaymentMethodFundingInterface ) ) {
				continue;
			}

			$enabled = array_merge( $enabled, (array) $payment_method->get_enabled_methods( $is_single ) );
		}

		/**
		 * Filter the enabled funding sources for PayPal Commerce payment.
		 *
		 * @since 1.10.0
		 *
		 * @param array $disabled  An array of the disabled funding sources.
		 * @param bool  $is_single Whether to consider One-Time Payment or Recurring. Defaults to One-Time.
		 */
		$enabled = (array) apply_filters( 'wpforms_integrations_paypal_commerce_frontend_get_enabled_funding_sources', $enabled, $is_single ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

		return implode( ',', $enabled );
	}

	/**
	 * Iterate over payment methods that implement the PaymentMethodAssetsInterface.
	 *
	 * This generator yields only payment methods that have assets (JS/CSS) to enqueue,
	 * filtering out payment methods that don't implement the required interface.
	 *
	 * @since 1.10.0
	 *
	 * @return Generator<PaymentMethodAssetsInterface> Generator yielding payment methods with assets.
	 */
	private function iterate_payment_methods_with_assets(): Generator {

		foreach ( $this->payment_methods as $payment_method ) {
			if ( ! ( $payment_method instanceof PaymentMethodAssetsInterface ) ) {
				continue;
			}

			yield $payment_method;
		}
	}

	/**
	 * Add a payment method to the registration.
	 *
	 * This method allows payment method modules to register themselves with the Enqueues class.
	 * Registered payment methods will have their components, scripts, and assets loaded based on
	 * the form field configuration.
	 *
	 * @since 1.10.0
	 *
	 * @param PaymentMethodInterface $payment_method The payment method instance to add.
	 */
	public function add_payment_method( PaymentMethodInterface $payment_method ): void {

		$this->payment_methods[] = $payment_method;
	}

	/**
	 * Get Payment Options.
	 *
	 * @since 1.10.0
	 *
	 * @param array $forms Form data of forms on the current page.
	 *
	 * @return array
	 */
	private function get_payment_options( array $forms ): array { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		$options = [];

		foreach ( $forms as $form_id => $form ) {

			if ( ! isset( $form['payments'][ PayPalCommerce::SLUG ] ) ) {
				continue;
			}

			$options[ $form_id ]['is_license_ok']      = Helpers::is_license_ok();
			$options[ $form_id ]['enable_one_time']    = Helpers::is_paypal_commerce_single_enabled( $form );
			$options[ $form_id ]['enable_recurring']   = Helpers::is_paypal_commerce_subscriptions_enabled( $form );
			$options[ $form_id ]['recurring_no_rules'] = Helpers::get_subscription_plan_id_without_rule( $form ) !== '';

			foreach ( $form['fields'] as $field ) {

				if ( $field['type'] !== 'paypal-commerce' ) {
					continue;
				}

				$options[ $form_id ]['button_size']     = $field['button_size'] ?? '';
				$options[ $form_id ]['paypal_checkout'] = isset( $field['paypal_checkout'] );
				$options[ $form_id ]['credit_card']     = isset( $field['credit_card'] );
				$options[ $form_id ]['fastlane']        = isset( $field['fastlane'] );
				$options[ $form_id ]['shape']           = $field['shape'];
				$options[ $form_id ]['color']           = $field['color'];

				// If both Credit Card and Fastlane are enabled, disable Fastlane.
				if ( ! empty( $options[ $form_id ]['credit_card'] ) && ! empty( $options[ $form_id ]['fastlane'] ) ) {
					$options[ $form_id ]['fastlane'] = false;
				}

				$options[ $form_id ] = $this->process_options_by_methods( $options[ $form_id ], $field, $form );

				if ( ! isset( $field['credit_card'] ) ) {
					continue;
				}

				$options[ $form_id ]['supported_cards'] = [
					isset( $field['amex'] ) ? 'american-express' : '',
					isset( $field['maestro'] ) ? 'maestro' : '',
					isset( $field['discover'] ) ? 'discover' : '',
					isset( $field['mastercard'] ) ? 'master-card' : '',
					isset( $field['visa'] ) ? 'visa' : '',
				];

				$options[ $form_id ]['sublabel_hide']      = isset( $field['sublabel_hide'] );
				$options[ $form_id ]['card_number']        = ! empty( $field['card_number'] ) ? $field['card_number'] : esc_html__( 'Card Number', 'wpforms-lite' );
				$options[ $form_id ]['expiration_date']    = ! empty( $field['expiration_date'] ) ? $field['expiration_date'] : esc_html__( 'Expiration Date', 'wpforms-lite' );
				$options[ $form_id ]['security_code']      = ! empty( $field['security_code'] ) ? $field['security_code'] : esc_html__( 'Security Code', 'wpforms-lite' );
				$options[ $form_id ]['card_holder_enable'] = isset( $field['card_holder_enable'] );
				$options[ $form_id ]['card_holder_name']   = ! empty( $field['card_holder_name'] ) ? $field['card_holder_name'] : esc_html__( 'Card Holder Name', 'wpforms-lite' );
			}
		}

		return $options;
	}

	/**
	 * Refresh tokens if conditions are met.
	 *
	 * @since 1.10.0
	 *
	 * @param array   $form_data Form data to process.
	 * @param WP_Post $form      The form object.
	 */
	public function maybe_refresh_tokens( $form_data, WP_Post $form ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed

		$form_data = (array) $form_data;

		$connection = Connection::get();

		if (
			! $connection ||
			! $connection->is_valid() ||
			! Helpers::has_paypal_commerce_field( $form_data ) ||
			! Helpers::is_paypal_commerce_enabled( $form_data )
		) {
			return;
		}

		$connection->refresh_expired_tokens();
	}

	/**
	 * Set Funding Sources.
	 *
	 * Resets the list of enabled funding sources based on the provided forms, ensuring only supported funding sources are retained.
	 *
	 * @since 1.10.0
	 *
	 * @param array $forms Form data of forms on the current page.
	 */
	private function set_payment_methods( array $forms ): void {

		// Reset the list of enabled funding sources.
		[ $payment_methods, $this->payment_methods ] = [ $this->payment_methods, [] ];

		foreach ( $payment_methods as $funding_source ) {
			foreach ( $forms as $form ) {
				$field = Helpers::get_paypal_field( $form['fields'] ?? [] );

				if ( ! $funding_source->is_supported( $field ) ) {
					continue;
				}

				$this->payment_methods[] = $funding_source;

				break;
			}
		}
	}

	/**
	 * Get the current currency.
	 *
	 * @since 1.10.0
	 *
	 * @return string
	 */
	public function get_currency(): string {

		return $this->currency;
	}
}