account = $account; $this->gateway = $gateway; $this->express_checkout_helper = $express_checkout_helper; $this->express_checkout_ajax_handler = $express_checkout_ajax_handler; } /** * Initialize hooks. * * @return void */ public function init() { // Checks if WCPay is enabled. if ( ! $this->gateway->is_enabled() ) { return; } // Checks if Payment Request is enabled. if ( 'yes' !== $this->gateway->get_option( 'payment_request' ) ) { return; } // Don't load for change payment method page. if ( isset( $_GET['change_payment_method'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification return; } add_action( 'template_redirect', [ $this, 'set_session' ] ); add_action( 'template_redirect', [ $this, 'handle_express_checkout_redirect' ] ); add_filter( 'woocommerce_login_redirect', [ $this, 'get_login_redirect_url' ], 10, 3 ); add_filter( 'woocommerce_registration_redirect', [ $this, 'get_login_redirect_url' ], 10, 3 ); add_filter( 'woocommerce_cart_needs_shipping_address', [ $this, 'filter_cart_needs_shipping_address' ], 11, 1 ); add_action( 'wp_enqueue_scripts', [ $this, 'scripts' ] ); add_filter( 'woocommerce_gateway_title', [ $this, 'filter_gateway_title' ], 10, 2 ); add_action( 'woocommerce_checkout_order_processed', [ $this->express_checkout_helper, 'add_order_payment_method_title' ], 10, 2 ); $this->express_checkout_ajax_handler->init(); if ( is_admin() && current_user_can( 'manage_woocommerce' ) ) { $this->register_ece_data_for_block_editor(); } } /** * The settings for the `button` attribute - they depend on the "grouped settings" flag value. * * @return array */ public function get_button_settings() { $button_type = $this->gateway->get_option( 'payment_request_button_type' ); $common_settings = $this->express_checkout_helper->get_common_button_settings(); $express_checkout_button_settings = [ // Default format is en_US. 'locale' => apply_filters( 'wcpay_payment_request_button_locale', substr( get_locale(), 0, 2 ) ), 'branded_type' => 'default' === $button_type ? 'short' : 'long', ]; return array_merge( $common_settings, $express_checkout_button_settings ); } /** * Settings array for the user authentication dialog and redirection. * * @return array|false */ public function get_login_confirmation_settings() { if ( is_user_logged_in() || ! $this->is_authentication_required() ) { return false; } /* translators: The text encapsulated in `**` can be replaced with "Apple Pay" or "Google Pay". Please translate this text, but don't remove the `**`. */ $message = __( 'To complete your transaction with **the selected payment method**, you must log in or create an account with our site.', 'woocommerce-payments' ); $redirect_url = add_query_arg( [ '_wpnonce' => wp_create_nonce( 'wcpay-set-redirect-url' ), 'wcpay_express_checkout_redirect_url' => rawurlencode( home_url( add_query_arg( [] ) ) ), // Current URL to redirect to after login. ], home_url() ); return [ // nosemgrep: audit.php.wp.security.xss.query-arg -- home_url passed in to add_query_arg. 'message' => $message, 'redirect_url' => $redirect_url, ]; } /** * Checks whether authentication is required for checkout. * * @return bool */ public function is_authentication_required() { // If guest checkout is disabled and account creation is not possible, authentication is required. if ( 'no' === get_option( 'woocommerce_enable_guest_checkout', 'yes' ) && ! $this->is_account_creation_possible() ) { return true; } // If cart contains subscription and account creation is not posible, authentication is required. if ( $this->has_subscription_product() && ! $this->is_account_creation_possible() ) { return true; } return false; } /** * Checks whether cart contains a subscription product or this is a subscription product page. * * @return boolean */ public function has_subscription_product() { if ( ! class_exists( 'WC_Subscriptions_Product' ) || ! class_exists( 'WC_Subscriptions_Cart' ) ) { return false; } if ( $this->express_checkout_helper->is_product() ) { $product = $this->express_checkout_helper->get_product(); if ( WC_Subscriptions_Product::is_subscription( $product ) ) { return true; } } if ( $this->express_checkout_helper->is_checkout() || $this->express_checkout_helper->is_cart() ) { if ( WC_Subscriptions_Cart::cart_contains_subscription() ) { return true; } } return false; } /** * Checks whether account creation is possible during checkout. * * @return bool */ public function is_account_creation_possible() { $is_signup_from_checkout_allowed = 'yes' === get_option( 'woocommerce_enable_signup_and_login_from_checkout', 'no' ); // If a subscription is being purchased, check if account creation is allowed for subscriptions. if ( ! $is_signup_from_checkout_allowed && $this->has_subscription_product() ) { $is_signup_from_checkout_allowed = 'yes' === get_option( 'woocommerce_enable_signup_from_checkout_for_subscriptions', 'no' ); } // If automatically generate username/password are disabled, the Express Checkout API // can't include any of those fields, so account creation is not possible. return ( $is_signup_from_checkout_allowed && 'yes' === get_option( 'woocommerce_registration_generate_username', 'yes' ) && 'yes' === get_option( 'woocommerce_registration_generate_password', 'yes' ) ); } /** * Gets the parameters needed for Express Checkout functionality. * * @return array Parameters for Express Checkout. */ public function get_express_checkout_params() { /** * Allowing some specific configuration to be tweaked by 3pd. * * @since 9.5.0 */ return array_merge( apply_filters( 'wcpay_express_checkout_js_params', [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ), 'nonce' => [ 'platform_tracker' => wp_create_nonce( 'platform_tracks_nonce' ), // needed to communicate via the Store API. 'tokenized_cart_nonce' => wp_create_nonce( 'woopayments_tokenized_cart_nonce' ), 'tokenized_cart_session_nonce' => wp_create_nonce( 'woopayments_tokenized_cart_session_nonce' ), 'store_api_nonce' => wp_create_nonce( 'wc_store_api' ), ], 'checkout' => [ 'currency_code' => strtolower( get_woocommerce_currency() ), 'currency_decimals' => WC_Payments::get_localization_service()->get_currency_format( get_woocommerce_currency() )['num_decimals'], 'country_code' => substr( get_option( 'woocommerce_default_country' ), 0, 2 ), 'needs_shipping' => WC()->cart->needs_shipping(), // Defaults to 'required' to match how core initializes this option. 'needs_payer_phone' => 'required' === get_option( 'woocommerce_checkout_phone_field', 'required' ), 'allowed_shipping_countries' => array_keys( WC()->countries->get_shipping_countries() ?? [] ), 'display_prices_with_tax' => 'incl' === get_option( 'woocommerce_tax_display_cart' ), ], 'button' => $this->get_button_settings(), 'login_confirmation' => $this->get_login_confirmation_settings(), 'button_context' => $this->express_checkout_helper->get_button_context(), 'has_block' => has_block( 'woocommerce/cart' ) || has_block( 'woocommerce/checkout' ), 'product' => $this->express_checkout_helper->get_product_data(), 'store_name' => get_bloginfo( 'name' ), ] ), [ // placing these outside of the filter to prevent modification of the values. 'stripe' => [ 'publishableKey' => $this->account->get_publishable_key( WC_Payments::mode()->is_test() ), 'accountId' => $this->account->get_stripe_account_id(), 'locale' => WC_Payments_Utils::convert_to_stripe_locale( get_locale() ), ], ] ); } /** * Load public scripts and styles. */ public function scripts() { // Don't load scripts if page is not supported. if ( ! $this->express_checkout_helper->should_show_express_checkout_button() ) { return; } $express_checkout_params = $this->get_express_checkout_params(); WC_Payments::register_script_with_dependencies( 'WCPAY_EXPRESS_CHECKOUT_ECE', 'dist/express-checkout', [ 'jquery', 'stripe', ] ); WC_Payments_Utils::enqueue_style( 'WCPAY_EXPRESS_CHECKOUT_ECE', plugins_url( 'dist/express-checkout.css', WCPAY_PLUGIN_FILE ), [], WC_Payments::get_file_version( 'dist/express-checkout.css' ) ); wp_localize_script( 'WCPAY_EXPRESS_CHECKOUT_ECE', 'wcpayExpressCheckoutParams', $express_checkout_params ); wp_localize_script( 'WCPAY_BLOCKS_CHECKOUT', 'wcpayExpressCheckoutParams', $express_checkout_params ); wp_set_script_translations( 'WCPAY_EXPRESS_CHECKOUT_ECE', 'woocommerce-payments' ); wp_enqueue_script( 'WCPAY_EXPRESS_CHECKOUT_ECE' ); Fraud_Prevention_Service::maybe_append_fraud_prevention_token(); $gateways = WC()->payment_gateways->get_available_payment_gateways(); if ( isset( $gateways['woocommerce_payments'] ) ) { WC_Payments::get_wc_payments_checkout()->register_scripts(); } } /** * Display the express checkout button. */ public function display_express_checkout_button_html() { if ( ! $this->express_checkout_helper->should_show_express_checkout_button() ) { return; } ?>
session ) && WC()->session->has_session(); if ( $has_active_session ) { return; } $is_checkout_or_cart = $this->express_checkout_helper->is_checkout() || $this->express_checkout_helper->is_cart(); if ( ! $is_checkout_or_cart ) { return; } WC()->session->set_customer_session_cookie( true ); } /** * Handles express checkout redirect when the redirect dialog "Continue" button is clicked. */ public function handle_express_checkout_redirect() { if ( ! empty( $_GET['wcpay_express_checkout_redirect_url'] ) && ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'wcpay-set-redirect-url' ) // @codingStandardsIgnoreLine ) { $url = rawurldecode( esc_url_raw( wp_unslash( $_GET['wcpay_express_checkout_redirect_url'] ) ) ); // Sets a redirect URL cookie for 10 minutes, which we will redirect to after authentication. // Users will have a 10 minute timeout to login/create account, otherwise redirect URL expires. wc_setcookie( 'wcpay_express_checkout_redirect_url', $url, time() + MINUTE_IN_SECONDS * 10 ); // Redirects to "my-account" page. wp_safe_redirect( get_permalink( get_option( 'woocommerce_myaccount_page_id' ) ) ); } } /** * Returns the login redirect URL. * * @param string $redirect Default redirect URL. * * @return string Redirect URL. */ public function get_login_redirect_url( $redirect ) { $url = esc_url_raw( wp_unslash( $_COOKIE['wcpay_express_checkout_redirect_url'] ?? '' ) ); if ( empty( $url ) ) { return $redirect; } wc_setcookie( 'wcpay_express_checkout_redirect_url', '' ); return $url; } /** * Determine whether to filter the cart needs shipping address. * * @param boolean $needs_shipping_address Whether the cart needs a shipping address. */ public function filter_cart_needs_shipping_address( $needs_shipping_address ) { if ( $this->has_subscription_product() && wc_get_shipping_method_count( true, true ) === 0 ) { return false; } return $needs_shipping_address; } /** * Filters the gateway title to reflect the button type used. * * @param string $title Gateway title. * @param string $id Gateway ID. */ public function filter_gateway_title( $title, $id ) { if ( 'woocommerce_payments' !== $id || ! is_admin() ) { return $title; } $order = $this->express_checkout_helper->get_current_order(); $method_title = is_object( $order ) ? $order->get_payment_method_title() : ''; if ( ! empty( $method_title ) ) { if ( strpos( $method_title, 'Apple Pay' ) === 0 || strpos( $method_title, 'Google Pay' ) === 0 || strpos( $method_title, 'Payment Request' ) === 0 // Legacy PRB title. ) { return $method_title; } } return $title; } /** * Add ECE data to `wcSettings` to allow it to be accessed by the front-end JS script in the Block editor. * * @return void */ private function register_ece_data_for_block_editor() { $data_registry = Package::container()->get( AssetDataRegistry::class ); if ( $data_registry->exists( 'ece_data' ) ) { return; } $data_registry->add( 'ece_data', [ 'button' => $this->get_button_settings(), ] ); } }