initial commit

This commit is contained in:
2021-12-10 12:03:04 +00:00
commit c46c7ddbf0
3643 changed files with 582794 additions and 0 deletions

View File

@ -0,0 +1,235 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\StoreApi\Utilities\NoticeHandler;
use Automattic\WooCommerce\Blocks\Payments\Integrations\Stripe;
use Automattic\WooCommerce\Blocks\Payments\Integrations\Cheque;
use Automattic\WooCommerce\Blocks\Payments\Integrations\PayPal;
use Automattic\WooCommerce\Blocks\Payments\Integrations\BankTransfer;
use Automattic\WooCommerce\Blocks\Payments\Integrations\CashOnDelivery;
/**
* The Api class provides an interface to payment method registration.
*
* @since 2.6.0
*/
class Api {
/**
* Reference to the PaymentMethodRegistry instance.
*
* @var PaymentMethodRegistry
*/
private $payment_method_registry;
/**
* Reference to the AssetDataRegistry instance.
*
* @var AssetDataRegistry
*/
private $asset_registry;
/**
* Constructor
*
* @param PaymentMethodRegistry $payment_method_registry An instance of Payment Method Registry.
* @param AssetDataRegistry $asset_registry Used for registering data to pass along to the request.
*/
public function __construct( PaymentMethodRegistry $payment_method_registry, AssetDataRegistry $asset_registry ) {
$this->payment_method_registry = $payment_method_registry;
$this->asset_registry = $asset_registry;
$this->init();
}
/**
* Initialize class features.
*/
protected function init() {
add_action( 'init', array( $this->payment_method_registry, 'initialize' ), 5 );
add_filter( 'woocommerce_blocks_register_script_dependencies', array( $this, 'add_payment_method_script_dependencies' ), 10, 2 );
add_action( 'woocommerce_blocks_checkout_enqueue_data', array( $this, 'add_payment_method_script_data' ) );
add_action( 'woocommerce_blocks_cart_enqueue_data', array( $this, 'add_payment_method_script_data' ) );
add_action( 'woocommerce_blocks_payment_method_type_registration', array( $this, 'register_payment_method_integrations' ) );
add_action( 'woocommerce_rest_checkout_process_payment_with_context', array( $this, 'process_legacy_payment' ), 999, 2 );
add_action( 'wp_print_scripts', array( $this, 'verify_payment_methods_dependencies' ), 1 );
}
/**
* Add payment method script handles as script dependencies.
*
* @param array $dependencies Array of script dependencies.
* @param string $handle Script handle.
* @return array
*/
public function add_payment_method_script_dependencies( $dependencies, $handle ) {
if ( ! in_array( $handle, [ 'wc-checkout-block', 'wc-checkout-block-frontend', 'wc-cart-block', 'wc-cart-block-frontend', 'wc-cart-i2-block', 'wc-cart-i2-block-frontend' ], true ) ) {
return $dependencies;
}
return array_merge( $dependencies, $this->payment_method_registry->get_all_active_payment_method_script_dependencies() );
}
/**
* Returns true if the payment gateway is enabled.
*
* @param object $gateway Payment gateway.
* @return boolean
*/
private function is_payment_gateway_enabled( $gateway ) {
return filter_var( $gateway->enabled, FILTER_VALIDATE_BOOLEAN );
}
/**
* Add payment method data to Asset Registry.
*/
public function add_payment_method_script_data() {
// Enqueue the order of enabled gateways as `paymentGatewaySortOrder`.
if ( ! $this->asset_registry->exists( 'paymentGatewaySortOrder' ) ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
$enabled_gateways = array_filter( $payment_gateways, array( $this, 'is_payment_gateway_enabled' ) );
$this->asset_registry->add( 'paymentGatewaySortOrder', array_keys( $enabled_gateways ) );
}
// Enqueue all registered gateway data (settings/config etc).
$script_data = $this->payment_method_registry->get_all_registered_script_data();
foreach ( $script_data as $asset_data_key => $asset_data_value ) {
if ( ! $this->asset_registry->exists( $asset_data_key ) ) {
$this->asset_registry->add( $asset_data_key, $asset_data_value );
}
}
}
/**
* Register payment method integrations bundled with blocks.
*
* @param PaymentMethodRegistry $payment_method_registry Payment method registry instance.
*/
public function register_payment_method_integrations( PaymentMethodRegistry $payment_method_registry ) {
// This is temporarily registering Stripe until it's moved to the extension.
if ( class_exists( '\WC_Stripe', false ) && ! $payment_method_registry->is_registered( 'stripe' ) ) {
$payment_method_registry->register(
Package::container()->get( Stripe::class )
);
}
$payment_method_registry->register(
Package::container()->get( Cheque::class )
);
$payment_method_registry->register(
Package::container()->get( PayPal::class )
);
$payment_method_registry->register(
Package::container()->get( BankTransfer::class )
);
$payment_method_registry->register(
Package::container()->get( CashOnDelivery::class )
);
}
/**
* Attempt to process a payment for the checkout API if no payment methods support the
* woocommerce_rest_checkout_process_payment_with_context action.
*
* @param PaymentContext $context Holds context for the payment.
* @param PaymentResult $result Result of the payment.
*/
public function process_legacy_payment( PaymentContext $context, PaymentResult &$result ) {
if ( $result->status ) {
return;
}
// phpcs:ignore WordPress.Security.NonceVerification
$post_data = $_POST;
// Set constants.
wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
// Add the payment data from the API to the POST global.
$_POST = $context->payment_data;
// Call the process payment method of the chosen gateway.
$payment_method_object = $context->get_payment_method_instance();
if ( ! $payment_method_object instanceof \WC_Payment_Gateway ) {
return;
}
$payment_method_object->validate_fields();
// If errors were thrown, we need to abort.
NoticeHandler::convert_notices_to_exceptions( 'woocommerce_rest_payment_error' );
// Process Payment.
$gateway_result = $payment_method_object->process_payment( $context->order->get_id() );
// Restore $_POST data.
$_POST = $post_data;
// If `process_payment` added notices, clear them. Notices are not displayed from the API -- payment should fail,
// and a generic notice will be shown instead if payment failed.
wc_clear_notices();
// Handle result.
$result->set_status( isset( $gateway_result['result'] ) && 'success' === $gateway_result['result'] ? 'success' : 'failure' );
// set payment_details from result.
$result->set_payment_details( array_merge( $result->payment_details, $gateway_result ) );
$result->set_redirect_url( $gateway_result['redirect'] );
}
/**
* Verify all dependencies of registered payment methods have been registered.
* If not, remove that payment method script from the list of dependencies
* of Cart and Checkout block scripts so it doesn't break the blocks and show
* an error in the admin.
*/
public function verify_payment_methods_dependencies() {
$wp_scripts = wp_scripts();
$payment_method_scripts = $this->payment_method_registry->get_all_active_payment_method_script_dependencies();
foreach ( $payment_method_scripts as $payment_method_script ) {
if (
! array_key_exists( $payment_method_script, $wp_scripts->registered ) ||
! property_exists( $wp_scripts->registered[ $payment_method_script ], 'deps' )
) {
continue;
}
$deps = $wp_scripts->registered[ $payment_method_script ]->deps;
foreach ( $deps as $dep ) {
if ( ! wp_script_is( $dep, 'registered' ) ) {
$error_handle = $dep . '-dependency-error';
$error_message = sprintf(
'Payment gateway with handle \'%1$s\' has been deactivated in Cart and Checkout blocks because its dependency \'%2$s\' is not registered. Read the docs about registering assets for payment methods: https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/extensibility/payment-method-integration.md#registering-assets',
esc_html( $payment_method_script ),
esc_html( $dep )
);
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
error_log( $error_message );
// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter,WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_register_script( $error_handle, '' );
wp_enqueue_script( $error_handle );
wp_add_inline_script(
$error_handle,
sprintf( 'console.error( "%s" );', $error_message )
);
$cart_checkout_scripts = [ 'wc-cart-block', 'wc-cart-block-frontend', 'wc-checkout-block', 'wc-checkout-block-frontend', 'wc-cart-i2-block', 'wc-cart-i2-block-frontend' ];
foreach ( $cart_checkout_scripts as $script_handle ) {
if (
! array_key_exists( $script_handle, $wp_scripts->registered ) ||
! property_exists( $wp_scripts->registered[ $script_handle ], 'deps' )
) {
continue;
}
// Remove payment method script from dependencies.
$wp_scripts->registered[ $script_handle ]->deps = array_diff(
$wp_scripts->registered[ $script_handle ]->deps,
[ $payment_method_script ]
);
}
}
}
}
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodTypeInterface;
/**
* AbstractPaymentMethodType class.
*
* @since 2.6.0
*/
abstract class AbstractPaymentMethodType implements PaymentMethodTypeInterface {
/**
* Payment method name defined by payment methods extending this class.
*
* @var string
*/
protected $name = '';
/**
* Settings from the WP options table
*
* @var array
*/
protected $settings = [];
/**
* Get a setting from the settings array if set.
*
* @param string $name Setting name.
* @param mixed $default Value that is returned if the setting does not exist.
* @return mixed
*/
protected function get_setting( $name, $default = '' ) {
return isset( $this->settings[ $name ] ) ? $this->settings[ $name ] : $default;
}
/**
* Returns the name of the payment method.
*/
public function get_name() {
return $this->name;
}
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active() {
return true;
}
/**
* Returns an array of script handles to enqueue for this payment method in
* the frontend context
*
* @return string[]
*/
public function get_payment_method_script_handles() {
return [];
}
/**
* Returns an array of script handles to enqueue for this payment method in
* the admin context
*
* @return string[]
*/
public function get_payment_method_script_handles_for_admin() {
return $this->get_payment_method_script_handles();
}
/**
* Returns an array of supported features.
*
* @return string[]
*/
public function get_supported_features() {
return [ 'products' ];
}
/**
* An array of key, value pairs of data made available to payment methods
* client side.
*
* @return array
*/
public function get_payment_method_data() {
return [];
}
/**
* Returns an array of script handles to enqueue in the frontend context.
*
* Alias of get_payment_method_script_handles. Defined by IntegrationInterface.
*
* @return string[]
*/
public function get_script_handles() {
return $this->get_payment_method_script_handles();
}
/**
* Returns an array of script handles to enqueue in the admin context.
*
* Alias of get_payment_method_script_handles_for_admin. Defined by IntegrationInterface.
*
* @return string[]
*/
public function get_editor_script_handles() {
return $this->get_payment_method_script_handles_for_admin();
}
/**
* An array of key, value pairs of data made available to the block on the client side.
*
* Alias of get_payment_method_data. Defined by IntegrationInterface.
*
* @return array
*/
public function get_script_data() {
return $this->get_payment_method_data();
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
use Automattic\WooCommerce\Blocks\Assets\Api;
/**
* Bank Transfer (BACS) payment method integration
*
* @since 3.0.0
*/
final class BankTransfer extends AbstractPaymentMethodType {
/**
* Payment method name/id/slug (matches id in WC_Gateway_BACS in core).
*
* @var string
*/
protected $name = 'bacs';
/**
* An instance of the Asset Api
*
* @var Api
*/
private $asset_api;
/**
* Constructor
*
* @param Api $asset_api An instance of Api.
*/
public function __construct( Api $asset_api ) {
$this->asset_api = $asset_api;
}
/**
* Initializes the payment method type.
*/
public function initialize() {
$this->settings = get_option( 'woocommerce_bacs_settings', [] );
}
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
}
/**
* Returns an array of scripts/handles to be registered for this payment method.
*
* @return array
*/
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
'wc-payment-method-bacs',
'build/wc-payment-method-bacs.js'
);
return [ 'wc-payment-method-bacs' ];
}
/**
* Returns an array of key=>value pairs of data made available to the payment methods script.
*
* @return array
*/
public function get_payment_method_data() {
return [
'title' => $this->get_setting( 'title' ),
'description' => $this->get_setting( 'description' ),
'supports' => $this->get_supported_features(),
];
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
use Automattic\WooCommerce\Blocks\Assets\Api;
/**
* Cash on Delivery (COD) payment method integration
*
* @since 3.0.0
*/
final class CashOnDelivery extends AbstractPaymentMethodType {
/**
* Payment method name/id/slug (matches id in WC_Gateway_COD in core).
*
* @var string
*/
protected $name = 'cod';
/**
* An instance of the Asset Api
*
* @var Api
*/
private $asset_api;
/**
* Constructor
*
* @param Api $asset_api An instance of Api.
*/
public function __construct( Api $asset_api ) {
$this->asset_api = $asset_api;
}
/**
* Initializes the payment method type.
*/
public function initialize() {
$this->settings = get_option( 'woocommerce_cod_settings', [] );
}
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
}
/**
* Return enable_for_virtual option.
*
* @return boolean True if store allows COD payment for orders containing only virtual products.
*/
private function get_enable_for_virtual() {
return filter_var( $this->get_setting( 'enable_for_virtual', false ), FILTER_VALIDATE_BOOLEAN );
}
/**
* Return enable_for_methods option.
*
* @return array Array of shipping methods (string ids) that allow COD. (If empty, all support COD.)
*/
private function get_enable_for_methods() {
$enable_for_methods = $this->get_setting( 'enable_for_methods', [] );
if ( '' === $enable_for_methods ) {
return [];
}
return $enable_for_methods;
}
/**
* Returns an array of scripts/handles to be registered for this payment method.
*
* @return array
*/
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
'wc-payment-method-cod',
'build/wc-payment-method-cod.js'
);
return [ 'wc-payment-method-cod' ];
}
/**
* Returns an array of key=>value pairs of data made available to the payment methods script.
*
* @return array
*/
public function get_payment_method_data() {
return [
'title' => $this->get_setting( 'title' ),
'description' => $this->get_setting( 'description' ),
'enableForVirtual' => $this->get_enable_for_virtual(),
'enableForShippingMethods' => $this->get_enable_for_methods(),
'supports' => $this->get_supported_features(),
];
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
use Exception;
use Automattic\WooCommerce\Blocks\Assets\Api;
/**
* Cheque payment method integration
*
* @since 2.6.0
*/
final class Cheque extends AbstractPaymentMethodType {
/**
* Payment method name defined by payment methods extending this class.
*
* @var string
*/
protected $name = 'cheque';
/**
* An instance of the Asset Api
*
* @var Api
*/
private $asset_api;
/**
* Constructor
*
* @param Api $asset_api An instance of Api.
*/
public function __construct( Api $asset_api ) {
$this->asset_api = $asset_api;
}
/**
* Initializes the payment method type.
*/
public function initialize() {
$this->settings = get_option( 'woocommerce_cheque_settings', [] );
}
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
}
/**
* Returns an array of scripts/handles to be registered for this payment method.
*
* @return array
*/
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
'wc-payment-method-cheque',
'build/wc-payment-method-cheque.js'
);
return [ 'wc-payment-method-cheque' ];
}
/**
* Returns an array of key=>value pairs of data made available to the payment methods script.
*
* @return array
*/
public function get_payment_method_data() {
return [
'title' => $this->get_setting( 'title' ),
'description' => $this->get_setting( 'description' ),
'supports' => $this->get_supported_features(),
];
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
use WC_Gateway_Paypal;
use Automattic\WooCommerce\Blocks\Assets\Api;
/**
* PayPal Standard payment method integration
*
* @since 2.6.0
*/
final class PayPal extends AbstractPaymentMethodType {
/**
* Payment method name defined by payment methods extending this class.
*
* @var string
*/
protected $name = 'paypal';
/**
* An instance of the Asset Api
*
* @var Api
*/
private $asset_api;
/**
* Constructor
*
* @param Api $asset_api An instance of Api.
*/
public function __construct( Api $asset_api ) {
$this->asset_api = $asset_api;
}
/**
* Initializes the payment method type.
*/
public function initialize() {
$this->settings = get_option( 'woocommerce_paypal_settings', [] );
}
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
}
/**
* Returns an array of scripts/handles to be registered for this payment method.
*
* @return array
*/
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
'wc-payment-method-paypal',
'build/wc-payment-method-paypal.js'
);
return [ 'wc-payment-method-paypal' ];
}
/**
* Returns an array of key=>value pairs of data made available to the payment methods script.
*
* @return array
*/
public function get_payment_method_data() {
return [
'title' => $this->get_setting( 'title' ),
'description' => $this->get_setting( 'description' ),
'supports' => $this->get_supported_features(),
];
}
/**
* Returns an array of supported features.
*
* @return string[]
*/
public function get_supported_features() {
$gateway = new WC_Gateway_Paypal();
$features = array_filter( $gateway->supports, array( $gateway, 'supports' ) );
return apply_filters( '__experimental_woocommerce_blocks_payment_gateway_features_list', $features, $this->get_name() );
}
}

