<?php
/**
* Class WC_Payments_Redirect_Service
*
* @package WooCommerce\Payments
*/
use WCPay\Core\Server\Request\Get_Account_Capital_Link;
use WCPay\Core\Server\Request\Get_Account_Login_Data;
use WCPay\Exceptions\API_Exception;
use WCPay\Tracker;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Class handling redirects business logic.
*/
class WC_Payments_Redirect_Service {
/**
* Client for making requests to the WooCommerce Payments API
*
* @var WC_Payments_API_Client
*/
private $payments_api_client;
/**
* Constructor for WC_Payments_Session_Service.
*
* @param WC_Payments_API_Client $payments_api_client - WooCommerce Payments API client.
*/
public function __construct(
WC_Payments_API_Client $payments_api_client
) {
$this->payments_api_client = $payments_api_client;
}
/**
* Calls wp_safe_redirect and exit.
*
* This method will end the execution immediately after the redirection.
*
* @param string $location The URL to redirect to.
*/
public function redirect_to( string $location ): void {
wp_safe_redirect( $location );
exit;
}
/**
* Redirects to a wcpay-connect URL which then handles the next step for the onboarding flow.
*
* This is a sure way to ensure that the user is redirected to the correct URL to continue their onboarding.
*
* @param string $from Source of the redirect.
* @param array $additional_params Optional. Additional URL params to add to the redirect URL.
*/
public function redirect_to_wcpay_connect( string $from = '', array $additional_params = [] ): void {
// Take the user to the 'wcpay-connect' URL.
// We handle creating and redirecting to the account link there.
$params = [
'wcpay-connect' => '1',
'_wpnonce' => wp_create_nonce( 'wcpay-connect' ),
];
$params = array_merge( $params, $additional_params );
if ( '' !== $from ) {
$params['from'] = $from;
}
$connect_url = add_query_arg(
$params,
admin_url( 'admin.php' )
);
$this->redirect_to( $connect_url );
}
/**
* Redirects to the capital view offer page or overview page with error message.
*/
public function redirect_to_capital_view_offer_page(): void {
$return_url = WC_Payments_Account::get_overview_page_url();
$refresh_url = add_query_arg( [ 'wcpay-loan-offer' => '' ], admin_url( 'admin.php' ) );
try {
$request = Get_Account_Capital_Link::create();
$type = 'capital_financing_offer';
$request->set_type( $type );
$request->set_return_url( $return_url );
$request->set_refresh_url( $refresh_url );
$capital_link = $request->send();
Tracker::track_admin( 'wcpay_capital_view_offer_redirect' );
$this->redirect_to( $capital_link['url'] );
} catch ( Exception $e ) {
$this->redirect_to_overview_page_with_error( [ 'wcpay-loan-offer-error' => '1' ] );
}
}
/**
* Function to immediately redirect to the account link.
*
* @param array $args The arguments to be sent with the link request.
*/
public function redirect_to_account_link( array $args ): void {
try {
$link = $this->payments_api_client->get_link( $args );
if ( isset( $args['type'] ) && 'complete_kyc_link' === $args['type'] && isset( $link['state'] ) ) {
set_transient( 'wcpay_stripe_onboarding_state', $link['state'], DAY_IN_SECONDS );
}
$this->redirect_to( $link['url'] );
} catch ( API_Exception $e ) {
$this->redirect_to_overview_page_with_error( [ 'wcpay-server-link-error' => '1' ] );
}
}
/**
* Immediately redirect to the NOX page.
*
* Note that this function immediately ends the execution.
*
* @param string|null $from Optional. Location of the redirect.
* @param string|null $source Optional. Where the merchant entered the onboarding flow.
*/
public function redirect_to_nox_flow( ?string $from = null, ?string $source = null ): void {
// If the WC Admin version is less than 9.5, redirect to the Connect page instead.
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '9.9.3', '<' ) ) {
$this->redirect_to_connect_page( null, $from, [ 'source' => $source ] );
}
$params = [
'page' => 'wc-settings',
'tab' => 'checkout',
'path' => '/woopayments/onboarding',
];
if ( ! empty( $from ) ) {
$params['from'] = $from;
}
if ( ! empty( $source ) ) {
$params['source'] = $source;
}
$this->redirect_to( admin_url( add_query_arg( $params, 'admin.php' ) ) );
}
/**
* Immediately redirect to the Connect page.
*
* Note that this function immediately ends the execution.
*
* @param string|null $error_message Optional. Error message to show in a notice.
* @param string|null $from Optional. Source of the redirect.
* @param array $additional_params Optional. Additional URL params to add to the redirect URL.
*/
public function redirect_to_connect_page( ?string $error_message = null, ?string $from = null, array $additional_params = [] ): void {
$params = [
'page' => 'wc-admin',
'path' => '/payments/connect',
];
if ( count( $params ) === count( array_intersect_assoc( $_GET, $params ) ) ) { // phpcs:disable WordPress.Security.NonceVerification.Recommended
// We are already on the Connect page. Do nothing.
return;
}
// If we were given an error message, store it in a very short-lived transient to show it on the page.
if ( ! empty( $error_message ) ) {
set_transient( WC_Payments_Account::ERROR_MESSAGE_TRANSIENT, $error_message, 30 );
}
$params = array_merge( $params, $additional_params );
if ( ! empty( $from ) ) {
$params['from'] = $from;
}
$this->redirect_to( admin_url( add_query_arg( $params, 'admin.php' ) ) );
}
/**
* Immediately redirect to the onboarding wizard.
*
* Note that this function immediately ends the execution.
*
* @param string|null $from Optional. Source of the redirect.
* @param array $additional_params Optional. Additional URL params to add to the redirect URL.
*/
public function redirect_to_onboarding_wizard( ?string $from = null, array $additional_params = [] ): void {
$params = [
'page' => 'wc-admin',
'path' => '/payments/onboarding',
];
if ( count( $params ) === count( array_intersect_assoc( $_GET, $params ) ) ) { // phpcs:disable WordPress.Security.NonceVerification.Recommended
// We are already in the onboarding wizard. Do nothing.
return;
}
$params = array_merge( $params, $additional_params );
if ( ! empty( $from ) ) {
$params['from'] = $from;
}
$this->redirect_to( admin_url( add_query_arg( $params, 'admin.php' ) ) );
}
/**
* Immediately redirect to the settings page.
*
* Note that this function immediately ends the execution.
*
* @param string|null $from Optional. Source of the redirect.
* @param array $additional_params Optional. Additional URL params to add to the redirect URL.
*/
public function redirect_to_settings_page( ?string $from = null, array $additional_params = [] ): void {
$params = [
'page' => 'wc-settings',
'tab' => 'checkout',
];
if ( count( $params ) === count( array_intersect_assoc( $_GET, $params ) ) ) { // phpcs:disable WordPress.Security.NonceVerification.Recommended
// We are already in the settings page. Do nothing.
return;
}
$params = array_merge( $params, $additional_params );
if ( ! empty( $from ) ) {
$params['from'] = $from;
}
$this->redirect_to( admin_url( add_query_arg( $params, 'admin.php' ) ) );
}
/**
* Redirect to the overview page.
*
* @param string $from Optional. Source of the redirect.
* @param array $additional_params Optional. Additional URL params to add to the redirect URL.
* */
public function redirect_to_overview_page( string $from = '', array $additional_params = [] ): void {
$params = $additional_params;
if ( '' !== $from ) {
$params['from'] = $from;
}
$this->redirect_to( add_query_arg( $params, WC_Payments_Account::get_overview_page_url() ) );
}
/**
* Redirect to the overview page with an error message.
*
* @param array $error The error data to show.
*/
public function redirect_to_overview_page_with_error( array $error ): void {
$overview_url_with_error = add_query_arg(
$error,
WC_Payments_Account::get_overview_page_url()
);
$this->redirect_to( $overview_url_with_error );
}
/**
* For the connected account, fetches the login url from the API and redirects to it.
*/
public function redirect_to_login(): void {
$redirect_url = WC_Payments_Account::get_overview_page_url();
$request = Get_Account_Login_Data::create();
$request->set_redirect_url( $redirect_url );
$response = $request->send();
$login_data = $response->to_array();
$this->redirect_to( $login_data['url'] );
}
}