Files
2025-11-24 21:33:55 +00:00

2203 lines
89 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Class WC_Payments
*
* @package WooCommerce\Payments
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
use WCPay\Core\Mode;
use WCPay\Core\Server\Request;
use WCPay\Migrations\Allowed_Payment_Request_Button_Types_Update;
use WCPay\Payment_Methods\CC_Payment_Method;
use WCPay\Payment_Methods\Bancontact_Payment_Method;
use WCPay\Payment_Methods\Becs_Payment_Method;
use WCPay\Payment_Methods\Giropay_Payment_Method;
use WCPay\Payment_Methods\Klarna_Payment_Method;
use WCPay\Payment_Methods\P24_Payment_Method;
use WCPay\Payment_Methods\Sepa_Payment_Method;
use WCPay\Payment_Methods\Sofort_Payment_Method;
use WCPay\Payment_Methods\Ideal_Payment_Method;
use WCPay\Payment_Methods\Eps_Payment_Method;
use WCPay\Payment_Methods\UPE_Payment_Method;
use WCPay\Payment_Methods\Multibanco_Payment_Method;
use WCPay\WooPay_Tracker;
use WCPay\WooPay\WooPay_Utilities;
use WCPay\WooPay\WooPay_Order_Status_Sync;
use WCPay\Payment_Methods\Link_Payment_Method;
use WCPay\Payment_Methods\Affirm_Payment_Method;
use WCPay\Payment_Methods\Afterpay_Payment_Method;
use WCPay\Session_Rate_Limiter;
use WCPay\Database_Cache;
use WCPay\WC_Payments_Checkout;
use WCPay\WooPay\Service\Checkout_Service;
use WCPay\Core\WC_Payments_Customer_Service_API;
use WCPay\Constants\Payment_Method;
use WCPay\Duplicate_Payment_Prevention_Service;
use WCPay\Internal\Service\Level3Service;
use WCPay\Internal\Service\OrderService;
use WCPay\WooPay\WooPay_Scheduler;
use WCPay\WooPay\WooPay_Session;
use WCPay\Compatibility_Service;
use WCPay\Duplicates_Detection_Service;
use WCPay\Payment_Methods\Grabpay_Payment_Method;
use WCPay\WC_Payments_Currency_Manager;
use WCPay\PaymentMethods\Configs\Registry\PaymentMethodDefinitionRegistry;
/**
* Main class for the WooPayments extension. Its responsibility is to initialize the extension.
*/
class WC_Payments {
/**
* Main payment gateway controller instance, created in init function.
*
* @var WC_Payment_Gateway_WCPay
*/
private static $card_gateway;
/**
* Instance of WC_Payments_API_Client, created in init function.
*
* @var WC_Payments_API_Client
*/
private static $api_client;
/**
* Instance of WC_Payments_DB.
*
* @var WC_Payments_DB
*/
private static $db_helper;
/**
* Instance of WC_Payments_Account, created in init function.
*
* @var WC_Payments_Account
*/
private static $account;
/**
* Instance of WC_Payments_Session_Service, created in init function.
*
* @var WC_Payments_Session_Service
*/
private static $session_service;
/**
* Instance of WC_Payments_Redirect_Service, created in init function.
*
* @var WC_Payments_Redirect_Service
*/
private static $redirect_service;
/**
* Instance of WC_Payments_Customer_Service, created in init function.
*
* @var WC_Payments_Customer_Service
*/
private static $customer_service;
/**
* Instance of WC_Payments_Token_Service, created in init function.
*
* @var WC_Payments_Token_Service
*/
private static $token_service;
/**
* Instance of WC_Payments_Remote_Note_Service, created in init function.
*
* @var WC_Payments_Remote_Note_Service
*/
private static $remote_note_service;
/**
* Instance of WC_Payments_Action_Scheduler_Service, created in init function
*
* @var WC_Payments_Action_Scheduler_Service
*/
private static $action_scheduler_service;
/**
* Instance of WC_Payments_Localization_Service, created in init function
*
* @var WC_Payments_Localization_Service
*/
private static $localization_service;
/**
* Instance of WC_Payments_Settings_Service, created in init function
*
* @var WC_Payments_Settings_Service
*/
private static $settings_service;
/**
* Instance of WC_Payments_Dependency_Service, created in init function
*
* @var WC_Payments_Dependency_Service
*/
private static $dependency_service;
/**
* Instance of WC_Payments_Fraud_Service, created in init function
*
* @var WC_Payments_Fraud_Service
*/
private static $fraud_service;
/**
* Instance of WC_Payments_In_Person_Payments_Receipts_Service, created in init function
*
* @var WC_Payments_In_Person_Payments_Receipts_Service
*/
private static $in_person_payments_receipts_service;
/**
* Instance of WC_Payments_Order_Service, created in init function
*
* @var WC_Payments_Order_Service
*/
private static $order_service;
/**
* Instance of WC_Payments_Order_Success_Page, created in init function
*
* @var WC_Payments_Order_Success_Page
*/
private static $order_success_page;
/**
* Instance of WC_Payments_Onboarding_Service, created in init function
*
* @var WC_Payments_Onboarding_Service
*/
private static $onboarding_service;
/**
* Instance of WC_Payments_Apple_Pay_Registration, created in init function
*
* @var WC_Payments_Apple_Pay_Registration
*/
private static $apple_pay_registration;
/**
* Instance of Session_Rate_Limiter to limit failed transactions
*
* @var Session_Rate_Limiter
*/
private static $failed_transaction_rate_limiter;
/**
* Instance of Database_Cache utils
*
* @var Database_Cache
*/
private static $database_cache;
/**
* Cache for plugin headers to avoid multiple calls to get_file_data
*
* @var array
*/
private static $plugin_headers = null;
/**
* Instance of WC_Payments_Webhook_Processing_Service to process webhook data.
*
* @var WC_Payments_Webhook_Processing_Service
*/
private static $webhook_processing_service;
/**
* Maps all availabled Stripe payment method IDs to Payment Method instances.
*
* @var array
*/
private static $payment_method_map = [];
/**
* Maps all availabled Stripe payment method IDs to Payment Gateway instances.
*
* @var array
*/
private static $payment_gateway_map = [];
/**
* Instance of WC_Payments_Webhook_Reliability_Service, created in init function
*
* @var WC_Payments_Webhook_Reliability_Service
*/
private static $webhook_reliability_service;
/**
* Holds WCPay's working mode.
*
* @var Mode
*/
private static $mode;
/**
* WooPay Utilities.
*
* @var WooPay_Utilities
*/
private static $woopay_util;
/**
* WooPay Tracker.
*
* @var WooPay_Tracker
*/
private static $woopay_tracker;
/**
* WC Payments Checkout
*
* @var WC_Payments_Checkout
*/
private static $wc_payments_checkout;
/**
* WooPay Checkout service
*
* @var Checkout_Service
*/
private static $woopay_checkout_service;
/**
* WC Payments Customer Service API
*
* @var WC_Payments_Customer_Service_API
*/
private static $customer_service_api;
/**
* Duplicate payment prevention service.
*
* @var Duplicate_Payment_Prevention_Service
*/
private static $duplicate_payment_prevention_service;
/**
* Instance of WC_Payments_Incentives_Service, created in init function.
*
* @var WC_Payments_Incentives_Service
*/
private static $incentives_service;
/**
* Instance of WC_Payments_Express_Checkout_Button_Helper, created in init function.
*
* @var WC_Payments_Express_Checkout_Button_Helper
*/
private static $express_checkout_helper;
/**
* Instance of Compatibility_Service, created in init function
*
* @var Compatibility_Service
*/
private static $compatibility_service;
/**
* Instance of Duplicates_Detection_Service, created in init function
*
* @var Duplicates_Detection_Service
*/
private static $duplicates_detection_service;
/**
* Instance of WC_Payments_Currency_Manager, created in init function
*
* @var WC_Payments_Currency_Manager
*/
private static $currency_manager;
/**
* Instance of WC_Payments_Payment_Method_Service, created in init function
*
* @var WC_Payments_Payment_Method_Service
*/
private static $payment_method_service;
/**
* Entry point to the initialization logic.
*/
public static function init() {
// in TeamCity tests, there might be multiple instances of WC_Payments initialized.
// This prevents the hooks from being registered multiple times, which can cause issues.
if ( defined( 'WCPAY_VERSION_NUMBER' ) ) {
return;
}
define( 'WCPAY_VERSION_NUMBER', self::get_plugin_headers()['Version'] );
include_once __DIR__ . '/class-wc-payments-utils.php';
include_once __DIR__ . '/core/class-mode.php';
self::$mode = new Mode();
include_once __DIR__ . '/class-database-cache.php';
self::$database_cache = new Database_Cache();
self::$database_cache->init_hooks();
include_once __DIR__ . '/class-wc-payments-dependency-service.php';
self::$dependency_service = new WC_Payments_Dependency_Service();
self::$dependency_service->init_hooks();
if ( false === self::$dependency_service->has_valid_dependencies() ) {
return;
}
add_action( 'admin_init', [ __CLASS__, 'add_woo_admin_notes' ] );
add_action( 'admin_init', [ __CLASS__, 'remove_deprecated_notes' ] );
add_action( 'init', [ __CLASS__, 'install_actions' ] );
add_action( 'woocommerce_blocks_payment_method_type_registration', [ __CLASS__, 'register_checkout_gateway' ] );
include_once __DIR__ . '/class-wc-payments-db.php';
self::$db_helper = new WC_Payments_DB();
include_once __DIR__ . '/exceptions/class-base-exception.php';
include_once __DIR__ . '/exceptions/class-api-exception.php';
include_once __DIR__ . '/exceptions/class-api-merchant-exception.php';
include_once __DIR__ . '/exceptions/class-connection-exception.php';
include_once __DIR__ . '/core/class-mode.php';
// Include core exceptions.
include_once __DIR__ . '/core/exceptions/server/request/class-server-request-exception.php';
include_once __DIR__ . '/core/exceptions/server/request/class-invalid-request-parameter-exception.php';
include_once __DIR__ . '/core/exceptions/server/request/class-immutable-parameter-exception.php';
include_once __DIR__ . '/core/exceptions/server/request/class-extend-request-exception.php';
include_once __DIR__ . '/core/exceptions/server/response/class-server-response-exception.php';
// Include core requests.
include_once __DIR__ . '/core/server/class-request.php';
include_once __DIR__ . '/core/server/class-response.php';
include_once __DIR__ . '/core/server/request/trait-intention.php';
include_once __DIR__ . '/core/server/request/trait-level3.php';
include_once __DIR__ . '/core/server/request/trait-order-info.php';
include_once __DIR__ . '/core/server/request/trait-date-parameters.php';
include_once __DIR__ . '/core/server/request/trait-use-test-mode-only-when-test-mode-onboarding.php';
include_once __DIR__ . '/core/server/request/class-generic.php';
include_once __DIR__ . '/core/server/request/class-get-intention.php';
include_once __DIR__ . '/core/server/request/class-create-intention.php';
include_once __DIR__ . '/core/server/request/class-update-intention.php';
include_once __DIR__ . '/core/server/request/class-capture-intention.php';
include_once __DIR__ . '/core/server/request/class-cancel-intention.php';
include_once __DIR__ . '/core/server/request/class-create-setup-intention.php';
include_once __DIR__ . '/core/server/request/class-create-and-confirm-setup-intention.php';
include_once __DIR__ . '/core/server/request/class-get-setup-intention.php';
include_once __DIR__ . '/core/server/request/class-get-account.php';
include_once __DIR__ . '/core/server/request/class-get-account-login-data.php';
include_once __DIR__ . '/core/server/request/class-get-account-capital-link.php';
include_once __DIR__ . '/core/server/request/class-add-account-tos-agreement.php';
include_once __DIR__ . '/core/server/request/class-update-account.php';
include_once __DIR__ . '/core/server/request/class-get-charge.php';
include_once __DIR__ . '/core/server/request/class-woopay-create-intent.php';
include_once __DIR__ . '/core/server/request/class-create-and-confirm-intention.php';
include_once __DIR__ . '/core/server/request/class-woopay-create-and-confirm-intention.php';
include_once __DIR__ . '/core/server/request/class-woopay-create-and-confirm-setup-intention.php';
include_once __DIR__ . '/core/server/request/class-paginated.php';
include_once __DIR__ . '/core/server/request/class-list-transactions.php';
include_once __DIR__ . '/core/server/request/class-list-fraud-outcome-transactions.php';
include_once __DIR__ . '/core/server/request/class-list-disputes.php';
include_once __DIR__ . '/core/server/request/class-list-deposits.php';
include_once __DIR__ . '/core/server/request/class-list-documents.php';
include_once __DIR__ . '/core/server/request/class-list-authorizations.php';
include_once __DIR__ . '/core/server/request/class-woopay-create-and-confirm-setup-intention.php';
include_once __DIR__ . '/core/server/request/class-refund-charge.php';
include_once __DIR__ . '/core/server/request/class-list-charge-refunds.php';
include_once __DIR__ . '/core/server/request/class-get-request.php';
include_once __DIR__ . '/core/server/request/class-request-utils.php';
include_once __DIR__ . '/woopay/services/class-checkout-service.php';
self::$api_client = self::create_api_client();
include_once __DIR__ . '/compat/subscriptions/trait-wc-payments-subscriptions-utilities.php';
include_once __DIR__ . '/compat/subscriptions/trait-wc-payment-gateway-wcpay-subscriptions.php';
include_once __DIR__ . '/class-wc-payments-session-service.php';
include_once __DIR__ . '/class-wc-payments-redirect-service.php';
include_once __DIR__ . '/class-wc-payments-account.php';
include_once __DIR__ . '/class-wc-payments-customer-service.php';
include_once __DIR__ . '/class-logger.php';
include_once __DIR__ . '/class-logger-context.php';
include_once __DIR__ . '/class-session-rate-limiter.php';
include_once __DIR__ . '/class-wc-payment-gateway-wcpay.php';
include_once __DIR__ . '/class-wc-payments-checkout.php';
include_once __DIR__ . '/payment-methods/class-cc-payment-gateway.php';
include_once __DIR__ . '/payment-methods/class-upe-payment-method.php';
include_once __DIR__ . '/payment-methods/class-cc-payment-method.php';
include_once __DIR__ . '/payment-methods/class-bancontact-payment-method.php';
include_once __DIR__ . '/payment-methods/class-sepa-payment-method.php';
include_once __DIR__ . '/payment-methods/class-giropay-payment-method.php';
include_once __DIR__ . '/payment-methods/class-p24-payment-method.php';
include_once __DIR__ . '/payment-methods/class-sofort-payment-method.php';
include_once __DIR__ . '/payment-methods/class-ideal-payment-method.php';
include_once __DIR__ . '/payment-methods/class-becs-payment-method.php';
include_once __DIR__ . '/payment-methods/class-eps-payment-method.php';
include_once __DIR__ . '/payment-methods/class-link-payment-method.php';
include_once __DIR__ . '/payment-methods/class-affirm-payment-method.php';
include_once __DIR__ . '/payment-methods/class-afterpay-payment-method.php';
include_once __DIR__ . '/payment-methods/class-klarna-payment-method.php';
include_once __DIR__ . '/payment-methods/class-multibanco-payment-method.php';
include_once __DIR__ . '/payment-methods/class-grabpay-payment-method.php';
include_once __DIR__ . '/inline-script-payloads/class-woo-payments-payment-methods-config.php';
include_once __DIR__ . '/express-checkout/class-wc-payments-express-checkout-button-helper.php';
include_once __DIR__ . '/class-wc-payment-token-wcpay-sepa.php';
include_once __DIR__ . '/class-wc-payments-status.php';
include_once __DIR__ . '/class-wc-payments-token-service.php';
include_once __DIR__ . '/express-checkout/class-wc-payments-express-checkout-ajax-handler.php';
include_once __DIR__ . '/express-checkout/class-wc-payments-express-checkout-button-display-handler.php';
include_once __DIR__ . '/express-checkout/class-wc-payments-express-checkout-button-handler.php';
include_once __DIR__ . '/class-wc-payments-woopay-button-handler.php';
include_once __DIR__ . '/class-wc-payments-woopay-direct-checkout.php';
include_once __DIR__ . '/class-wc-payments-apple-pay-registration.php';
include_once __DIR__ . '/exceptions/class-add-payment-method-exception.php';
include_once __DIR__ . '/exceptions/class-amount-too-large-exception.php';
include_once __DIR__ . '/exceptions/class-amount-too-small-exception.php';
include_once __DIR__ . '/exceptions/class-cannot-combine-currencies-exception.php';
include_once __DIR__ . '/exceptions/class-intent-authentication-exception.php';
include_once __DIR__ . '/exceptions/class-invalid-payment-method-exception.php';
include_once __DIR__ . '/exceptions/class-process-payment-exception.php';
include_once __DIR__ . '/exceptions/class-invalid-phone-number-exception.php';
include_once __DIR__ . '/exceptions/class-invalid-webhook-data-exception.php';
include_once __DIR__ . '/exceptions/class-invalid-price-exception.php';
include_once __DIR__ . '/exceptions/class-fraud-ruleset-exception.php';
include_once __DIR__ . '/exceptions/class-fraud-prevention-enabled-exception.php';
include_once __DIR__ . '/exceptions/class-order-not-found-exception.php';
include_once __DIR__ . '/exceptions/class-order-id-mismatch-exception.php';
include_once __DIR__ . '/exceptions/class-rate-limiter-enabled-exception.php';
include_once __DIR__ . '/exceptions/class-invalid-address-exception.php';
include_once __DIR__ . '/exceptions/class-subscription-mode-mismatch-exception.php';
include_once __DIR__ . '/constants/class-base-constant.php';
include_once __DIR__ . '/constants/class-country-code.php';
include_once __DIR__ . '/constants/class-country-test-cards.php';
include_once __DIR__ . '/constants/class-currency-code.php';
include_once __DIR__ . '/constants/class-fraud-meta-box-type.php';
include_once __DIR__ . '/constants/class-order-mode.php';
include_once __DIR__ . '/constants/class-order-status.php';
include_once __DIR__ . '/constants/class-payment-type.php';
include_once __DIR__ . '/constants/class-payment-initiated-by.php';
include_once __DIR__ . '/constants/class-intent-status.php';
include_once __DIR__ . '/constants/class-refund-status.php';
include_once __DIR__ . '/constants/class-refund-failure-reason.php';
include_once __DIR__ . '/constants/class-payment-intent-status.php';
include_once __DIR__ . '/constants/class-payment-capture-type.php';
include_once __DIR__ . '/constants/class-payment-method.php';
include_once __DIR__ . '/constants/class-track-events.php';
include_once __DIR__ . '/class-payment-information.php';
require_once __DIR__ . '/notes/class-wc-payments-remote-note-service.php';
include_once __DIR__ . '/class-wc-payments-action-scheduler-service.php';
include_once __DIR__ . '/class-wc-payments-fraud-service.php';
include_once __DIR__ . '/class-wc-payments-onboarding-service.php';
include_once __DIR__ . '/class-experimental-abtest.php';
include_once __DIR__ . '/class-wc-payments-localization-service.php';
include_once __DIR__ . '/class-wc-payments-settings-service.php';
include_once __DIR__ . '/in-person-payments/class-wc-payments-in-person-payments-receipts-service.php';
include_once __DIR__ . '/class-wc-payments-order-service.php';
include_once __DIR__ . '/class-wc-payments-order-success-page.php';
include_once __DIR__ . '/class-wc-payments-file-service.php';
include_once __DIR__ . '/class-wc-payments-webhook-processing-service.php';
include_once __DIR__ . '/class-wc-payments-webhook-reliability-service.php';
include_once __DIR__ . '/fraud-prevention/class-fraud-prevention-service.php';
include_once __DIR__ . '/fraud-prevention/class-buyer-fingerprinting-service.php';
include_once __DIR__ . '/fraud-prevention/class-fraud-risk-tools.php';
include_once __DIR__ . '/fraud-prevention/wc-payments-fraud-risk-tools.php';
include_once __DIR__ . '/woopay/class-woopay-store-api-token.php';
include_once __DIR__ . '/woopay/class-woopay-utilities.php';
include_once __DIR__ . '/woopay/class-woopay-order-status-sync.php';
include_once __DIR__ . '/woopay/class-woopay-store-api-session-handler.php';
include_once __DIR__ . '/woopay/class-woopay-scheduler.php';
include_once __DIR__ . '/woopay/class-woopay-adapted-extensions.php';
include_once __DIR__ . '/class-wc-payment-token-wcpay-link.php';
include_once __DIR__ . '/core/service/class-wc-payments-customer-service-api.php';
include_once __DIR__ . '/class-duplicate-payment-prevention-service.php';
include_once __DIR__ . '/class-wc-payments-incentives-service.php';
include_once __DIR__ . '/class-compatibility-service.php';
include_once __DIR__ . '/compat/multi-currency/wc-payments-multi-currency.php';
include_once __DIR__ . '/compat/multi-currency/class-wc-payments-currency-manager.php';
include_once __DIR__ . '/class-duplicates-detection-service.php';
include_once __DIR__ . '/class-wc-payments-payment-method-service.php';
wcpay_get_container()->get( \WCPay\Internal\LoggerContext::class )->init_hooks();
self::$woopay_checkout_service = new Checkout_Service();
self::$woopay_checkout_service->init();
// // Load woopay save user section if feature is enabled.
add_action( 'woocommerce_cart_loaded_from_session', [ __CLASS__, 'init_woopay' ] );
// Init the email template for In Person payment receipt email. We need to do it before passing the mailer to the service.
add_filter( 'woocommerce_email_classes', [ __CLASS__, 'add_ipp_emails' ], 10 );
// Always load tracker to avoid class not found errors.
include_once WCPAY_ABSPATH . 'includes/admin/tracks/class-tracker.php';
// Load woopay tracking.
include_once WCPAY_ABSPATH . 'includes/class-woopay-tracker.php';
self::$order_service = new WC_Payments_Order_Service( self::$api_client );
self::$compatibility_service = new Compatibility_Service( self::$api_client );
self::$action_scheduler_service = new WC_Payments_Action_Scheduler_Service( self::$api_client, self::$order_service, self::$compatibility_service );
self::$session_service = new WC_Payments_Session_Service( self::$api_client );
self::$redirect_service = new WC_Payments_Redirect_Service( self::$api_client );
self::$onboarding_service = new WC_Payments_Onboarding_Service( self::$api_client, self::$database_cache, self::$session_service );
self::$account = new WC_Payments_Account( self::$api_client, self::$database_cache, self::$action_scheduler_service, self::$onboarding_service, self::$redirect_service );
self::$customer_service = new WC_Payments_Customer_Service( self::$api_client, self::$account, self::$database_cache, self::$session_service, self::$order_service );
self::$token_service = new WC_Payments_Token_Service( self::$api_client, self::$customer_service );
self::$remote_note_service = new WC_Payments_Remote_Note_Service( WC_Data_Store::load( 'admin-note' ) );
self::$fraud_service = new WC_Payments_Fraud_Service( self::$api_client, self::$customer_service, self::$account, self::$session_service, self::$database_cache );
self::$in_person_payments_receipts_service = new WC_Payments_In_Person_Payments_Receipts_Service();
self::$localization_service = new WC_Payments_Localization_Service();
self::$settings_service = new WC_Payments_Settings_Service();
self::$failed_transaction_rate_limiter = new Session_Rate_Limiter( Session_Rate_Limiter::SESSION_KEY_DECLINED_CARD_REGISTRY, 5, 10 * MINUTE_IN_SECONDS );
self::$order_success_page = new WC_Payments_Order_Success_Page();
self::$woopay_util = new WooPay_Utilities();
self::$woopay_tracker = new WooPay_Tracker( self::get_wc_payments_http() );
self::$incentives_service = new WC_Payments_Incentives_Service( self::$database_cache );
self::$duplicate_payment_prevention_service = new Duplicate_Payment_Prevention_Service();
self::$duplicates_detection_service = new Duplicates_Detection_Service();
( new WooPay_Scheduler( self::$api_client ) )->init();
// Initialise hooks.
self::$action_scheduler_service->init_hooks();
self::$account->init_hooks();
self::$fraud_service->init_hooks();
self::$onboarding_service->init_hooks();
self::$incentives_service->init_hooks();
self::$compatibility_service->init_hooks();
self::$customer_service->init_hooks();
self::$token_service->init_hooks();
/**
* FLAG: PAYMENT_METHODS_LIST
* As payment methods are converted to use definitions, they need to be removed from the list below.
*/
$payment_method_classes = [
CC_Payment_Method::class,
Bancontact_Payment_Method::class,
Sepa_Payment_Method::class,
Giropay_Payment_Method::class,
Sofort_Payment_Method::class,
P24_Payment_Method::class,
Ideal_Payment_Method::class,
Becs_Payment_Method::class,
Eps_Payment_Method::class,
Link_Payment_Method::class,
Affirm_Payment_Method::class,
Afterpay_Payment_Method::class,
Klarna_Payment_Method::class,
Multibanco_Payment_Method::class,
Grabpay_Payment_Method::class,
];
$payment_methods = [];
// Initialize legacy payment methods.
foreach ( $payment_method_classes as $payment_method_class ) {
$payment_method = new $payment_method_class( self::$token_service );
$payment_methods[ $payment_method->get_id() ] = $payment_method;
}
// Initialize definition-based payment methods.
// Initialize and get payment method classes from the registry for those that have been converted.
$registry = PaymentMethodDefinitionRegistry::instance();
$registry->init();
$payment_method_definitions = $registry->get_all_payment_method_definitions();
foreach ( $payment_method_definitions as $definition_class ) {
$payment_method = new UPE_Payment_Method( self::$token_service, $definition_class );
$payment_methods[ $payment_method->get_id() ] = $payment_method;
}
foreach ( $payment_methods as $payment_method ) {
self::$payment_method_map[ $payment_method->get_id() ] = $payment_method;
$split_gateway = new WC_Payment_Gateway_WCPay( self::$api_client, self::$account, self::$customer_service, self::$token_service, self::$action_scheduler_service, $payment_method, $payment_methods, self::$order_service, self::$duplicate_payment_prevention_service, self::$localization_service, self::$fraud_service, self::$duplicates_detection_service, self::$failed_transaction_rate_limiter );
// Card gateway hooks are registered once below.
if ( 'card' !== $payment_method->get_id() ) {
$split_gateway->init_hooks();
}
self::$payment_gateway_map[ $payment_method->get_id() ] = $split_gateway;
}
self::$card_gateway = self::get_payment_gateway_by_id( 'card' );
self::$wc_payments_checkout = new WC_Payments_Checkout( self::get_gateway(), self::$woopay_util, self::$account, self::$customer_service, self::$fraud_service );
self::$card_gateway->init_hooks();
self::$wc_payments_checkout->init_hooks();
self::$webhook_processing_service = new WC_Payments_Webhook_Processing_Service( self::$api_client, self::$db_helper, self::$account, self::$remote_note_service, self::$order_service, self::$in_person_payments_receipts_service, self::get_gateway(), self::$customer_service, self::$database_cache, self::$onboarding_service );
self::$webhook_reliability_service = new WC_Payments_Webhook_Reliability_Service( self::$api_client, self::$action_scheduler_service, self::$webhook_processing_service );
self::$customer_service_api = new WC_Payments_Customer_Service_API( self::$customer_service );
self::$currency_manager = new WC_Payments_Currency_Manager( self::get_gateway() );
self::$currency_manager->init_hooks();
// Only register hooks of the new `src` service with the same feature of Duplicate_Payment_Prevention_Service.
// To avoid register the same hooks twice.
wcpay_get_container()->get( \WCPay\Internal\Service\DuplicatePaymentPreventionService::class )->init_hooks();
self::$apple_pay_registration = new WC_Payments_Apple_Pay_Registration( self::$api_client, self::$account, self::get_gateway() );
self::$apple_pay_registration->init_hooks();
$express_checkout_helper = new WC_Payments_Express_Checkout_Button_Helper( self::get_gateway(), self::$account );
self::set_express_checkout_helper( $express_checkout_helper );
self::$payment_method_service = new WC_Payments_Payment_Method_Service( self::$api_client, self::$order_service );
self::$payment_method_service->init_hooks();
// Delay registering hooks that could end up in a fatal error due to expired account cache.
// The `woocommerce_payments_account_refreshed` action will result in a fatal error if it's fired before the `$wp_rewrite` is defined.
// See #8942 for more details.
add_action(
'setup_theme',
function () {
add_action( 'woocommerce_payments_account_refreshed', [ WooPay_Order_Status_Sync::class, 'remove_webhook' ] );
self::maybe_register_woopay_hooks();
self::maybe_display_express_checkout_buttons();
self::maybe_init_woopay_direct_checkout();
self::maybe_enqueue_woopay_common_config_script( WC_Payments_Features::is_woopay_direct_checkout_enabled() );
}
);
if ( self::get_gateway()->is_enabled() ) {
// Insert the Stripe Payment Messaging Element only if there is at least one BNPL method enabled.
$enabled_bnpl_payment_methods = array_intersect(
Payment_Method::BNPL_PAYMENT_METHODS,
self::get_gateway()->get_upe_enabled_payment_method_ids()
);
if ( [] !== $enabled_bnpl_payment_methods ) {
add_action( 'woocommerce_single_product_summary', [ __CLASS__, 'load_stripe_bnpl_site_messaging' ], 10 );
add_action( 'woocommerce_proceed_to_checkout', [ __CLASS__, 'load_stripe_bnpl_site_messaging' ], 5 );
add_action( 'woocommerce_blocks_enqueue_cart_block_scripts_after', [ __CLASS__, 'load_stripe_bnpl_site_messaging' ] );
add_action( 'wc_ajax_wcpay_get_cart_total', [ __CLASS__, 'ajax_get_cart_total' ] );
add_action( 'wc_ajax_wcpay_check_bnpl_availability', [ __CLASS__, 'ajax_check_bnpl_availability' ] );
}
}
add_filter( 'woocommerce_payment_gateways', [ __CLASS__, 'register_gateway' ] );
add_filter( 'option_woocommerce_gateway_order', [ __CLASS__, 'order_woopayments_gateways' ], 2 );
add_filter( 'default_option_woocommerce_gateway_order', [ __CLASS__, 'order_woopayments_gateways' ], 3 );
add_filter( 'woocommerce_admin_get_user_data_fields', [ __CLASS__, 'add_user_data_fields' ] );
add_filter( 'woocommerce_address_providers', [ __CLASS__, 'add_address_provider' ] );
// Add note query support for source.
add_filter( 'woocommerce_rest_notes_object_query', [ __CLASS__, 'possibly_add_source_to_notes_query' ], 10, 2 );
add_filter( 'woocommerce_note_where_clauses', [ __CLASS__, 'possibly_add_note_source_where_clause' ], 10, 2 );
// Priority 5 so we can manipulate the registered gateways before they are shown.
add_action( 'woocommerce_admin_field_payment_gateways', [ __CLASS__, 'hide_gateways_on_settings_page' ], 5 );
require_once __DIR__ . '/migrations/class-allowed-payment-request-button-types-update.php';
require_once __DIR__ . '/migrations/class-allowed-payment-request-button-sizes-update.php';
require_once __DIR__ . '/migrations/class-update-service-data-from-server.php';
require_once __DIR__ . '/migrations/class-additional-payment-methods-admin-notes-removal.php';
require_once __DIR__ . '/migrations/class-link-woopay-mutual-exclusion-handler.php';
require_once __DIR__ . '/migrations/class-gateway-settings-sync.php';
require_once __DIR__ . '/migrations/class-delete-active-woopay-webhook.php';
require_once __DIR__ . '/migrations/class-payment-method-deprecation-settings-update.php';
require_once __DIR__ . '/migrations/class-erase-bnpl-announcement-meta.php';
require_once __DIR__ . '/migrations/class-erase-deprecated-flags-and-options.php';
require_once __DIR__ . '/migrations/class-manual-capture-payment-method-settings-update.php';
add_action( 'woocommerce_woocommerce_payments_updated', [ new Allowed_Payment_Request_Button_Types_Update( self::get_gateway() ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Allowed_Payment_Request_Button_Sizes_Update( self::get_gateway() ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Update_Service_Data_From_Server( self::get_account_service() ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Additional_Payment_Methods_Admin_Notes_Removal(), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Link_WooPay_Mutual_Exclusion_Handler( self::get_gateway() ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Gateway_Settings_Sync( self::get_gateway(), self::get_payment_gateway_map() ), 'maybe_sync' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ '\WCPay\Migrations\Delete_Active_WooPay_Webhook', 'maybe_delete' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Payment_Method_Deprecation_Settings_Update( self::get_gateway(), self::get_payment_gateway_map(), Giropay_Payment_Method::PAYMENT_METHOD_STRIPE_ID, '7.9.0' ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Payment_Method_Deprecation_Settings_Update( self::get_gateway(), self::get_payment_gateway_map(), Sofort_Payment_Method::PAYMENT_METHOD_STRIPE_ID, '8.9.0' ), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Erase_Bnpl_Announcement_Meta(), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Erase_Deprecated_Flags_And_Options(), 'maybe_migrate' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ new \WCPay\Migrations\Manual_Capture_Payment_Method_Settings_Update( self::get_gateway(), self::get_payment_gateway_map() ), 'maybe_migrate' ] );
include_once WCPAY_ABSPATH . '/includes/class-wc-payments-explicit-price-formatter.php';
WC_Payments_Explicit_Price_Formatter::init();
include_once WCPAY_ABSPATH . 'includes/class-wc-payments-captured-event-note.php';
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-payments-admin-settings.php';
include_once WCPAY_ABSPATH . 'includes/fraud-prevention/class-order-fraud-and-risk-meta-box.php';
// Add admin screens.
if ( is_admin() ) {
include_once WCPAY_ABSPATH . 'includes/inline-script-payloads/class-woo-payments-payment-method-definitions.php';
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-payments-admin.php';
}
if ( is_admin() && current_user_can( 'manage_woocommerce' ) ) {
$admin = new WC_Payments_Admin(
self::$api_client,
self::get_gateway(),
self::$account,
self::$onboarding_service,
self::$order_service,
self::$incentives_service,
self::$fraud_service,
self::$database_cache
);
$admin->init_hooks();
$admin_settings = new WC_Payments_Admin_Settings( self::get_gateway(), self::get_account_service() );
$admin_settings->init_hooks();
// Use tracks loader only in admin screens because it relies on WC_Tracks loaded by WC_Admin.
include_once WCPAY_ABSPATH . 'includes/admin/tracks/tracks-loader.php';
$wcpay_status = new WC_Payments_Status( self::get_gateway(), self::get_wc_payments_http(), self::get_account_service() );
$wcpay_status->init_hooks();
$wcpay_order_frt_meta_box = new WCPay\Fraud_Prevention\Order_Fraud_And_Risk_Meta_Box( self::$order_service );
$wcpay_order_frt_meta_box->init_hooks();
// Initialize Stripe Billing deprecation notices.
include_once WCPAY_ABSPATH . '/includes/subscriptions/class-wc-payments-subscriptions-admin-notices.php';
$wcpay_subscriptions_admin_notices = new WC_Payments_Subscriptions_Admin_Notices();
$wcpay_subscriptions_admin_notices->init_hooks();
}
// Load Stripe Billing subscription integration.
include_once WCPAY_ABSPATH . '/includes/subscriptions/class-wc-payments-subscriptions.php';
WC_Payments_Subscriptions::init( self::$api_client, self::$customer_service, self::$order_service, self::$account, self::$token_service );
// Add hook to remove Stripe Billing deprecation note when WooCommerce Subscriptions is installed.
add_action( 'activated_plugin', [ __CLASS__, 'maybe_remove_stripe_billing_deprecation_note' ], 10, 1 );
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '7.9.0', '<' ) ) {
add_action( 'woocommerce_onboarding_profile_data_updated', 'WC_Payments_Features::maybe_enable_wcpay_subscriptions_after_onboarding', 10, 2 );
}
add_action( 'woocommerce_woocommerce_payments_updated', [ __CLASS__, 'maybe_disable_wcpay_subscriptions_on_update' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ __CLASS__, 'maybe_update_stripe_billing_deprecation_note' ] );
add_action( 'rest_api_init', [ __CLASS__, 'init_rest_api' ] );
add_action( 'woocommerce_woocommerce_payments_updated', [ __CLASS__, 'set_plugin_activation_timestamp' ] );
add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_dev_runtime_scripts' ] );
add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_assets_script' ] );
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_assets_script' ] );
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_cart_scripts' ] );
self::$duplicate_payment_prevention_service->init( self::$card_gateway, self::$order_service );
wcpay_get_container()->get( \WCPay\Internal\PluginManagement\TranslationsLoader::class )->init_hooks();
}
/**
* Returns the gateway's working mode.
*
* @return Mode
*/
public static function mode() {
return self::$mode;
}
/**
* Adds IPP Email template to WooCommerce emails.
*
* @param array $email_classes the email classes.
* @return array
*/
public static function add_ipp_emails( array $email_classes ): array {
$email_classes['WC_Payments_Email_IPP_Receipt'] = include __DIR__ . '/emails/class-wc-payments-email-ipp-receipt.php';
return $email_classes;
}
/**
* Prints the given message in an "admin notice" wrapper with "error" class.
*
* @param string $message Message to print. Can contain HTML.
*/
public static function display_admin_error( $message ) {
self::display_admin_notice( $message, 'notice-error' );
}
/**
* Prints the given message in an "admin notice" wrapper with provided classes.
*
* @param string $message Message to print. Can contain HTML.
* @param string $classes Space separated list of classes to be applied to notice element.
*/
public static function display_admin_notice( $message, $classes ) {
?>
<div class="notice wcpay-notice <?php echo esc_attr( $classes ); ?>">
<p><b>WooPayments</b></p>
<p><?php echo $message; // PHPCS:Ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p>
</div>
<?php
}
/**
* Get plugin headers and cache the result to avoid reopening the file.
* First call should execute get_file_data and fetch headers from plugin details comment.
* Subsequent calls return the value stored in the variable $plugin_headers.
*
* @return array Array with plugin headers
*/
public static function get_plugin_headers() {
if ( null === self::$plugin_headers ) {
self::$plugin_headers = get_file_data(
WCPAY_PLUGIN_FILE,
[
// Mirrors the functionality on WooCommerce core: https://github.com/woocommerce/woocommerce/blob/ff2eadeccec64aa76abd02c931bf607dd819bbf0/includes/wc-core-functions.php#L1916 .
'WCRequires' => 'WC requires at least',
'RequiresWP' => 'Requires at least',
'Version' => 'Version',
]
);
}
return self::$plugin_headers;
}
/**
* Adds the WooPayments' gateway class to the list of installed payment gateways.
*
* @param array $gateways Existing list of gateway classes that will be available for the merchant to configure.
* @return array The list of payment gateways that will be available, including WooPayments' Gateway class.
*/
public static function register_gateway( $gateways ) {
$payment_methods = array_keys( self::get_payment_method_map() );
$gateways[] = self::$card_gateway;
foreach ( $payment_methods as $payment_method_id ) {
if ( 'card' === $payment_method_id || 'link' === $payment_method_id ) {
continue;
}
$gateways[] = self::get_payment_gateway_by_id( $payment_method_id );
}
return $gateways;
}
/**
* Add the WooCommerce Payments address autocomplete provider, but only if a WCPay gateway is enabled.
*
* @psalm-suppress MissingDependency
*
* @param array $providers The address providers.
* @return array The address providers.
*/
public static function add_address_provider( $providers ) {
// Only enable address provider integration if a WCPay gateway is enabled.
if ( ! self::get_gateway()->is_enabled() ) {
return $providers;
}
if ( ! class_exists( 'Automattic\WooCommerce\Internal\AddressProvider\AbstractAutomatticAddressProvider' ) ) {
return $providers;
}
include_once __DIR__ . '/class-wc-payments-address-provider.php';
$providers[] = new WC_Payments_Address_Provider( self::$api_client, self::$account, self::$database_cache );
return $providers;
}
/**
* Called on Payments setting page.
*
* Remove all WCPay gateways except CC one.
*/
public static function hide_gateways_on_settings_page() {
$default_gateway = self::get_gateway();
foreach ( WC()->payment_gateways->payment_gateways as $index => $payment_gateway ) {
if ( $payment_gateway instanceof WC_Payment_Gateway_WCPay && $payment_gateway !== $default_gateway ) {
unset( WC()->payment_gateways->payment_gateways[ $index ] );
}
}
}
/**
* Sets WooPayments gateways at the beginning if not already in the ordering.
* Sets WooPayments gateways after the main gateway if already in the ordering.
*
* @param array $ordering Existing ordering of the payment gateways.
*
* @return array Modified ordering.
*/
public static function order_woopayments_gateways( $ordering ) {
try {
$ordering = (array) $ordering;
$woopayments_payment_methods = array_flip( self::get_woopayments_gateway_ids() );
$main_gateway_id = self::get_gateway()->id;
$main_gateway_position = $ordering[ $main_gateway_id ] ?? null;
$before = [];
$after = [];
foreach ( $ordering as $gateway_id => $position ) {
if ( null === $main_gateway_position || $position < $main_gateway_position ) {
$before[ $gateway_id ] = null; // `null` for now, the position will be set later.
} elseif ( $position > $main_gateway_position && ! isset( $woopayments_payment_methods[ $gateway_id ] ) ) {
$after[ $gateway_id ] = null; // `null` for now, the position will be set later.
}
}
$new_ordering = [];
if ( null === $main_gateway_position ) {
$new_ordering = array_merge( $woopayments_payment_methods, $before, $after );
} else {
$new_ordering = array_merge( $before, $woopayments_payment_methods, $after );
}
$index = 0;
foreach ( array_keys( $new_ordering ) as $gateway_id ) {
$new_ordering[ $gateway_id ] = $index++;
}
return $new_ordering;
} catch ( Exception $e ) {
if ( function_exists( 'wc_get_logger' ) ) {
$logger = wc_get_logger();
$logger->warning( 'Failed to order gateways: ' . $e->getMessage(), [ 'source' => 'woopayments' ] );
}
return $ordering;
}
}
/**
* Define fields for storing user preferences in the wp_usermeta table.
*
* Includes fields for inbox notifications and table column visibility.
*
* @param array $user_data_fields User data fields.
* @return array
*/
public static function add_user_data_fields( $user_data_fields ) {
return array_merge(
$user_data_fields,
[
// Inbox notifications.
'wc_payments_overview_inbox_last_read',
// Column visibility preferences.
'wc_payments_transactions_hidden_columns',
'wc_payments_transactions_blocked_hidden_columns',
'wc_payments_transactions_risk_review_hidden_columns',
'wc_payments_transactions_uncaptured_hidden_columns',
'wc_payments_payouts_hidden_columns',
'wc_payments_disputes_hidden_columns',
'wc_payments_documents_hidden_columns',
// WPORG 2025 merchant feedback prompt user dismissed state.
'wc_payments_wporg_review_2025_prompt_dismissed',
]
);
}
/**
* By default, new payment gateways are put at the bottom of the list on the admin "Payments" settings screen.
* For visibility, we want WooPayments to be at the top of the list.
* NOTE: this can be removed after WC version 5.6, when the api supports the use of source.
* https://github.com/woocommerce/woocommerce-admin/pull/6979
*
* @param array $args Existing ordering of the payment gateways.
* @param WP_REST_Request $request Full details about the request.
*
* @return array Modified ordering.
*/
public static function possibly_add_source_to_notes_query( $args, $request ) {
if ( isset( $request['source'] ) && ! isset( $args['source'] ) ) {
return array_merge(
$args,
[
'source' => wp_parse_list( $request['source'] ),
]
);
}
return $args;
}
/**
* Adds source where clause to note query.
* NOTE: this can be removed after WC version 5.6, when the api supports the use of source.
* https://github.com/woocommerce/woocommerce-admin/pull/6979
*
* @param string $where_clauses Existing ordering of the payment gateways.
* @param array $args Full details about the request.
*
* @return string Modified where clause.
*/
public static function possibly_add_note_source_where_clause( $where_clauses, $args ) {
if ( ! empty( $args['source'] ) && false === strpos( $where_clauses, 'AND source IN' ) ) {
$where_source_array = [];
foreach ( $args['source'] as $args_type ) {
$args_type = trim( $args_type );
$where_source_array[] = "'" . esc_sql( $args_type ) . "'";
}
$escaped_where_source = implode( ',', $where_source_array );
$where_clauses .= " AND source IN ($escaped_where_source)";
}
return $where_clauses;
}
/**
* Create the API client.
*
* @return WC_Payments_API_Client
*/
public static function create_api_client() {
require_once __DIR__ . '/wc-payment-api/models/class-wc-payments-api-charge.php';
require_once __DIR__ . '/wc-payment-api/models/class-wc-payments-api-abstract-intention.php';
require_once __DIR__ . '/wc-payment-api/models/class-wc-payments-api-payment-intention.php';
require_once __DIR__ . '/wc-payment-api/models/class-wc-payments-api-setup-intention.php';
require_once __DIR__ . '/wc-payment-api/class-wc-payments-api-client.php';
$http_class = self::get_wc_payments_http();
$api_client_class = apply_filters( 'wc_payments_api_client', WC_Payments_API_Client::class );
if ( ! class_exists( $api_client_class ) || ! is_subclass_of( $api_client_class, 'WC_Payments_API_Client' ) ) {
$api_client_class = WC_Payments_API_Client::class;
}
return new $api_client_class(
'WooCommerce Payments/' . WCPAY_VERSION_NUMBER,
$http_class,
self::$db_helper
);
}
/**
* Initialize the REST API controllers.
*/
public static function init_rest_api() {
// Ensures we are not initializing our REST during `rest_preload_api_request`.
// When constructor signatures change, in manual update scenarios we were running into fatals.
// Those fatals are not critical, but they cause hiccups in the release process as catches unnecessary attention.
if ( function_exists( 'get_current_screen' ) && get_current_screen() ) {
return;
}
include_once WCPAY_ABSPATH . 'includes/exceptions/class-rest-request-exception.php';
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-payments-rest-controller.php';
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-accounts-controller.php';
$accounts_controller = new WC_REST_Payments_Accounts_Controller( self::$api_client );
$accounts_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-deposits-controller.php';
$deposits_controller = new WC_REST_Payments_Deposits_Controller( self::$api_client );
$deposits_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-transactions-controller.php';
$transactions_controller = new WC_REST_Payments_Transactions_Controller( self::$api_client );
$transactions_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-disputes-controller.php';
$disputes_controller = new WC_REST_Payments_Disputes_Controller( self::$api_client );
$disputes_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-charges-controller.php';
$charges_controller = new WC_REST_Payments_Charges_Controller( self::$api_client );
$charges_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-connection-tokens-controller.php';
$conn_tokens_controller = new WC_REST_Payments_Connection_Tokens_Controller( self::$api_client );
$conn_tokens_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-orders-controller.php';
$orders_controller = new WC_REST_Payments_Orders_Controller( self::$api_client, self::get_gateway(), self::$customer_service, self::$order_service );
$orders_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-fraud-outcomes-controller.php';
$fraud_outcomes_controller = new WC_REST_Payments_Fraud_Outcomes_Controller( self::$api_client );
$fraud_outcomes_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-timeline-controller.php';
$timeline_controller = new WC_REST_Payments_Timeline_Controller( self::$api_client );
$timeline_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-webhook-controller.php';
$webhook_controller = new WC_REST_Payments_Webhook_Controller( self::$api_client, self::$webhook_processing_service );
$webhook_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-tos-controller.php';
$tos_controller = new WC_REST_Payments_Tos_Controller( self::$api_client, self::get_gateway(), self::$account );
$tos_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-terminal-locations-controller.php';
$accounts_controller = new WC_REST_Payments_Terminal_Locations_Controller( self::$api_client );
$accounts_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-settings-controller.php';
$settings_controller = new WC_REST_Payments_Settings_Controller( self::$api_client, self::get_gateway(), self::$account );
$settings_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-settings-option-controller.php';
$settings_option_controller = new WC_REST_Payments_Settings_Option_Controller( self::$api_client );
$settings_option_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-reader-controller.php';
$charges_controller = new WC_REST_Payments_Reader_Controller( self::$api_client, self::get_gateway(), self::$in_person_payments_receipts_service );
$charges_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-files-controller.php';
$files_controller = new WC_REST_Payments_Files_Controller( self::$api_client );
$files_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-capital-controller.php';
$capital_controller = new WC_REST_Payments_Capital_Controller( self::$api_client );
$capital_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-onboarding-controller.php';
$onboarding_controller = new WC_REST_Payments_Onboarding_Controller( self::$api_client, self::$onboarding_service );
$onboarding_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-customer-controller.php';
$customer_controller = new WC_REST_Payments_Customer_Controller( self::$api_client, self::$customer_service );
$customer_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-refunds-controller.php';
$refunds_controller = new WC_REST_Payments_Refunds_Controller( self::$api_client );
$refunds_controller->register_routes();
if ( WC_Payments_Features::is_documents_section_enabled() ) {
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-documents-controller.php';
$documents_controller = new WC_REST_Payments_Documents_Controller( self::$api_client );
$documents_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-vat-controller.php';
$vat_controller = new WC_REST_Payments_VAT_Controller( self::$api_client );
$vat_controller->register_routes();
}
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-payment-intents-controller.php';
$payment_intents_controller = new WC_REST_Payments_Payment_Intents_Controller(
self::$api_client,
self::get_gateway(),
wcpay_get_container()->get( OrderService::class ),
wcpay_get_container()->get( Level3Service::class )
);
$payment_intents_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-payments-authorizations-controller.php';
$authorizations_controller = new WC_REST_Payments_Authorizations_Controller( self::$api_client );
$authorizations_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/reports/class-wc-rest-payments-reports-transactions-controller.php';
$reports_transactions_controller = new WC_REST_Payments_Reports_Transactions_Controller( self::$api_client );
$reports_transactions_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/reports/class-wc-rest-payments-reports-authorizations-controller.php';
$reports_authorizations_controller = new WC_REST_Payments_Reports_Authorizations_Controller( self::$api_client );
$reports_authorizations_controller->register_routes();
include_once WCPAY_ABSPATH . 'includes/admin/class-wc-rest-woopay-session-controller.php';
$woopay_session_controller = new WC_REST_WooPay_Session_Controller();
$woopay_session_controller->register_routes();
}
/**
* Gets the file modified time as a cache buster if we're in dev mode, or the plugin version otherwise.
*
* @param string $file Local path to the file.
* @return string The cache buster value to use for the given file.
*/
public static function get_file_version( $file ): string {
if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( WCPAY_ABSPATH . $file ) ) {
return (string) filemtime( WCPAY_ABSPATH . trim( $file, '/' ) );
}
return WCPAY_VERSION_NUMBER;
}
/**
* Returns the WooPay_Tracker instance
*
* @return WooPay_Tracker instance
*/
public static function woopay_tracker(): WooPay_Tracker {
return self::$woopay_tracker;
}
/**
* Load script with all required dependencies.
*
* @param string $handler Script handler.
* @param string $script Script name.
* @param array $dependencies Additional dependencies.
*
* @return void
*/
public static function register_script_with_dependencies( string $handler, string $script, array $dependencies = [] ) {
$script_file = $script . '.js';
$script_src_url = plugins_url( $script_file, WCPAY_PLUGIN_FILE );
$script_asset_path = WCPAY_ABSPATH . $script . '.asset.php';
$script_asset = file_exists( $script_asset_path ) ? require $script_asset_path : [ 'dependencies' => [] ]; // nosemgrep: audit.php.lang.security.file.inclusion-arg -- server generated path is used.
$script_asset['dependencies'] = array_merge( $script_asset['dependencies'], $dependencies );
wp_register_script(
$handler,
$script_src_url,
$script_asset['dependencies'],
self::get_file_version( $script_file ),
true
);
}
/**
* Returns payment method instance by Stripe ID.
*
* @param string $payment_method_id Stripe payment method type ID.
* @return false|UPE_Payment_Method Matching Payment Method instance.
*/
public static function get_payment_method_by_id( $payment_method_id ) {
if ( ! isset( self::$payment_method_map[ $payment_method_id ] ) ) {
return false;
}
return self::$payment_method_map[ $payment_method_id ];
}
/**
* Returns payment gateway instance by Stripe ID.
*
* @param string $payment_method_id Stripe payment method type ID.
* @return false|WC_Payment_Gateway_WCPay Matching Payment Gateway instance.
*/
public static function get_payment_gateway_by_id( $payment_method_id ) {
if ( ! isset( self::$payment_gateway_map[ $payment_method_id ] ) ) {
return false;
}
return self::$payment_gateway_map[ $payment_method_id ];
}
/**
* Returns the WooPayments gateway IDs.
*
* @return array
*/
public static function get_woopayments_gateway_ids() {
$wcpay_gateway_ids = [];
foreach ( self::get_payment_gateway_map() as $gateway ) {
$wcpay_gateway_ids[] = $gateway->id;
}
return $wcpay_gateway_ids;
}
/**
* Returns Payment Method map.
*
* @return array
*/
public static function get_payment_method_map() {
return self::$payment_method_map;
}
/**
* Returns Payment Gateway map.
*
* @return array
*/
public static function get_payment_gateway_map() {
return self::$payment_gateway_map;
}
/**
* Returns the WC_Payment_Gateway_WCPay instance
*
* @return WC_Payment_Gateway_WCPay gateway instance
*/
public static function get_gateway() {
return self::$card_gateway;
}
/**
* Returns the WC_Payments_Checkout instance
*
* @return WC_Payments_Checkout gateway instance
*/
public static function get_wc_payments_checkout() {
return self::$wc_payments_checkout;
}
/**
* Returns the WC_Payments_Express_Checkout_Button_Helper instance.
*
* @return WC_Payments_Express_Checkout_Button_Helper instance.
*/
public static function get_express_checkout_helper() {
return self::$express_checkout_helper;
}
/**
* Returns the Database_Cache instance.
*
* @return Database_Cache Database_Cache instance.
*/
public static function get_database_cache(): Database_Cache {
return self::$database_cache;
}
/**
* Sets the Database_Cache instance.
*
* @param Database_Cache $database_cache The cache instance.
*/
public static function set_database_cache( Database_Cache $database_cache ) {
self::$database_cache = $database_cache;
}
/**
* Sets the card gateway instance.
*
* @param WC_Payment_Gateway_WCPay $gateway The card gateway instance.
*/
public static function set_gateway( $gateway ) {
self::$card_gateway = $gateway;
}
/**
* Sets the express checkout helper instance.
*
* @param WC_Payments_Express_Checkout_Button_Helper $express_checkout_helper The express checkout helper instance.
*/
public static function set_express_checkout_helper( $express_checkout_helper ) {
self::$express_checkout_helper = $express_checkout_helper;
}
/**
* Returns the WC_Payments_Account instance
*
* @return WC_Payments_Account account service instance
*/
public static function get_account_service() {
return self::$account;
}
/**
* Sets the account service instance.
*
* @param WC_Payments_Account $account The account instance.
*/
public static function set_account_service( WC_Payments_Account $account ) {
self::$account = $account;
}
/**
* Returns the WC_Payments_API_Client
*
* @return WC_Payments_API_Client API Client instance
*/
public static function get_payments_api_client() {
return self::$api_client;
}
/**
* Returns the WC_Payments_Localization_Service
*
* @return WC_Payments_Localization_Service Localization Service instance
*/
public static function get_localization_service() {
return self::$localization_service;
}
/**
* Returns the WC_Payments_Settings_Service
*
* @return WC_Payments_Settings_Service Localization Service instance
*/
public static function get_settings_service() {
return self::$settings_service;
}
/**
* Returns the WC_Payments_Action_Scheduler_Service
*
* @return WC_Payments_Action_Scheduler_Service Action Scheduler Service instance
*/
public static function get_action_scheduler_service() {
return self::$action_scheduler_service;
}
/**
* Returns the WC_Payments_Fraud_Service instance
*
* @return WC_Payments_Fraud_Service Fraud Service instance
*/
public static function get_fraud_service() {
return self::$fraud_service;
}
/**
* Returns the WC_Payments_Customer_Service instance
*
* @return WC_Payments_Customer_Service The Customer Service instance.
*/
public static function get_customer_service(): WC_Payments_Customer_Service {
return self::$customer_service;
}
/**
* Returns the WC_Payments_Customer_Service_API instance
*
* @return WC_Payments_Customer_Service_API The Customer Service instance.
*/
public static function get_customer_service_api(): WC_Payments_Customer_Service_API {
return self::$customer_service_api;
}
/**
* Returns the order service instance.
*
* @return WC_Payments_Order_Service
*/
public static function get_order_service(): WC_Payments_Order_Service {
return self::$order_service;
}
/**
* Returns the token service instance.
*
* @return WC_Payments_Token_Service
*/
public static function get_token_service(): WC_Payments_Token_Service {
return self::$token_service;
}
/**
* Sets the token service instance. This is needed only for tests.
*
* @param WC_Payments_Token_Service $token_service Instance of WC_Payments_Token_Service.
*
* @return void
*/
public static function set_token_service( WC_Payments_Token_Service $token_service ) {
self::$token_service = $token_service;
}
/**
* Sets the customer service instance. This is needed only for tests.
*
* @param WC_Payments_Customer_Service $customer_service_class Instance of WC_Payments_Customer_Service.
*
* @return void
*/
public static function set_customer_service( WC_Payments_Customer_Service $customer_service_class ) {
self::$customer_service = $customer_service_class;
}
/**
* Returns the WC_Payments_Session_Service instance
*
* @return WC_Payments_Session_Service Session Service instance
*/
public static function get_session_service() {
return self::$session_service;
}
/**
* Registers the payment method with the blocks registry.
*
* @param Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry The registry.
*/
public static function register_checkout_gateway( $payment_method_registry ) {
require_once __DIR__ . '/class-wc-payments-blocks-payment-method.php';
$payment_method_registry->register( new WC_Payments_Blocks_Payment_Method() );
}
/**
* Handles upgrade routines.
*/
public static function install_actions() {
if ( version_compare( WCPAY_VERSION_NUMBER, get_option( 'woocommerce_woocommerce_payments_version' ), '>' ) ) {
do_action( 'woocommerce_woocommerce_payments_updated' );
self::update_plugin_version();
}
}
/**
* Updates the plugin version in db.
*/
public static function update_plugin_version() {
update_option( 'woocommerce_woocommerce_payments_version', WCPAY_VERSION_NUMBER );
}
/**
* Sets the plugin activation timestamp.
*
* Use add_option so that we don't overwrite the value.
*/
public static function set_plugin_activation_timestamp() {
add_option( 'wcpay_activation_timestamp', time() );
}
/**
* Adds WCPay notes to the WC-Admin inbox.
*/
public static function add_woo_admin_notes() {
// Do not try to add notes on ajax requests to improve their performance.
if ( wp_doing_ajax() ) {
return;
}
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '4.4.0', '>=' ) ) {
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-set-https-for-checkout.php';
WC_Payments_Notes_Set_Https_For_Checkout::possibly_add_note();
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-set-up-stripelink.php';
WC_Payments_Notes_Set_Up_StripeLink::set_gateway( self::get_gateway() );
WC_Payments_Notes_Set_Up_StripeLink::possibly_add_note();
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-stripe-billing-deprecation.php';
WC_Payments_Notes_Stripe_Billing_Deprecation::possibly_add_note();
}
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '7.5', '<' ) && get_woocommerce_currency() === 'NOK' ) {
add_filter( 'admin_notices', [ __CLASS__, 'wcpay_show_old_woocommerce_for_norway_notice' ] );
}
add_filter( 'admin_notices', [ __CLASS__, 'wcpay_show_old_woocommerce_for_hungary_sweden_and_czech_republic' ] );
}
/**
* Removes deprecated notes i.e. no longer required notes.
*
* @return void
*/
public static function remove_deprecated_notes() {
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '4.4.0', '>=' ) ) {
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-qualitative-feedback.php';
WC_Payments_Notes_Qualitative_Feedback::possibly_delete_note();
}
}
/**
* Shows an alert notice for Norwegian merchants on WooCommerce 7.4 and below
*/
public static function wcpay_show_old_woocommerce_for_norway_notice() {
?>
<div class="notice wcpay-notice notice-error">
<p>
<?php
echo WC_Payments_Utils::esc_interpolated_html( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
sprintf(
/* translators: %1$s: WooCommerce, %2$s: WooPayments, a1: documentation URL */
__( 'The %1$s version you have installed is not compatible with %2$s for a Norwegian business. Please update %1$s to version 7.5 or above. You can do that via the <a1>the plugins page.</a1>', 'woocommerce-payments' ),
'WooCommerce',
'WooPayments'
),
[
'a1' => '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">',
]
)
?>
</p>
</div>
<?php
}
/**
* Removes WCPay notes from the WC-Admin inbox.
*/
public static function remove_woo_admin_notes() {
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '4.4.0', '>=' ) ) {
self::$remote_note_service->delete_notes();
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-qualitative-feedback.php';
WC_Payments_Notes_Qualitative_Feedback::possibly_delete_note();
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-set-https-for-checkout.php';
WC_Payments_Notes_Set_Https_For_Checkout::possibly_delete_note();
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-instant-deposits-eligible.php';
WC_Payments_Notes_Instant_Deposits_Eligible::possibly_delete_note();
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-set-up-stripelink.php';
WC_Payments_Notes_Set_Up_StripeLink::possibly_delete_note();
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-stripe-billing-deprecation.php';
WC_Payments_Notes_Stripe_Billing_Deprecation::possibly_delete_note();
}
}
/**
* Filter to check if WCPay should operate as usual (the customer can save payment methods at checkout and those payment methods
* will only be used on this site), or if saved cards should be available for all the sites on the multisite network.
*
* NOTE: DON'T USE THIS FILTER. Everything will break. At this moment, it's only intended to be used internally by Automattic.
*
* @return bool Normal WCPay behavior (false, default) or TRUE if the site should only use network-wide saved payment methods.
*/
public static function is_network_saved_cards_enabled() {
return apply_filters( 'wcpay_force_network_saved_cards', false );
}
/**
* Registers woopay hooks if the woopay feature flag is enabled.
* Removes WooPay webhooks if the merchant is not eligible.
*
* @return void
*/
public static function maybe_register_woopay_hooks() {
$is_woopay_eligible = WC_Payments_Features::is_woopay_eligible(); // Feature flag.
$is_woopay_enabled = 'yes' === self::get_gateway()->get_option( 'platform_checkout', 'no' );
if ( $is_woopay_eligible && $is_woopay_enabled ) {
add_action( 'wc_ajax_wcpay_init_woopay', [ WooPay_Session::class, 'ajax_init_woopay' ] );
add_action( 'wc_ajax_wcpay_get_woopay_session', [ WooPay_Session::class, 'ajax_get_woopay_session' ] );
add_action( 'wc_ajax_wcpay_set_woopay_phone_number', [ WooPay_Session::class, 'ajax_set_woopay_phone_number' ] );
add_action( 'wc_ajax_wcpay_get_woopay_signature', [ __CLASS__, 'ajax_get_woopay_signature' ] );
add_action( 'wc_ajax_wcpay_get_woopay_minimum_session_data', [ WooPay_Session::class, 'ajax_get_woopay_minimum_session_data' ] );
// This injects the payments API and draft orders into core, so the WooCommerce Blocks plugin is not necessary.
// We should remove this once both features are available by default in the WC minimum supported version.
// - The payments API is currently only available in feature builds (with flag `WC_BLOCKS_IS_FEATURE_PLUGIN`).
// - The Draft order status is available after WC blocks 7.5.0.
if (
! defined( 'WC_BLOCKS_IS_FEATURE_PLUGIN' ) &&
class_exists( 'Automattic\WooCommerce\Blocks\Package' ) &&
class_exists( 'Automattic\WooCommerce\Blocks\Payments\Api' )
) {
// Register payments API.
$blocks_package_container = Automattic\WooCommerce\Blocks\Package::container();
$blocks_package_container->register(
Automattic\WooCommerce\Blocks\Payments\Api::class,
function ( $container ) {
$payment_method_registry = $container->get( Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry::class );
$asset_data_registry = $container->get( Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry::class );
return new Automattic\WooCommerce\Blocks\Payments\Api( $payment_method_registry, $asset_data_registry );
}
);
$blocks_package_container->get( Automattic\WooCommerce\Blocks\Payments\Api::class );
// Register draft orders.
$draft_orders = $blocks_package_container->get( Automattic\WooCommerce\Blocks\Domain\Services\DraftOrders::class );
add_filter( 'wc_order_statuses', [ $draft_orders, 'register_draft_order_status' ] );
add_filter( 'woocommerce_register_shop_order_post_statuses', [ $draft_orders, 'register_draft_order_post_status' ] );
add_filter( 'woocommerce_analytics_excluded_order_statuses', [ $draft_orders, 'append_draft_order_post_status' ] );
add_filter( 'woocommerce_valid_order_statuses_for_payment', [ $draft_orders, 'append_draft_order_post_status' ] );
add_filter( 'woocommerce_valid_order_statuses_for_payment_complete', [ $draft_orders, 'append_draft_order_post_status' ] );
// Hook into the query to retrieve My Account orders so draft status is excluded.
add_action( 'woocommerce_my_account_my_orders_query', [ $draft_orders, 'delete_draft_order_post_status_from_args' ] );
add_action( 'woocommerce_cleanup_draft_orders', [ $draft_orders, 'delete_expired_draft_orders' ] );
add_action( 'admin_init', [ $draft_orders, 'install' ] );
}
new WooPay_Order_Status_Sync( self::$api_client, self::$account );
}
}
/**
* Initializes woopay direct checkout if the woopay feature flag is enabled.
*
* @return void
*/
public static function maybe_init_woopay_direct_checkout() {
if ( ! WC_Payments_Features::is_woopay_direct_checkout_enabled() ) {
return;
}
$woopay_direct_checkout = new WC_Payments_WooPay_Direct_Checkout( self::$woopay_util );
$woopay_direct_checkout->init();
}
/**
* Validates whether the common config script should be enqueued and enqueues it.
*
* If the express checkout button is disabled on the cart page, the common config
* script needs to be enqueued to ensure `wcpayConfig` is available on the cart page.
*
* @return void
*/
public static function validate_and_enqueue_woopay_common_config_script() {
$is_express_button_disabled_on_cart = self::get_express_checkout_helper()->is_cart()
&& ! self::get_express_checkout_helper()->is_available_at( 'cart', WC_Payments_WooPay_Button_Handler::BUTTON_LOCATIONS );
if ( $is_express_button_disabled_on_cart ) {
self::enqueue_woopay_common_config_script();
}
}
/**
* Enqueues the common config script.
*
* @return void
*/
public static function enqueue_woopay_common_config_script() {
try {
// is_test() throws if the class 'Mode' has not been initialized.
$is_test_mode = self::mode()->is_test();
} catch ( Exception $e ) {
// Default to false if the class 'Mode' has not been initialized.
$is_test_mode = false;
}
wp_register_script( 'WCPAY_WOOPAY_COMMON_CONFIG', '', [], WCPAY_VERSION_NUMBER, false );
wp_localize_script(
'WCPAY_WOOPAY_COMMON_CONFIG',
'wcpayConfig',
[
'woopayHost' => WooPay_Utilities::get_woopay_url(),
'testMode' => $is_test_mode,
'wcAjaxUrl' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
'woopaySessionNonce' => wp_create_nonce( 'woopay_session_nonce' ),
'woopayMerchantId' => Jetpack_Options::get_option( 'id' ),
'isWooPayDirectCheckoutEnabled' => WC_Payments_Features::is_woopay_direct_checkout_enabled(),
'platformTrackerNonce' => wp_create_nonce( 'platform_tracks_nonce' ),
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'woopayMinimumSessionData' => WooPay_Session::get_woopay_minimum_session_data(),
]
);
wp_enqueue_script( 'WCPAY_WOOPAY_COMMON_CONFIG' );
}
/**
* Enqueues the common config script if the WooPay Direct Checkout flow is
* enabled and the express checkout button is disabled on the cart page.
*
* @param bool $should_enqueue Whether the script should be enqueued.
*
* @return void
*/
public static function maybe_enqueue_woopay_common_config_script( $should_enqueue ) {
if ( ! $should_enqueue ) {
return;
}
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'validate_and_enqueue_woopay_common_config_script' ] );
}
/**
* Initializes express checkout buttons if payments are enabled
*
* @return void
*/
public static function maybe_display_express_checkout_buttons() {
if ( WC_Payments_Features::are_payments_enabled() ) {
$woopay_button_handler = new WC_Payments_WooPay_Button_Handler( self::$account, self::get_gateway(), self::$woopay_util, self::get_express_checkout_helper() );
$express_checkout_ajax_handler = new WC_Payments_Express_Checkout_Ajax_Handler( self::get_express_checkout_helper() );
$express_checkout_element_button_handler = new WC_Payments_Express_Checkout_Button_Handler( self::$account, self::get_gateway(), self::get_express_checkout_helper(), $express_checkout_ajax_handler );
$express_checkout_button_display_handler = new WC_Payments_Express_Checkout_Button_Display_Handler( self::get_gateway(), $woopay_button_handler, $express_checkout_element_button_handler, $express_checkout_ajax_handler, self::get_express_checkout_helper() );
$express_checkout_button_display_handler->init();
}
}
/**
* Retrieve a woopay request signature.
*
* @return void
*/
public static function ajax_get_woopay_signature() {
$is_nonce_valid = check_ajax_referer( 'woopay_signature_nonce', false, false );
if ( ! $is_nonce_valid ) {
wp_send_json_error(
__( 'You arent authorized to do that.', 'woocommerce-payments' ),
403
);
}
$woopay_util = new WooPay_Utilities();
$signature = $woopay_util->get_woopay_request_signature();
wp_send_json_success(
[
'signature' => $signature,
],
200
);
}
/**
* Get cart total.
*/
public static function ajax_get_cart_total() {
check_ajax_referer( 'wcpay-get-cart-total', 'security' );
if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
define( 'WOOCOMMERCE_CART', true );
}
if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
define( 'WOOCOMMERCE_CHECKOUT', true );
}
WC()->cart->calculate_totals();
$cart_total = WC()->cart->total;
$currency_code = get_woocommerce_currency();
wp_send_json( [ 'total' => WC_Payments_Utils::prepare_amount( $cart_total, $currency_code ) ] );
}
/**
* Check if BNPL is available for the given price, currency, and country.
*/
public static function ajax_check_bnpl_availability() {
check_ajax_referer( 'wcpay-is-bnpl-available', 'security' );
$price = floatval( $_POST['price'] );
$currency = sanitize_text_field( wp_unslash( $_POST['currency'] ) );
$country = sanitize_text_field( wp_unslash( $_POST['country'] ) );
$enabled_bnpl_payment_methods = array_intersect(
Payment_Method::BNPL_PAYMENT_METHODS,
self::get_gateway()->get_upe_enabled_payment_method_ids()
);
$is_available = WC_Payments_Utils::is_any_bnpl_method_available( $enabled_bnpl_payment_methods, $country, $currency, $price );
wp_send_json_success( [ 'is_available' => $is_available ] );
}
/**
* Adds custom email field.
*/
public static function woopay_fields_before_billing_details() {
$checkout = WC()->checkout;
echo '<div class="woocommerce-billing-fields" id="contact_details">';
echo '<h3>' . esc_html( __( 'Contact information', 'woocommerce-payments' ) ) . '</h3>';
echo '<div class="woocommerce-billing-fields__field-wrapper">';
woocommerce_form_field(
'billing_email',
[
'type' => 'email',
'label' => __( 'Email address', 'woocommerce-payments' ),
'class' => [ 'form-row-wide woopay-billing-email' ],
'input_class' => [ 'woopay-billing-email-input' ],
'validate' => [ 'email' ],
'required' => true,
],
$checkout->get_value( 'billing_email' )
);
echo '</div>';
echo '</div>';
// Ensure WC Blocks styles are enqueued so the spinner will show.
// This style is not enqueued be default when using a block theme and classic checkout.
wp_enqueue_style( 'wc-blocks-style' );
}
/**
* Hide the core email field
*
* @param string $field The checkout field being filtered.
* @param string $key The field key.
* @param mixed $args Field arguments.
* @param string $value Field value.
* @return string
*/
public static function filter_woocommerce_form_field_woopay_email( $field, $key, $args, $value ) {
$class = $args['class'][0];
if ( false === strpos( $class, 'woopay-billing-email' ) && is_checkout() && ! is_checkout_pay_page() ) {
$field = '';
}
return $field;
}
/**
* Enqueue cart page scripts.
*
* @return void
*/
public static function enqueue_cart_scripts() {
if ( ! WC_Payments_Utils::is_cart_page() || ! self::get_gateway()->is_enabled() ) {
return;
}
self::register_script_with_dependencies( 'WCPAY_CART', 'dist/cart' );
wp_enqueue_script( 'WCPAY_CART' );
if ( WC_Payments_Utils::is_cart_block() ) {
self::register_script_with_dependencies( 'WCPAY_CART_BLOCK', 'dist/cart-block', [ 'wc-cart-block-frontend' ] );
wp_enqueue_script( 'WCPAY_CART_BLOCK' );
// Enqueue cart block styles.
WC_Payments_Utils::enqueue_style(
'WCPAY_CART_BLOCK',
plugins_url( 'dist/cart-block.css', WCPAY_PLUGIN_FILE ),
[],
self::get_file_version( 'dist/cart-block.css' ),
'all'
);
}
}
/**
* Register woopay hooks and scripts if feature is available.
*
* @return void
*/
public static function init_woopay() {
// Load woopay save user section if feature is enabled.
if ( self::$woopay_util->should_enable_woopay( self::get_gateway() ) ) {
// Update email field location.
add_action( 'woocommerce_checkout_billing', [ __CLASS__, 'woopay_fields_before_billing_details' ], -50 );
add_filter( 'woocommerce_form_field_email', [ __CLASS__, 'filter_woocommerce_form_field_woopay_email' ], 20, 4 );
add_action( 'woocommerce_checkout_process', [ __CLASS__, 'maybe_show_woopay_phone_number_error' ] );
include_once __DIR__ . '/woopay-user/class-woopay-save-user.php';
new WooPay_Save_User();
}
}
/**
* Load stripe site messaging script.
*
* @return void
*/
public static function load_stripe_bnpl_site_messaging() {
// The messaging element shall not be shown for subscription products.
// As we are not too deep into subscriptions API, we follow simplistic approach for now.
$is_subscription = false;
$cart_contains_subscription = false;
$are_subscriptions_enabled = class_exists( 'WC_Subscriptions' ) || class_exists( 'WC_Subscriptions_Core_Plugin' );
if ( $are_subscriptions_enabled ) {
global $product;
$is_subscription = $product && WC_Subscriptions_Product::is_subscription( $product );
$cart_contains_subscription = is_cart() && WC_Subscriptions_Cart::cart_contains_subscription();
}
if ( ! $is_subscription && ! $cart_contains_subscription ) {
require_once __DIR__ . '/class-wc-payments-payment-method-messaging-element.php';
$stripe_site_messaging = new WC_Payments_Payment_Method_Messaging_Element( self::$account, self::$card_gateway );
echo wp_kses( $stripe_site_messaging->init() ?? '', 'post' );
}
}
/**
* Load webpack runtime script, only if SCRIPT_DEBUG is enabled and the script exists.
* Required for webpack server with HMR.
*
* @return void
*/
public static function enqueue_dev_runtime_scripts() {
if ( ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) && file_exists( WCPAY_ABSPATH . 'dist/runtime.js' ) ) {
wp_enqueue_script( 'WCPAY_RUNTIME', plugins_url( 'dist/runtime.js', WCPAY_PLUGIN_FILE ), [], self::get_file_version( 'dist/runtime.js' ), true );
}
}
/**
* Creates a new request object for a server call.
*
* @param string $class_name The name of the request class. Must extend WCPay\Core\Server\Request.
* @param mixed $id The item ID, if the request needs it (Optional).
* @return Request
* @throws Exception If the request class is not really a request.
*/
public static function create_request( $class_name, $id = null ) {
/**
* Used for unit tests only, as requests have dependencies, which are not publicly available in live mode.
*
* @param Request $request Null, but if the filter returns a request, it will be used.
* @param string $class_name The name of the request class.
*/
$request = apply_filters( 'wcpay_create_request', null, $class_name, $id );
if ( $request instanceof Request ) {
return $request;
}
if ( ! is_subclass_of( $class_name, Request::class ) ) {
throw new Exception(
sprintf(
'WC_Payments::create_request() requires a class, which extends %s, %s provided instead',
Request::class,
$class_name
)
);
}
return new $class_name( self::get_payments_api_client(), self::get_wc_payments_http(), $id );
}
/**
* Inject an inline script with WCPay assets properties.
* window.wcpayAssets.url Dist URL, required to properly load chunks on sites with JS concatenation enabled.
*
* @return void
*/
public static function enqueue_assets_script() {
wp_register_script( 'WCPAY_ASSETS', '', [], WCPAY_VERSION_NUMBER, false );
wp_enqueue_script( 'WCPAY_ASSETS' );
wp_localize_script(
'WCPAY_ASSETS',
'wcpayAssets',
[
'url' => plugins_url( '/dist/', WCPAY_PLUGIN_FILE ),
]
);
}
/**
* Shows an alert notice for Hungarian, Sweden, and Czech Republic merchants on WooCommerce 7.4 and below
*/
public static function wcpay_show_old_woocommerce_for_hungary_sweden_and_czech_republic() {
$currencies = [ 'HUF', 'SEK', 'CZK' ];
$store_currency = get_woocommerce_currency();
$should_show_error = in_array( $store_currency, $currencies, true );
if ( ! defined( 'WC_VERSION' ) || ! version_compare( WC_VERSION, '7.8', '<' ) || ! $should_show_error ) {
return;
}
$notice = '';
switch ( $store_currency ) {
case 'HUF':
/* translators: %1$s: WooCommerce , %2$s: WooPayments, %3$s: The current WooCommerce version used by the store */
$notice = __( 'The %1$s version you have installed is not compatible with %2$s for a Hungarian business. Please update %1$s to version 7.8 or above (you are using %3$s). You can do that via the <a1>the plugins page.</a1>', 'woocommerce-payments' );
break;
case 'SEK':
/* translators: %1$s: WooCommerce , %2$s: WooPayments, %3$s: The current WooCommerce version used by the store */
$notice = __( 'The %1$s version you have installed is not compatible with %2$s for a Swedish business. Please update %1$s to version 7.8 or above (you are using %3$s). You can do that via the <a1>the plugins page.</a1>', 'woocommerce-payments' );
break;
case 'CZK':
/* translators: %1$s: WooCommerce , %2$s: WooPayments, %3$s: The current WooCommerce version used by the store */
$notice = __( 'The %1$s version you have installed is not compatible with %2$s for a Czech Republic business. Please update %1$s to version 7.8 or above (you are using %3$s). You can do that via the <a1>the plugins page.</a1>', 'woocommerce-payments' );
break;
}
?>
<div class="notice wcpay-notice notice-error">
<p>
<?php
echo WC_Payments_Utils::esc_interpolated_html( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
sprintf(
$notice,
'WooCommerce',
'WooPayments',
esc_html( WC_VERSION )
),
[
'a1' => '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">',
]
)
?>
</p>
</div>
<?php
}
/**
* Disable the WCPay Subscriptions feature on WooPayments plugin update if it's enabled and the store is no longer eligible.
*
* @see WC_Payments_Features::is_wcpay_subscriptions_eligible() for eligibility criteria.
*/
public static function maybe_disable_wcpay_subscriptions_on_update() {
if ( WC_Payments_Features::is_wcpay_subscriptions_enabled() && ( class_exists( 'WC_Subscriptions' ) || ! WC_Payments_Features::is_wcpay_subscriptions_eligible() ) ) {
update_option( WC_Payments_Features::WCPAY_SUBSCRIPTIONS_FLAG_NAME, '0' );
}
}
/**
* Show error when WooPay opt-in is checked but no phone number was typed.
*/
public static function maybe_show_woopay_phone_number_error() {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( isset( $_POST['save_user_in_woopay'] ) && 'true' === $_POST['save_user_in_woopay'] ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['woopay_user_phone_field'] ) || ! isset( $_POST['woopay_user_phone_field']['no-country-code'] ) || empty( $_POST['woopay_user_phone_field']['no-country-code'] ) ) {
wc_add_notice( '<strong>' . __( 'Mobile Number', 'woocommerce-payments' ) . '</strong> ' . __( 'is required to create an WooPay account.', 'woocommerce-payments' ), 'error' );
}
}
}
/**
* Removes the Stripe Billing deprecation note when WooCommerce Subscriptions is installed.
*
* @param string $plugin The plugin being activated.
*/
public static function maybe_remove_stripe_billing_deprecation_note( $plugin ) {
if ( 'woocommerce-subscriptions/woocommerce-subscriptions.php' === $plugin || 'woocommerce-com-woocommerce-subscriptions/woocommerce-subscriptions.php' === $plugin ) {
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-stripe-billing-deprecation.php';
WC_Payments_Notes_Stripe_Billing_Deprecation::possibly_delete_note();
}
}
/**
* Update the Stripe Billing deprecation note.
*/
public static function maybe_update_stripe_billing_deprecation_note() {
// If bundled subscriptions are not enabled or WooCommerce Subscriptions is active, do not update the note.
$has_bundled_subs = WC_Payments_Features::is_wcpay_subscriptions_enabled() || WC_Payments_Features::is_stripe_billing_enabled();
if ( ! $has_bundled_subs || class_exists( 'WC_Subscriptions' ) ) {
return;
}
require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-stripe-billing-deprecation.php';
WC_Payments_Notes_Stripe_Billing_Deprecation::possibly_update_note();
}
/**
* Create the HTTP instantiation.
*
* @return WC_Payments_Http_Interface
*/
private static function get_wc_payments_http() {
require_once __DIR__ . '/wc-payment-api/class-wc-payments-http-interface.php';
require_once __DIR__ . '/wc-payment-api/class-wc-payments-http.php';
$http_class = apply_filters( 'wc_payments_http', null );
if ( ! $http_class instanceof WC_Payments_Http_Interface ) {
$http_class = new WC_Payments_Http( new Automattic\Jetpack\Connection\Manager( 'woocommerce-payments' ) );
$http_class->init_hooks();
}
return $http_class;
}
/**
* Determines whether we should load Stripe Billing integration classes.
*
* Return true when:
* - the WCPay Subscriptions feature is enabled & the Woo Subscriptions plugin isn't active, or
* - Woo Subscriptions plugin is active and Stripe Billing is enabled or there are Stripe Billing Subscriptions.
*
* @see WC_Payments_Features::should_use_stripe_billing()
*
* @return bool
*/
private static function should_load_stripe_billing_integration() {
if ( WC_Payments_Features::should_use_stripe_billing() ) {
return true;
}
if ( ! function_exists( 'wcs_get_orders_with_meta_query' ) ) {
return false;
}
// If there are any Stripe Billing Subscriptions, we should load the Stripe Billing integration classes. eg while a migration is in progress, or to support legacy subscriptions.
$result = wcs_get_orders_with_meta_query(
[
'status' => 'any',
'return' => 'ids',
'type' => 'shop_subscription',
'limit' => 1, // We only need to know if there are any - at least 1.
'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
[
'key' => '_wcpay_subscription_id',
'compare' => 'EXISTS',
],
],
]
);
return (bool) ( is_countable( $result ) ? count( $result ) : 0 );
}
}