View File

@ -0,0 +1,348 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
use Exception;
use WC_Stripe_Payment_Request;
use WC_Stripe_Helper;
use WC_Gateway_Stripe;
use Automattic\WooCommerce\Blocks\Assets\Api;
use Automattic\WooCommerce\Blocks\Payments\PaymentContext;
use Automattic\WooCommerce\Blocks\Payments\PaymentResult;
/**
* Stripe payment method integration
*
* Temporary integration of the stripe payment method for the new cart and
* checkout blocks. Once the api is demonstrated to be stable, this integration
* will be moved to the Stripe extension
*
* @since 2.6.0
*/
final class Stripe extends AbstractPaymentMethodType {
/**
* Payment method name defined by payment methods extending this class.
*
* @var string
*/
protected $name = 'stripe';
/**
* An instance of the Asset Api
*
* @var Api
*/
private $asset_api;
/**
* Constructor
*
* @param Api $asset_api An instance of Api.
*/
public function __construct( Api $asset_api ) {
$this->asset_api = $asset_api;
add_action( 'woocommerce_rest_checkout_process_payment_with_context', [ $this, 'add_payment_request_order_meta' ], 8, 2 );
add_action( 'woocommerce_rest_checkout_process_payment_with_context', [ $this, 'add_stripe_intents' ], 9999, 2 );
}
/**
* Initializes the payment method type.
*/
public function initialize() {
$this->settings = get_option( 'woocommerce_stripe_settings', [] );
}
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active() {
return ! empty( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled'];
}
/**
* Returns an array of scripts/handles to be registered for this payment method.
*
* @return array
*/
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
'wc-payment-method-stripe',
'build/wc-payment-method-stripe.js',
[]
);
return [ 'wc-payment-method-stripe' ];
}
/**
* Returns an array of key=>value pairs of data made available to the payment methods script.
*
* @return array
*/
public function get_payment_method_data() {
return [
'stripeTotalLabel' => $this->get_total_label(),
'publicKey' => $this->get_publishable_key(),
'allowPrepaidCard' => $this->get_allow_prepaid_card(),
'title' => $this->get_title(),
'button' => [
'type' => $this->get_button_type(),
'theme' => $this->get_button_theme(),
'height' => $this->get_button_height(),
'locale' => $this->get_button_locale(),
],
'inline_cc_form' => $this->get_inline_cc_form(),
'icons' => $this->get_icons(),
'showSavedCards' => $this->get_show_saved_cards(),
'allowPaymentRequest' => $this->get_allow_payment_request(),
'showSaveOption' => $this->get_show_save_option(),
'supports' => $this->get_supported_features(),
];
}
/**
* Determine if store allows cards to be saved during checkout.
*
* @return bool True if merchant allows shopper to save card (payment method) during checkout).
*/
private function get_show_saved_cards() {
return isset( $this->settings['saved_cards'] ) ? 'yes' === $this->settings['saved_cards'] : false;
}
/**
* Determine if the checkbox to enable the user to save their payment method should be shown.
*
* @return bool True if the save payment checkbox should be displayed to the user.
*/
private function get_show_save_option() {
$saved_cards = $this->get_show_saved_cards();
// This assumes that Stripe supports `tokenization` - currently this is true, based on
// https://github.com/woocommerce/woocommerce-gateway-stripe/blob/master/includes/class-wc-gateway-stripe.php#L95 .
// See https://github.com/woocommerce/woocommerce-gateway-stripe/blob/ad19168b63df86176cbe35c3e95203a245687640/includes/class-wc-gateway-stripe.php#L271 and
// https://github.com/woocommerce/woocommerce/wiki/Payment-Token-API .
return apply_filters( 'wc_stripe_display_save_payment_method_checkbox', filter_var( $saved_cards, FILTER_VALIDATE_BOOLEAN ) );
}
/**
* Returns the label to use accompanying the total in the stripe statement.
*
* @return string Statement descriptor.
*/
private function get_total_label() {
return ! empty( $this->settings['statement_descriptor'] ) ? WC_Stripe_Helper::clean_statement_descriptor( $this->settings['statement_descriptor'] ) : '';
}
/**
* Returns the publishable api key for the Stripe service.
*
* @return string Public api key.
*/
private function get_publishable_key() {
$test_mode = ( ! empty( $this->settings['testmode'] ) && 'yes' === $this->settings['testmode'] );
$setting_key = $test_mode ? 'test_publishable_key' : 'publishable_key';
return ! empty( $this->settings[ $setting_key ] ) ? $this->settings[ $setting_key ] : '';
}
/**
* Returns whether to allow prepaid cards for payments.
*
* @return bool True means to allow prepaid card (default).
*/
private function get_allow_prepaid_card() {
return apply_filters( 'wc_stripe_allow_prepaid_card', true );
}
/**
* Returns the title string to use in the UI (customisable via admin settings screen).
*
* @return string Title / label string
*/
private function get_title() {
return isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'Credit / Debit Card', 'woocommerce' );
}
/**
* Determine if store allows Payment Request buttons - e.g. Apple Pay / Chrome Pay.
*
* @return bool True if merchant has opted into payment request.
*/
private function get_allow_payment_request() {
$option = isset( $this->settings['payment_request'] ) ? $this->settings['payment_request'] : false;
return filter_var( $option, FILTER_VALIDATE_BOOLEAN );
}
/**
* Return the button type for the payment button.
*
* @return string Defaults to 'default'.
*/
private function get_button_type() {
return isset( $this->settings['payment_request_button_type'] ) ? $this->settings['payment_request_button_type'] : 'default';
}
/**
* Return the theme to use for the payment button.
*
* @return string Defaults to 'dark'.
*/
private function get_button_theme() {
return isset( $this->settings['payment_request_button_theme'] ) ? $this->settings['payment_request_button_theme'] : 'dark';
}
/**
* Return the height for the payment button.
*
* @return string A pixel value for the height (defaults to '64').
*/
private function get_button_height() {
return isset( $this->settings['payment_request_button_height'] ) ? str_replace( 'px', '', $this->settings['payment_request_button_height'] ) : '64';
}
/**
* Return the inline cc option.
*
* @return boolean True if the inline CC form option is enabled.
*/
private function get_inline_cc_form() {
return isset( $this->settings['inline_cc_form'] ) && 'yes' === $this->settings['inline_cc_form'];
}
/**
* Return the locale for the payment button.
*
* @return string Defaults to en_US.
*/
private function get_button_locale() {
return apply_filters( 'wc_stripe_payment_request_button_locale', substr( get_locale(), 0, 2 ) );
}
/**
* Return the icons urls.
*
* @return array Arrays of icons metadata.
*/
private function get_icons() {
$icons_src = [
'visa' => [
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/visa.svg',
'alt' => __( 'Visa', 'woocommerce' ),
],
'amex' => [
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/amex.svg',
'alt' => __( 'American Express', 'woocommerce' ),
],
'mastercard' => [
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/mastercard.svg',
'alt' => __( 'Mastercard', 'woocommerce' ),
],
];
if ( 'USD' === get_woocommerce_currency() ) {
$icons_src['discover'] = [
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/discover.svg',
'alt' => __( 'Discover', 'woocommerce' ),
];
$icons_src['jcb'] = [
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/jcb.svg',
'alt' => __( 'JCB', 'woocommerce' ),
];
$icons_src['diners'] = [
'src' => WC_STRIPE_PLUGIN_URL . '/assets/images/diners.svg',
'alt' => __( 'Diners', 'woocommerce' ),
];
}
return $icons_src;
}
/**
* Add payment request data to the order meta as hooked on the
* woocommerce_rest_checkout_process_payment_with_context action.
*
* @param PaymentContext $context Holds context for the payment.
* @param PaymentResult $result Result object for the payment.
*/
public function add_payment_request_order_meta( PaymentContext $context, PaymentResult &$result ) {
$data = $context->payment_data;
if ( ! empty( $data['payment_request_type'] ) && 'stripe' === $context->payment_method ) {
// phpcs:ignore WordPress.Security.NonceVerification
$post_data = $_POST;
$_POST = $context->payment_data;
$this->add_order_meta( $context->order, $data['payment_request_type'] );
$_POST = $post_data;
}
// hook into stripe error processing so that we can capture the error to
// payment details (which is added to notices and thus not helpful for
// this context).
if ( 'stripe' === $context->payment_method ) {
add_action(
'wc_gateway_stripe_process_payment_error',
function( $error ) use ( &$result ) {
$payment_details = $result->payment_details;
$payment_details['errorMessage'] = wp_strip_all_tags( $error->getLocalizedMessage() );
$result->set_payment_details( $payment_details );
}
);
}
}
/**
* Handles any potential stripe intents on the order that need handled.
*
* This is configured to execute after legacy payment processing has
* happened on the woocommerce_rest_checkout_process_payment_with_context
* action hook.
*
* @param PaymentContext $context Holds context for the payment.
* @param PaymentResult $result Result object for the payment.
*/
public function add_stripe_intents( PaymentContext $context, PaymentResult &$result ) {
if ( 'stripe' === $context->payment_method
&& (
! empty( $result->payment_details['payment_intent_secret'] )
|| ! empty( $result->payment_details['setup_intent_secret'] )
)
) {
$payment_details = $result->payment_details;
$payment_details['verification_endpoint'] = add_query_arg(
[
'order' => $context->order->get_id(),
'nonce' => wp_create_nonce( 'wc_stripe_confirm_pi' ),
'redirect_to' => rawurlencode( $result->redirect_url ),
],
home_url() . \WC_Ajax::get_endpoint( 'wc_stripe_verify_intent' )
);
$result->set_payment_details( $payment_details );
$result->set_status( 'success' );
}
}
/**
* Handles adding information about the payment request type used to the order meta.
*
* @param \WC_Order $order The order being processed.
* @param string $payment_request_type The payment request type used for payment.
*/
private function add_order_meta( \WC_Order $order, string $payment_request_type ) {
if ( 'apple_pay' === $payment_request_type ) {
$order->set_payment_method_title( 'Apple Pay (Stripe)' );
$order->save();
}
if ( 'payment_request_api' === $payment_request_type ) {
$order->set_payment_method_title( 'Chrome Payment Request (Stripe)' );
$order->save();
}
}
/**
* Returns an array of supported features.
*
* @return string[]
*/
public function get_supported_features() {
$gateway = new WC_Gateway_Stripe();
return array_filter( $gateway->supports, array( $gateway, 'supports' ) );
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments;
/**
* PaymentContext class.
*/
class PaymentContext {
/**
* Payment method ID.
*
* @var string
*/
protected $payment_method = '';
/**
* Order object for the order being paid.
*
* @var \WC_Order
*/
protected $order;
/**
* Holds data to send to the payment gateway to support payment.
*
* @var array Key value pairs.
*/
protected $payment_data = [];
/**
* Magic getter for protected properties.
*
* @param string $name Property name.
*/
public function __get( $name ) {
if ( in_array( $name, [ 'payment_method', 'order', 'payment_data' ], true ) ) {
return $this->$name;
}
return null;
}
/**
* Set the chosen payment method ID context.
*
* @param string $payment_method Payment method ID.
*/
public function set_payment_method( $payment_method ) {
$this->payment_method = (string) $payment_method;
}
/**
* Retrieve the payment method instance for the current set payment method.
*
* @return {\WC_Payment_Gateway|null} An instance of the payment gateway if it exists.
*/
public function get_payment_method_instance() {
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
if ( ! isset( $available_gateways[ $this->payment_method ] ) ) {
return;
}
return $available_gateways[ $this->payment_method ];
}
/**
* Set the order context.
*
* @param \WC_Order $order Order object.
*/
public function set_order( \WC_Order $order ) {
$this->order = $order;
}
/**
* Set payment data context.
*
* @param array $payment_data Array of key value pairs of data.
*/
public function set_payment_data( $payment_data = [] ) {
$this->payment_data = [];
foreach ( $payment_data as $key => $value ) {
$this->payment_data[ (string) $key ] = (string) $value;
}
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments;
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
/**
* Class used for interacting with payment method types.
*
* @since 2.6.0
*/
final class PaymentMethodRegistry extends IntegrationRegistry {
/**
* Integration identifier is used to construct hook names and is given when the integration registry is initialized.
*
* @var string
*/
protected $registry_identifier = 'payment_method_type';
/**
* Retrieves all registered payment methods that are also active.
*
* @return PaymentMethodTypeInterface[]
*/
public function get_all_active_registered() {
return array_filter(
$this->get_all_registered(),
function( $payment_method ) {
return $payment_method->is_active();
}
);
}
/**
* Gets an array of all registered payment method script handles, but only for active payment methods.
*
* @return string[]
*/
public function get_all_active_payment_method_script_dependencies() {
$script_handles = [];
$payment_methods = $this->get_all_active_registered();
foreach ( $payment_methods as $payment_method ) {
$script_handles = array_merge(
$script_handles,
is_admin() ? $payment_method->get_payment_method_script_handles_for_admin() : $payment_method->get_payment_method_script_handles()
);
}
return array_unique( array_filter( $script_handles ) );
}
/**
* Gets an array of all registered payment method script data, but only for active payment methods.
*
* @return array
*/
public function get_all_registered_script_data() {
$script_data = [];
$payment_methods = $this->get_all_active_registered();
foreach ( $payment_methods as $payment_method ) {
$script_data[ $payment_method->get_name() . '_data' ] = $payment_method->get_payment_method_data();
}
return array_filter( $script_data );
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments;
use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;
interface PaymentMethodTypeInterface extends IntegrationInterface {
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active();
/**
* Returns an array of script handles to enqueue for this payment method in
* the frontend context
*
* @return string[]
*/
public function get_payment_method_script_handles();
/**
* Returns an array of script handles to enqueue for this payment method in
* the admin context
*
* @return string[]
*/
public function get_payment_method_script_handles_for_admin();
/**
* An array of key, value pairs of data made available to payment methods
* client side.
*
* @return array
*/
public function get_payment_method_data();
/**
* Get array of supported features.
*
* @return string[]
*/
public function get_supported_features();
}

View File

@ -0,0 +1,94 @@
<?php
namespace Automattic\WooCommerce\Blocks\Payments;
/**
* PaymentResult class.
*/
class PaymentResult {
/**
* List of valid payment statuses.
*
* @var array
*/
protected $valid_statuses = [ 'success', 'failure', 'pending', 'error' ];
/**
* Current payment status.
*
* @var string
*/
protected $status = '';
/**
* Array of details about the payment.
*
* @var string
*/
protected $payment_details = [];
/**
* Redirect URL for checkout.
*
* @var string
*/
protected $redirect_url = '';
/**
* Constructor.
*
* @param string $status Sets the payment status for the result.
*/
public function __construct( $status = '' ) {
if ( $status ) {
$this->set_status( $status );
}
}
/**
* Magic getter for protected properties.
*
* @param string $name Property name.
*/
public function __get( $name ) {
if ( in_array( $name, [ 'status', 'payment_details', 'redirect_url' ], true ) ) {
return $this->$name;
}
return null;
}
/**
* Set payment status.
*
* @throws \Exception When an invalid status is provided.
*
* @param string $payment_status Status to set.
*/
public function set_status( $payment_status ) {
if ( ! in_array( $payment_status, $this->valid_statuses, true ) ) {
throw new \Exception( sprintf( 'Invalid payment status %s. Use one of %s', $payment_status, implode( ', ', $this->valid_statuses ) ) );
}
$this->status = $payment_status;
}
/**
* Set payment details.
*
* @param array $payment_details Array of key value pairs of data.
*/
public function set_payment_details( $payment_details = [] ) {
$this->payment_details = [];
foreach ( $payment_details as $key => $value ) {
$this->payment_details[ (string) $key ] = (string) $value;
}
}
/**
* Set redirect URL.
*
* @param array $redirect_url URL to redirect the customer to after checkout.
*/
public function set_redirect_url( $redirect_url = [] ) {
$this->redirect_url = esc_url_raw( $redirect_url );
}
}