1592 lines
59 KiB
PHP
1592 lines
59 KiB
PHP
<?php
|
|
/**
|
|
* Set up top-level menus for WCPay.
|
|
*
|
|
* @package WooCommerce\Payments\Admin
|
|
*/
|
|
|
|
use Automattic\Jetpack\Identity_Crisis as Jetpack_Identity_Crisis;
|
|
use Automattic\Jetpack\Constants;
|
|
use Automattic\WooCommerce\Admin\Features\Features;
|
|
use WCPay\Constants\Intent_Status;
|
|
use WCPay\Core\Server\Request;
|
|
use WCPay\Database_Cache;
|
|
use WCPay\Inline_Script_Payloads\Woo_Payments_Payment_Method_Definitions;
|
|
use WCPay\Inline_Script_Payloads\Woo_Payments_Payment_Methods_Config;
|
|
use WCPay\Logger;
|
|
use WCPay\WooPay\WooPay_Utilities;
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
/**
|
|
* WC_Payments_Admin Class.
|
|
*/
|
|
class WC_Payments_Admin {
|
|
|
|
/**
|
|
* Badge with number "1" displayed next to a menu item when there is something important to communicate on a page.
|
|
*
|
|
* @var string
|
|
*/
|
|
const MENU_NOTIFICATION_BADGE = ' <span class="wcpay-menu-badge awaiting-mod count-1"><span class="plugin-count">1</span></span>';
|
|
|
|
/**
|
|
* Badge with a count (number of unresolved items) displayed next to a menu item.
|
|
* Unresolved refers to items that are unread or need action.
|
|
*
|
|
* @var string
|
|
*/
|
|
const UNRESOLVED_NOTIFICATION_BADGE_FORMAT = ' <span class="wcpay-menu-badge awaiting-mod count-%1$s"><span class="plugin-count">%1$d</span></span>';
|
|
|
|
/**
|
|
* WC Payments WordPress Admin menu slug.
|
|
*
|
|
* @var string
|
|
*/
|
|
const PAYMENTS_SUBMENU_SLUG = 'wc-admin&path=/payments/overview';
|
|
|
|
/**
|
|
* Client for making requests to the WooCommerce Payments API.
|
|
*
|
|
* @var WC_Payments_API_Client
|
|
*/
|
|
protected $payments_api_client;
|
|
|
|
/**
|
|
* WCPay Gateway instance to get information regarding WooCommerce Payments setup.
|
|
*
|
|
* @var WC_Payment_Gateway_WCPay
|
|
*/
|
|
private $wcpay_gateway;
|
|
|
|
/**
|
|
* WC_Payments_Account instance to get information about the account
|
|
*
|
|
* @var WC_Payments_Account
|
|
*/
|
|
private $account;
|
|
|
|
/**
|
|
* WC_Payments_Onboarding_Service instance to get information for onboarding.
|
|
*
|
|
* @var WC_Payments_Onboarding_Service
|
|
*/
|
|
private $onboarding_service;
|
|
|
|
/**
|
|
* Instance of Order Service for accessing order data.
|
|
*
|
|
* @var WC_Payments_Order_Service
|
|
*/
|
|
private $order_service;
|
|
|
|
/**
|
|
* WC_Payments_Incentives_Service instance to get information for incentives.
|
|
*
|
|
* @var WC_Payments_Incentives_Service
|
|
*/
|
|
private $incentives_service;
|
|
|
|
/**
|
|
* WC_Payments_PM_Promotions_Service instance to get information for payment method promotions.
|
|
*
|
|
* @var WC_Payments_PM_Promotions_Service
|
|
*/
|
|
private $pm_promotions_service;
|
|
|
|
/**
|
|
* WC_Payments_Fraud_Service instance to get information about fraud services.
|
|
*
|
|
* @var WC_Payments_Fraud_Service
|
|
*/
|
|
private $fraud_service;
|
|
|
|
/**
|
|
* WCPay admin child pages.
|
|
*
|
|
* @var array
|
|
*/
|
|
private $admin_child_pages;
|
|
|
|
/**
|
|
* Database_Cache instance.
|
|
*
|
|
* @var Database_Cache
|
|
*/
|
|
private $database_cache;
|
|
|
|
/**
|
|
* The internal cache for WCPay settings passed to JS through script localization.
|
|
*
|
|
* This data should only be generated once per request, hence the internal cache.
|
|
*
|
|
* @see self::get_js_settings()
|
|
*
|
|
* @var ?array
|
|
*/
|
|
private $wcpay_js_settings = null;
|
|
|
|
/**
|
|
* Hook in admin menu items.
|
|
*
|
|
* @param WC_Payments_API_Client $payments_api_client WooCommerce Payments API client.
|
|
* @param WC_Payment_Gateway_WCPay $gateway WCPay Gateway instance to get information regarding WooCommerce Payments setup.
|
|
* @param WC_Payments_Account $account Account instance.
|
|
* @param WC_Payments_Onboarding_Service $onboarding_service Onboarding service instance.
|
|
* @param WC_Payments_Order_Service $order_service Order service instance.
|
|
* @param WC_Payments_Incentives_Service $incentives_service Incentives service instance.
|
|
* @param WC_Payments_PM_Promotions_Service $pm_promotions_service PM Promotions service instance.
|
|
* @param WC_Payments_Fraud_Service $fraud_service Fraud service instance.
|
|
* @param Database_Cache $database_cache Database Cache instance.
|
|
*/
|
|
public function __construct(
|
|
WC_Payments_API_Client $payments_api_client,
|
|
WC_Payment_Gateway_WCPay $gateway,
|
|
WC_Payments_Account $account,
|
|
WC_Payments_Onboarding_Service $onboarding_service,
|
|
WC_Payments_Order_Service $order_service,
|
|
WC_Payments_Incentives_Service $incentives_service,
|
|
WC_Payments_PM_Promotions_Service $pm_promotions_service,
|
|
WC_Payments_Fraud_Service $fraud_service,
|
|
Database_Cache $database_cache
|
|
) {
|
|
$this->payments_api_client = $payments_api_client;
|
|
$this->wcpay_gateway = $gateway;
|
|
$this->account = $account;
|
|
$this->onboarding_service = $onboarding_service;
|
|
$this->order_service = $order_service;
|
|
$this->incentives_service = $incentives_service;
|
|
$this->pm_promotions_service = $pm_promotions_service;
|
|
$this->fraud_service = $fraud_service;
|
|
$this->database_cache = $database_cache;
|
|
}
|
|
|
|
/**
|
|
* Initializes this class's WP hooks.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function init_hooks() {
|
|
add_action( 'admin_notices', [ $this, 'display_not_supported_currency_notice' ], 9999 );
|
|
add_action( 'admin_notices', [ $this, 'display_isk_decimal_notice' ] );
|
|
|
|
add_action( 'woocommerce_admin_order_data_after_payment_info', [ $this, 'render_order_edit_payment_details_container' ] );
|
|
|
|
// Add menu items.
|
|
add_action( 'admin_menu', [ $this, 'add_payments_menu' ], 0 );
|
|
// Run this after the redirects in WC_Payments_Account.
|
|
add_action( 'admin_init', [ $this, 'maybe_redirect_from_payments_admin_child_pages' ], 16 );
|
|
add_action( 'admin_enqueue_scripts', [ $this, 'register_payments_scripts' ], 9 );
|
|
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_payments_scripts' ], 9 );
|
|
add_action( 'woocommerce_admin_order_totals_after_total', [ $this, 'show_woopay_payment_method_name_admin' ] );
|
|
add_action( 'woocommerce_admin_order_totals_after_total', [ $this, 'display_wcpay_transaction_fee' ] );
|
|
add_action( 'admin_init', [ $this, 'redirect_deposits_to_payouts' ] );
|
|
add_action( 'woocommerce_update_options_site-visibility', [ $this, 'inform_stripe_when_store_goes_live' ] );
|
|
add_action( 'admin_init', [ $this, 'add_css_classes' ] );
|
|
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_wc_payment_settings_spotlight' ] );
|
|
add_action( 'admin_footer', [ $this, 'inject_payment_settings_spotlight_container' ] );
|
|
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_wc_payments_review_prompt' ] );
|
|
}
|
|
|
|
/**
|
|
* When a store transitions to live mode, we need to notify Stripe to trigger necessary verification checks.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function inform_stripe_when_store_goes_live() {
|
|
|
|
$nonce = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '';
|
|
// New Settings API uses wp_rest nonce.
|
|
$nonce_string = Features::is_enabled( 'settings' ) ? 'wp_rest' : 'woocommerce-settings';
|
|
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, $nonce_string ) ) {
|
|
return;
|
|
}
|
|
|
|
// If an account is not connected, we can skip this.
|
|
if ( ! $this->account->is_stripe_connected() ) {
|
|
return;
|
|
}
|
|
|
|
$coming_soon_value = get_option( 'woocommerce_coming_soon' );
|
|
$coming_soon_new_value = sanitize_text_field( wp_unslash( $_POST['woocommerce_coming_soon'] ) );
|
|
|
|
// If the store is transitioning from coming soon to live, Stripe should be notified.
|
|
// This is triggered by updating the account business URL.
|
|
if ( 'no' === $coming_soon_new_value && $coming_soon_value !== $coming_soon_new_value ) {
|
|
$response = $this->wcpay_gateway->update_account_settings( [ 'account_business_url' => $this->account->get_business_url() ] );
|
|
if ( is_wp_error( $response ) ) {
|
|
Logger::error( 'Failed to update account business URL.' );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Redirect /payments/deposits to /payments/payouts.
|
|
*/
|
|
public function redirect_deposits_to_payouts() {
|
|
if ( is_admin() && isset( $_GET['page'] ) && 'wc-admin' === $_GET['page'] && isset( $_GET['path'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
|
|
$redirect_map = [
|
|
'/payments/deposits' => '/payments/payouts',
|
|
'/payments/deposits/details' => '/payments/payouts/details',
|
|
];
|
|
$query_params = $_GET; // phpcs:ignore WordPress.Security.NonceVerification
|
|
if ( isset( $redirect_map[ $query_params['path'] ] ) ) {
|
|
$query_params['path'] = $redirect_map[ $query_params['path'] ];
|
|
$redirect_url = add_query_arg(
|
|
$query_params,
|
|
admin_url( 'admin.php?page=wc-admin' ),
|
|
);
|
|
wp_safe_redirect( $redirect_url );
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add notice explaining that the selected currency is not available.
|
|
*/
|
|
public function display_not_supported_currency_notice() {
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! $this->wcpay_gateway->is_available_for_current_currency() ) {
|
|
?>
|
|
<div id="wcpay-unsupported-currency-notice" class="notice notice-warning">
|
|
<p>
|
|
<b>
|
|
<?php esc_html_e( 'Unsupported currency:', 'woocommerce-payments' ); ?>
|
|
<?php esc_html( ' ' . get_woocommerce_currency() ); ?>
|
|
</b>
|
|
<?php
|
|
printf(
|
|
/* translators: %s: WooPayments*/
|
|
esc_html__( 'The selected currency is not available for the country set in your %s account.', 'woocommerce-payments' ),
|
|
'WooPayments'
|
|
);
|
|
?>
|
|
</p>
|
|
</div>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Render a container for adding notices to order details screen payment box.
|
|
*/
|
|
public function render_order_edit_payment_details_container() {
|
|
?>
|
|
<div id="wcpay-order-payment-details-container"></div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Add notice explaining that ISK cannot have decimals.
|
|
*/
|
|
public function display_isk_decimal_notice() {
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( get_woocommerce_currency() === 'ISK' && wc_get_price_decimals() !== 0 ) {
|
|
$url = get_admin_url( null, 'admin.php?page=wc-settings' );
|
|
|
|
?>
|
|
<div id="wcpay-unsupported-currency-notice" class="notice notice-error">
|
|
<p>
|
|
<b>
|
|
<?php esc_html_e( 'Unsupported currency:', 'woocommerce-payments' ); ?>
|
|
<?php esc_html( ' ' . get_woocommerce_currency() ); ?>
|
|
</b>
|
|
<?php
|
|
echo wp_kses_post(
|
|
sprintf(
|
|
/* Translators: %1$s: Opening anchor tag. %2$s: Closing anchor tag.*/
|
|
__( 'Icelandic Króna does not accept decimals. Please update your currency number of decimals to 0 or select a different currency. %1$sVisit settings%2$s', 'woocommerce-payments' ),
|
|
'<a href="' . $url . '">',
|
|
'</a>'
|
|
)
|
|
);
|
|
?>
|
|
</p>
|
|
</div>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add payments menu items.
|
|
*/
|
|
public function add_payments_menu() {
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
return;
|
|
}
|
|
global $submenu;
|
|
|
|
$this->admin_child_pages = [
|
|
'wc-payments-overview' => [
|
|
'id' => 'wc-payments-overview',
|
|
'title' => __( 'Overview', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/overview',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 10,
|
|
],
|
|
],
|
|
'wc-payments-deposits' => [
|
|
'id' => 'wc-payments-deposits',
|
|
'title' => __( 'Payouts', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/payouts',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 20,
|
|
],
|
|
],
|
|
'wc-payments-transactions' => [
|
|
'id' => 'wc-payments-transactions',
|
|
'title' => __( 'Transactions', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/transactions',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 30,
|
|
],
|
|
],
|
|
'wc-payments-disputes' => [
|
|
'id' => 'wc-payments-disputes',
|
|
'title' => __( 'Disputes', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/disputes',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 40,
|
|
],
|
|
],
|
|
];
|
|
|
|
try {
|
|
// Render full payments menu with sub-items only if:
|
|
// - we have working WPCOM/Jetpack connection;
|
|
// - the Stripe account is valid (connected, details submitted, and proper capabilities).
|
|
$should_render_full_menu = $this->account->has_working_jetpack_connection() && $this->account->is_stripe_account_valid();
|
|
} catch ( Exception $e ) {
|
|
// There is an issue with connection, don't render full menu, user will get redirected to the connect page.
|
|
$should_render_full_menu = false;
|
|
}
|
|
|
|
$top_level_link = $should_render_full_menu ? '/payments/overview' : '/payments/connect';
|
|
|
|
$menu_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnNjciCiAgIHNvZGlwb2RpOmRvY25hbWU9IndjcGF5X21lbnVfaWNvbi5zdmciCiAgIHdpZHRoPSI4NTIiCiAgIGhlaWdodD0iNjg0IgogICBpbmtzY2FwZTp2ZXJzaW9uPSIxLjEgKGM0ZThmOWUsIDIwMjEtMDUtMjQpIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM3MSIgLz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9Im5hbWVkdmlldzY5IgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGZpdC1tYXJnaW4tdG9wPSIwIgogICAgIGZpdC1tYXJnaW4tbGVmdD0iMCIKICAgICBmaXQtbWFyZ2luLXJpZ2h0PSIwIgogICAgIGZpdC1tYXJnaW4tYm90dG9tPSIwIgogICAgIGlua3NjYXBlOnpvb209IjI1NiIKICAgICBpbmtzY2FwZTpjeD0iLTg0Ljg1NzQyMiIKICAgICBpbmtzY2FwZTpjeT0iLTgzLjI5NDkyMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjEzMTIiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTA4MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMTE2IgogICAgIGlua3NjYXBlOndpbmRvdy15PSIyMDIiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmc2NyIgLz4KICA8cGF0aAogICAgIHRyYW5zZm9ybT0ic2NhbGUoLTEsIDEpIHRyYW5zbGF0ZSgtODUwLCAwKSIKICAgICBkPSJNIDc2OCw4NiBWIDU5OCBIIDg0IFYgODYgWiBtIDAsNTk4IGMgNDgsMCA4NCwtMzggODQsLTg2IFYgODYgQyA4NTIsMzggODE2LDAgNzY4LDAgSCA4NCBDIDM2LDAgMCwzOCAwLDg2IHYgNTEyIGMgMCw0OCAzNiw4NiA4NCw4NiB6IE0gMzg0LDEyOCB2IDQ0IGggLTg2IHYgODQgaCAxNzAgdiA0NCBIIDM0MCBjIC0yNCwwIC00MiwxOCAtNDIsNDIgdiAxMjggYyAwLDI0IDE4LDQyIDQyLDQyIGggNDQgdiA0NCBoIDg0IHYgLTQ0IGggODYgViA0MjggSCAzODQgdiAtNDQgaCAxMjggYyAyNCwwIDQyLC0xOCA0MiwtNDIgViAyMTQgYyAwLC0yNCAtMTgsLTQyIC00MiwtNDIgaCAtNDQgdiAtNDQgeiIKICAgICBmaWxsPSIjYTJhYWIyIgogICAgIGlkPSJwYXRoNjUiIC8+Cjwvc3ZnPgo=';
|
|
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments',
|
|
'title' => __( 'Payments', 'woocommerce-payments' ),
|
|
'capability' => 'manage_woocommerce',
|
|
'path' => $top_level_link,
|
|
'position' => '55.7', // After WooCommerce & Product menu items.
|
|
'icon' => $menu_icon,
|
|
'nav_args' => [
|
|
'title' => 'WooPayments',
|
|
'is_category' => $should_render_full_menu,
|
|
'menuId' => 'plugins',
|
|
'is_top_level' => true,
|
|
],
|
|
]
|
|
);
|
|
|
|
// Merchants are unable to see their deposits, transactions, disputes and settings if their account is rejected or under review.
|
|
// That's expected, because account under review is hard-blocked account that spends in a review pretty short time-frame.
|
|
// Either merchant gets approved and continues to use payments or they remain suspended and can't use payments.
|
|
if ( $this->account->is_account_rejected() || $this->account->is_account_under_review() ) {
|
|
// If the account is rejected, only show the overview page.
|
|
wc_admin_register_page( $this->admin_child_pages['wc-payments-overview'] );
|
|
return;
|
|
}
|
|
|
|
if ( ! $this->account->is_stripe_connected() ) {
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-onboarding',
|
|
'title' => __( 'Onboarding', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/onboarding',
|
|
'capability' => 'manage_woocommerce',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
],
|
|
]
|
|
);
|
|
remove_submenu_page( 'wc-admin&path=/payments/connect', 'wc-admin&path=/payments/onboarding' );
|
|
}
|
|
|
|
// We handle how we register this page slightly differently depending on if details are submitted or not.
|
|
if ( $this->account->is_stripe_connected() && ! $this->account->is_details_submitted() ) {
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-onboarding-kyc',
|
|
'title' => __( 'Continue onboarding', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/onboarding/kyc',
|
|
'capability' => 'manage_woocommerce',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 50,
|
|
],
|
|
]
|
|
);
|
|
remove_submenu_page( 'wc-admin&path=/payments/connect', 'wc-admin&path=/payments/onboarding/kyc' );
|
|
}
|
|
|
|
if ( $should_render_full_menu ) {
|
|
if ( $this->account->is_card_present_eligible() && $this->account->has_card_readers_available() ) {
|
|
$this->admin_child_pages['wc-payments-card-readers'] = [
|
|
'id' => 'wc-payments-card-readers',
|
|
'title' => __( 'Card Readers', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/card-readers',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 50,
|
|
],
|
|
];
|
|
}
|
|
|
|
if ( $this->account->get_capital()['has_previous_loans'] ) {
|
|
$this->admin_child_pages['wc-payments-capital'] = [
|
|
'id' => 'wc-payments-capital',
|
|
'title' => __( 'Capital Loans', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/loans',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 60,
|
|
],
|
|
];
|
|
}
|
|
|
|
if ( WC_Payments_Features::is_documents_section_enabled() ) {
|
|
$this->admin_child_pages['wc-payments-documents'] = [
|
|
'id' => 'wc-payments-documents',
|
|
'title' => __( 'Documents', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments',
|
|
'path' => '/payments/documents',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'order' => 50,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Please note that if any other page is registered first and it's
|
|
* path is different from the $top_level_link it will make
|
|
* wc_admin_register_page to duplicate "Payments" menu item as a
|
|
* first item in the sub-menu.
|
|
*/
|
|
foreach ( $this->admin_child_pages as $admin_child_page ) {
|
|
wc_admin_register_page( $admin_child_page );
|
|
}
|
|
|
|
// Remove the "Continue onboarding" submenu item, if it exists.
|
|
if ( in_array( 'wc-payments-onboarding-kyc', array_keys( $this->admin_child_pages ), true ) ) {
|
|
remove_submenu_page( 'wc-admin&path=/payments/overview', 'wc-admin&path=/payments/onboarding/kyc' );
|
|
}
|
|
|
|
wc_admin_connect_page(
|
|
[
|
|
'id' => 'woocommerce-settings-payments-woocommerce-payments',
|
|
'parent' => 'woocommerce-settings-payments',
|
|
'screen_id' => 'woocommerce_page_wc-settings-checkout-woocommerce_payments',
|
|
'title' => 'WooPayments',
|
|
'nav_args' => [
|
|
'parent' => 'wc-payments',
|
|
'title' => __( 'Settings', 'woocommerce-payments' ),
|
|
'url' => 'wc-settings&tab=checkout§ion=woocommerce_payments',
|
|
'order' => 99,
|
|
],
|
|
]
|
|
);
|
|
// Add the Settings submenu directly to the array, it's the only way to make it link to an absolute URL.
|
|
$submenu_keys = array_keys( $submenu );
|
|
$last_submenu_key = $submenu_keys[ count( $submenu ) - 1 ];
|
|
$submenu[ $last_submenu_key ][] = [ // PHPCS:Ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
|
$this->get_settings_menu_item_name(),
|
|
'manage_woocommerce',
|
|
WC_Payments_Admin_Settings::get_settings_url(),
|
|
];
|
|
|
|
// Temporary fix to settings menu disappearance is to register the page after settings menu has been manually added.
|
|
// TODO: More robust solution is to be implemented by https://github.com/Automattic/woocommerce-payments/issues/231.
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-deposit-details',
|
|
'title' => __( 'Payout details', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments-transactions', // Not (top level) deposits, as workaround for showing up as submenu page.
|
|
'path' => '/payments/payouts/details',
|
|
]
|
|
);
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-transaction-details',
|
|
'title' => __( 'Payment details', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments-transactions',
|
|
'path' => '/payments/transactions/details',
|
|
]
|
|
);
|
|
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-disputes-details-legacy-redirect',
|
|
'title' => __( 'Dispute details', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments-disputes',
|
|
'path' => '/payments/disputes/details',
|
|
]
|
|
);
|
|
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-disputes-challenge',
|
|
'title' => __( 'Challenge dispute', 'woocommerce-payments' ),
|
|
'parent' => 'wc-payments-disputes-details',
|
|
'path' => '/payments/disputes/challenge',
|
|
]
|
|
);
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-additional-payment-methods',
|
|
'parent' => 'woocommerce-settings-payments',
|
|
'title' => __( 'Add new payment methods', 'woocommerce-payments' ),
|
|
'path' => '/payments/additional-payment-methods',
|
|
]
|
|
);
|
|
wc_admin_register_page(
|
|
[
|
|
'id' => 'wc-payments-multi-currency-setup',
|
|
'parent' => 'woocommerce-settings-payments',
|
|
'title' => __( 'Set up multiple currencies', 'woocommerce-payments' ),
|
|
'path' => '/payments/multi-currency-setup',
|
|
]
|
|
);
|
|
}
|
|
|
|
WC_Payments_Utils::enqueue_style(
|
|
'wcpay-admin-css',
|
|
plugins_url( 'assets/css/admin.css', WCPAY_PLUGIN_FILE ),
|
|
[],
|
|
WC_Payments::get_file_version( 'assets/css/admin.css' ),
|
|
'all'
|
|
);
|
|
|
|
$this->add_menu_notification_badge();
|
|
$this->add_disputes_notification_badge();
|
|
if ( $this->wcpay_gateway->get_option( 'manual_capture' ) === 'yes' ) {
|
|
$this->add_transactions_notification_badge();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register the CSS and JS scripts
|
|
*/
|
|
public function register_payments_scripts() {
|
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
|
return;
|
|
}
|
|
|
|
WC_Payments::register_script_with_dependencies( 'WCPAY_DASH_APP', 'dist/index', [ 'wp-api-request' ] );
|
|
wp_add_inline_script(
|
|
'WCPAY_DASH_APP',
|
|
new Woo_Payments_Payment_Method_Definitions(),
|
|
'before'
|
|
);
|
|
|
|
wp_add_inline_script(
|
|
'WCPAY_DASH_APP',
|
|
new Woo_Payments_Payment_Methods_Config(),
|
|
'before'
|
|
);
|
|
|
|
wp_set_script_translations( 'WCPAY_DASH_APP', 'woocommerce-payments' );
|
|
|
|
WC_Payments_Utils::register_style(
|
|
'WCPAY_DASH_APP',
|
|
plugins_url( 'dist/index.css', WCPAY_PLUGIN_FILE ),
|
|
[ 'wc-components' ],
|
|
WC_Payments::get_file_version( 'dist/index.css' ),
|
|
'all'
|
|
);
|
|
|
|
WC_Payments::register_script_with_dependencies( 'WCPAY_TOS', 'dist/tos', [ 'wp-components' ] );
|
|
wp_set_script_translations( 'WCPAY_TOS', 'woocommerce-payments' );
|
|
|
|
WC_Payments_Utils::register_style(
|
|
'WCPAY_TOS',
|
|
plugins_url( 'dist/tos.css', WCPAY_PLUGIN_FILE ),
|
|
[],
|
|
WC_Payments::get_file_version( 'dist/tos.css' ),
|
|
'all'
|
|
);
|
|
|
|
WC_Payments::register_script_with_dependencies( 'WCPAY_ADMIN_ORDER_ACTIONS', 'dist/order', [ 'jquery-tiptip', 'wp-components' ] );
|
|
|
|
WC_Payments_Utils::register_style(
|
|
'WCPAY_ADMIN_ORDER_ACTIONS',
|
|
plugins_url( 'dist/order.css', WCPAY_PLUGIN_FILE ),
|
|
[],
|
|
WC_Payments::get_file_version( 'dist/order.css' ),
|
|
'all'
|
|
);
|
|
|
|
WC_Payments::register_script_with_dependencies( 'WCPAY_ADMIN_SETTINGS', 'dist/settings' );
|
|
wp_add_inline_script(
|
|
'WCPAY_ADMIN_SETTINGS',
|
|
new Woo_Payments_Payment_Method_Definitions(),
|
|
'before'
|
|
);
|
|
|
|
wp_localize_script(
|
|
'WCPAY_ADMIN_SETTINGS',
|
|
'wcpayExpressCheckoutParams',
|
|
[
|
|
'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() ),
|
|
],
|
|
]
|
|
);
|
|
|
|
wp_set_script_translations( 'WCPAY_ADMIN_SETTINGS', 'woocommerce-payments' );
|
|
|
|
WC_Payments_Utils::register_style(
|
|
'WCPAY_ADMIN_SETTINGS',
|
|
plugins_url( 'dist/settings.css', WCPAY_PLUGIN_FILE ),
|
|
[ 'wc-components' ],
|
|
WC_Payments::get_file_version( 'dist/settings.css' ),
|
|
'all'
|
|
);
|
|
|
|
WC_Payments::register_script_with_dependencies( 'WCPAY_PLUGINS_PAGE', 'dist/plugins-page', [ 'wp-api-request', 'wp-components' ] );
|
|
wp_set_script_translations( 'WCPAY_PLUGINS_PAGE', 'woocommerce-payments' );
|
|
|
|
WC_Payments_Utils::register_style(
|
|
'WCPAY_PLUGINS_PAGE',
|
|
plugins_url( 'dist/plugins-page.css', WCPAY_PLUGIN_FILE ),
|
|
[ 'wp-components', 'wc-components' ],
|
|
WC_Payments::get_file_version( 'dist/plugins-page.css' ),
|
|
'all'
|
|
);
|
|
|
|
WC_Payments::register_script_with_dependencies( 'WCPAY_WC_PAYMENTS_SETTINGS_SPOTLIGHT', 'dist/wc-payments-settings-spotlight' );
|
|
wp_set_script_translations( 'WCPAY_WC_PAYMENTS_SETTINGS_SPOTLIGHT', 'woocommerce-payments' );
|
|
|
|
WC_Payments_Utils::register_style(
|
|
'WCPAY_WC_PAYMENTS_SETTINGS_SPOTLIGHT',
|
|
plugins_url( 'dist/wc-payments-settings-spotlight.css', WCPAY_PLUGIN_FILE ),
|
|
[],
|
|
WC_Payments::get_file_version( 'dist/wc-payments-settings-spotlight.css' ),
|
|
'all'
|
|
);
|
|
|
|
WC_Payments::register_script_with_dependencies( 'WCPAY_REVIEW_PROMPT', 'dist/wc-payments-review-prompt' );
|
|
wp_set_script_translations( 'WCPAY_REVIEW_PROMPT', 'woocommerce-payments' );
|
|
|
|
WC_Payments_Utils::register_style(
|
|
'WCPAY_REVIEW_PROMPT',
|
|
plugins_url( 'dist/wc-payments-review-prompt.css', WCPAY_PLUGIN_FILE ),
|
|
[],
|
|
WC_Payments::get_file_version( 'dist/wc-payments-review-prompt.css' ),
|
|
'all'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Load the assets
|
|
*/
|
|
public function enqueue_payments_scripts() {
|
|
global $current_tab;
|
|
|
|
// Enqueue the admin settings assets on any WCPay settings page.
|
|
// We also need to enqueue and localize on the multi-currency tab.
|
|
if ( WC_Payments_Utils::is_payments_settings_page() || 'wcpay_multi_currency' === $current_tab ) {
|
|
// Localize before actually enqueuing to avoid unnecessary settings generation.
|
|
// Most importantly, the destructive error transient handling.
|
|
wp_localize_script(
|
|
'WCPAY_ADMIN_SETTINGS',
|
|
'wcpaySettings',
|
|
$this->get_js_settings()
|
|
);
|
|
|
|
// Output the settings JS and CSS only on the settings page.
|
|
wp_enqueue_script( 'WCPAY_ADMIN_SETTINGS' );
|
|
wp_enqueue_style( 'WCPAY_ADMIN_SETTINGS' );
|
|
}
|
|
|
|
// Enqueue the onboarding scripts if the user is on the onboarding page.
|
|
if ( WC_Payments_Utils::is_onboarding_page() ) {
|
|
wp_localize_script(
|
|
'WCPAY_ONBOARDING_SETTINGS',
|
|
'wcpayOnboardingSettings',
|
|
[]
|
|
);
|
|
}
|
|
|
|
// TODO: Try to enqueue the JS and CSS bundles lazily (will require changes on WC-Admin).
|
|
$current_screen = get_current_screen() ? get_current_screen()->base : null;
|
|
if ( wc_admin_is_registered_page() || 'widgets' === $current_screen ) {
|
|
// Localize before actually enqueuing to avoid unnecessary settings generation.
|
|
// Most importantly, the destructive error transient handling.
|
|
wp_localize_script(
|
|
'WCPAY_DASH_APP',
|
|
'wcpaySettings',
|
|
$this->get_js_settings()
|
|
);
|
|
|
|
wp_enqueue_script( 'WCPAY_DASH_APP' );
|
|
wp_enqueue_style( 'WCPAY_DASH_APP' );
|
|
}
|
|
|
|
// TODO: Update conditions when ToS script is enqueued.
|
|
$tos_agreement_declined = (
|
|
'checkout' === $current_tab
|
|
&& isset( $_GET['tos-disabled'] ) // phpcs:ignore WordPress.Security.NonceVerification
|
|
);
|
|
|
|
$tos_agreement_required = (
|
|
$this->is_tos_agreement_required() &&
|
|
(
|
|
WC_Payments_Utils::is_payments_settings_page() ||
|
|
|
|
// Or a WC Admin page?
|
|
// Note: Merchants can navigate from analytics to payments w/o reload,
|
|
// which is why this is necessary.
|
|
wc_admin_is_registered_page()
|
|
)
|
|
);
|
|
|
|
$track_stripe_connected = get_option( '_wcpay_onboarding_stripe_connected' );
|
|
|
|
if ( $tos_agreement_declined || $tos_agreement_required || $track_stripe_connected ) {
|
|
// phpcs:ignore WordPress.Security.NonceVerification
|
|
wp_localize_script(
|
|
'WCPAY_TOS',
|
|
'wcpay_tos_settings',
|
|
[
|
|
'settingsUrl' => WC_Payments_Admin_Settings::get_settings_url(),
|
|
'tosAgreementRequired' => $tos_agreement_required,
|
|
'tosAgreementDeclined' => $tos_agreement_declined,
|
|
'trackStripeConnected' => $track_stripe_connected,
|
|
]
|
|
);
|
|
|
|
wp_enqueue_script( 'WCPAY_TOS' );
|
|
wp_enqueue_style( 'WCPAY_TOS' );
|
|
}
|
|
|
|
$screen = get_current_screen();
|
|
|
|
// Only enqueue the scripts on the plugins page.
|
|
if ( in_array( $screen->id, [ 'plugins' ], true ) ) {
|
|
// Localize before actually enqueuing to avoid unnecessary settings generation.
|
|
// Most importantly, the destructive error transient handling.
|
|
wp_localize_script(
|
|
'WCPAY_PLUGINS_PAGE',
|
|
'wcpayPluginsSettings',
|
|
$this->get_plugins_page_js_settings()
|
|
);
|
|
|
|
wp_enqueue_script( 'WCPAY_PLUGINS_PAGE' );
|
|
wp_enqueue_style( 'WCPAY_PLUGINS_PAGE' );
|
|
|
|
add_action( 'admin_footer', [ $this, 'load_plugins_page_wrapper' ] );
|
|
}
|
|
|
|
if ( in_array( $screen->id, [ 'shop_order', 'woocommerce_page_wc-orders' ], true ) ) {
|
|
$order = wc_get_order();
|
|
|
|
if ( $order && strpos( $order->get_payment_method(), WC_Payment_Gateway_WCPay::GATEWAY_ID ) !== false ) {
|
|
$refund_amount = $order->get_remaining_refund_amount();
|
|
|
|
// Check if the order's test mode meta matches the site's current test mode state.
|
|
// E.g. order and site are both in test mode, or both in live mode.
|
|
$order_mode = $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY );
|
|
if ( '' === $order_mode ) {
|
|
// If the order doesn't have a mode set, assume it was created before the order mode meta was added (< 6.9 PR#7651) and return null.
|
|
$order_test_mode_match = null;
|
|
} else {
|
|
$order_test_mode_match = (
|
|
\WCPay\Constants\Order_Mode::PRODUCTION === $order_mode &&
|
|
WC_Payments::mode()->is_live()
|
|
) || (
|
|
\WCPay\Constants\Order_Mode::TEST === $order_mode &&
|
|
WC_Payments::mode()->is_test()
|
|
);
|
|
}
|
|
|
|
wp_localize_script(
|
|
'WCPAY_ADMIN_ORDER_ACTIONS',
|
|
'wcpay_order_config',
|
|
[
|
|
'disableManualRefunds' => ! $this->wcpay_gateway->has_refund_failed( $order ),
|
|
'manualRefundsTip' => __( 'Refunding manually requires reimbursing your customer offline via cash, check, etc. The refund amounts entered here will only be used to balance your analytics.', 'woocommerce-payments' ),
|
|
'refundAmount' => $refund_amount,
|
|
'formattedRefundAmount' => wp_strip_all_tags( wc_price( $refund_amount, [ 'currency' => $order->get_currency() ] ) ),
|
|
'refundedAmount' => $order->get_total_refunded(),
|
|
'canRefund' => $this->wcpay_gateway->can_refund_order( $order ),
|
|
'chargeId' => $this->order_service->get_charge_id_for_order( $order ),
|
|
'hasOpenAuthorization' => $this->order_service->has_open_authorization( $order ),
|
|
'testMode' => \WCPay\Constants\Order_Mode::TEST === $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY ),
|
|
'orderTestModeMatch' => $order_test_mode_match,
|
|
]
|
|
);
|
|
wp_localize_script(
|
|
'WCPAY_ADMIN_ORDER_ACTIONS',
|
|
'wcpaySettings',
|
|
$this->get_js_settings()
|
|
);
|
|
|
|
wp_enqueue_script( 'WCPAY_ADMIN_ORDER_ACTIONS' );
|
|
WC_Payments_Utils::enqueue_style( 'WCPAY_ADMIN_ORDER_ACTIONS' );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Outputs the wrapper for the plugin modal
|
|
* Contents are loaded by React script
|
|
*
|
|
* @return void
|
|
*/
|
|
public function load_plugins_page_wrapper() {
|
|
wc_get_template(
|
|
'plugins-page/plugins-page-wrapper.php',
|
|
[],
|
|
'',
|
|
WCPAY_ABSPATH . 'templates/'
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the WCPay settings to be sent to JS.
|
|
*
|
|
* It used an internal cache to make sure it only generates the settings once per request.
|
|
* This is needed in order to avoid performance issues and simplify error transients handling.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_js_settings(): array {
|
|
// Return the internally cached data if it is already initialized.
|
|
if ( ! is_null( $this->wcpay_js_settings ) ) {
|
|
return $this->wcpay_js_settings;
|
|
}
|
|
|
|
$error_message = get_transient( WC_Payments_Account::ERROR_MESSAGE_TRANSIENT );
|
|
delete_transient( WC_Payments_Account::ERROR_MESSAGE_TRANSIENT );
|
|
|
|
/**
|
|
* This is a workaround to pass the current user's email address to WCPay's settings until we do not need to rely
|
|
* on backwards compatibility and can use `getCurrentUser` from `@wordpress/core-data`.
|
|
*/
|
|
$current_user = wp_get_current_user();
|
|
$current_user_email = $current_user && $current_user->user_email ? $current_user->user_email : get_option( 'admin_email' );
|
|
|
|
if ( version_compare( WC_VERSION, '6.0', '<' ) ) {
|
|
$path = WCPAY_ABSPATH . 'i18n/locale-info.php';
|
|
} else {
|
|
$path = WC()->plugin_path() . '/i18n/locale-info.php';
|
|
}
|
|
|
|
$locale_info = include $path;
|
|
|
|
// Get symbols for those currencies without a short one.
|
|
$symbols = get_woocommerce_currency_symbols();
|
|
$currency_data = [];
|
|
|
|
foreach ( $locale_info as $key => $value ) {
|
|
$currency_code = $value['currency_code'] ?? '';
|
|
$default_locale_formatting = $value['locales']['default'] ?? [];
|
|
$currency_data[ $key ] = [
|
|
'code' => $currency_code,
|
|
'symbol' => $value['short_symbol'] ?? $symbols[ $currency_code ] ?? '',
|
|
'symbolPosition' => $value['currency_pos'] ?? '',
|
|
'thousandSeparator' => $value['thousand_sep'] ?? '',
|
|
'decimalSeparator' => $value['decimal_sep'] ?? '',
|
|
'precision' => $value['num_decimals'],
|
|
'defaultLocale' => [
|
|
'symbolPosition' => $default_locale_formatting['currency_pos'] ?? '',
|
|
'thousandSeparator' => $default_locale_formatting['thousand_sep'] ?? '',
|
|
'decimalSeparator' => $default_locale_formatting['decimal_sep'] ?? '',
|
|
],
|
|
];
|
|
}
|
|
|
|
$account_status_data = $this->account->get_account_status_data();
|
|
$account_is_valid = $this->account->is_stripe_account_valid();
|
|
|
|
$test_mode = false;
|
|
try {
|
|
$test_mode = WC_Payments::mode()->is_test();
|
|
} catch ( Exception $e ) {
|
|
Logger::log( sprintf( 'WooPayments JS settings: Could not determine if the gateway should process payments in test mode! Message: %s', $e->getMessage() ), 'warning' );
|
|
}
|
|
|
|
$test_mode_onboarding = false;
|
|
try {
|
|
$test_mode_onboarding = WC_Payments::mode()->is_test_mode_onboarding();
|
|
} catch ( Exception $e ) {
|
|
Logger::log( sprintf( 'WooPayments JS settings: Could not determine if we should onboard accounts in test mode! Message: %s', $e->getMessage() ), 'warning' );
|
|
}
|
|
|
|
$dev_mode = false;
|
|
try {
|
|
$dev_mode = WC_Payments::mode()->is_dev();
|
|
} catch ( Exception $e ) {
|
|
Logger::log( sprintf( 'WooPayments JS settings: Could not determine if the gateway should be in dev mode! Message: %s', $e->getMessage() ), 'warning' );
|
|
}
|
|
|
|
$connect_url = WC_Payments_Account::get_connect_url();
|
|
$connect_incentive = $this->incentives_service->get_connect_incentive();
|
|
// If we have an incentive ID, attach it to the connect URL.
|
|
if ( ! empty( $connect_incentive['id'] ) ) {
|
|
$connect_url = add_query_arg( [ 'promo' => sanitize_text_field( $connect_incentive['id'] ) ], $connect_url );
|
|
}
|
|
|
|
// Get the site logo URL, if available.
|
|
$site_logo_id = get_theme_mod( 'custom_logo' );
|
|
$site_logo_url = $site_logo_id ? ( wp_get_attachment_image_src( $site_logo_id, 'full' )[0] ?? '' ) : '';
|
|
|
|
$this->wcpay_js_settings = [
|
|
'version' => WCPAY_VERSION_NUMBER,
|
|
'connectUrl' => $connect_url,
|
|
'overviewUrl' => WC_Payments_Account::get_overview_page_url(),
|
|
'connect' => [
|
|
'country' => WC()->countries->get_base_country(),
|
|
'availableCountries' => WC_Payments_Utils::supported_countries(),
|
|
'availableStates' => WC()->countries->get_states(),
|
|
],
|
|
'connectIncentive' => $connect_incentive,
|
|
'devMode' => $dev_mode,
|
|
'testModeOnboarding' => $test_mode_onboarding,
|
|
'testMode' => $test_mode,
|
|
// Set this flag for use in the front-end to alter messages and notices if on-boarding has been disabled.
|
|
'onBoardingDisabled' => WC_Payments_Account::is_on_boarding_disabled(),
|
|
'onboardingFieldsData' => $account_is_valid ? null : $this->onboarding_service->get_fields_data( get_user_locale() ),
|
|
'onboardingEmbeddedKycInProgress' => $this->onboarding_service->is_embedded_kyc_in_progress(),
|
|
'errorMessage' => $error_message,
|
|
'featureFlags' => $this->get_frontend_feature_flags(),
|
|
'isSubscriptionsActive' => class_exists( 'WC_Subscriptions' ) && version_compare( WC_Subscriptions::$version, '2.2.0', '>=' ),
|
|
// Used in the settings page by the AccountFees component.
|
|
'zeroDecimalCurrencies' => WC_Payments_Utils::zero_decimal_currencies(),
|
|
'fraudServices' => $this->fraud_service->get_fraud_services_config(),
|
|
'isJetpackConnected' => $this->account->has_working_jetpack_connection(),
|
|
'isJetpackIdcActive' => Jetpack_Identity_Crisis::has_identity_crisis(),
|
|
'isAccountConnected' => $this->account->has_account_data(),
|
|
'isAccountValid' => $account_is_valid,
|
|
'accountStatus' => $account_status_data,
|
|
'accountFees' => $this->account->get_fees(),
|
|
'accountLoans' => $this->account->get_capital(),
|
|
'accountEmail' => $this->account->get_account_email(),
|
|
'accountDetails' => $this->account->get_account_details(),
|
|
'showUpdateDetailsTask' => $this->get_should_show_update_business_details_task( $account_status_data ),
|
|
'wpcomReconnectUrl' => $this->payments_api_client->is_server_connected() && ! $this->payments_api_client->has_server_connection_owner() ? WC_Payments_Account::get_wpcom_reconnect_url() : null,
|
|
'multiCurrencySetup' => [
|
|
'isSetupCompleted' => filter_var( get_option( 'wcpay_multi_currency_setup_completed' ), FILTER_VALIDATE_BOOLEAN ) ? 'yes' : 'no',
|
|
],
|
|
'isMultiCurrencyEnabled' => WC_Payments_Features::is_customer_multi_currency_enabled(),
|
|
'shouldUseExplicitPrice' => WC_Payments_Explicit_Price_Formatter::should_output_explicit_price(),
|
|
'overviewTasksVisibility' => [
|
|
'dismissedTodoTasks' => get_option( 'woocommerce_dismissed_todo_tasks', [] ),
|
|
'deletedTodoTasks' => get_option( 'woocommerce_deleted_todo_tasks', [] ),
|
|
'remindMeLaterTodoTasks' => get_option( 'woocommerce_remind_me_later_todo_tasks', [] ),
|
|
],
|
|
'currentUserEmail' => $current_user_email,
|
|
'currencyData' => $currency_data,
|
|
'restUrl' => get_rest_url( null, '' ), // rest url to concatenate when merchant use Plain permalinks.
|
|
'siteLogoUrl' => $site_logo_url,
|
|
'fraudProtection' => [
|
|
'isWelcomeTourDismissed' => WC_Payments_Features::is_fraud_protection_welcome_tour_dismissed(),
|
|
],
|
|
'accountDefaultCurrency' => $this->account->get_account_default_currency(),
|
|
'storeCurrency' => get_option( 'woocommerce_currency' ),
|
|
'isWooPayStoreCountryAvailable' => WooPay_Utilities::is_store_country_available(),
|
|
'woopayLastDisableDate' => $this->wcpay_gateway->get_option( 'platform_checkout_last_disable_date' ),
|
|
'isStripeBillingEnabled' => WC_Payments_Features::is_stripe_billing_enabled(),
|
|
'isStripeBillingEligible' => WC_Payments_Features::is_stripe_billing_eligible(),
|
|
'storeName' => get_bloginfo( 'name' ),
|
|
'isNextDepositNoticeDismissed' => WC_Payments_Features::is_next_deposit_notice_dismissed(),
|
|
'isInstantDepositNoticeDismissed' => get_option( 'wcpay_instant_deposit_notice_dismissed', false ),
|
|
'instantDepositsPreviouslyEligible' => get_option( 'wcpay_instant_deposits_previously_eligible', false ),
|
|
'dismissedDuplicateNotices' => get_option( 'wcpay_duplicate_payment_method_notices_dismissed', [] ),
|
|
'isConnectionSuccessModalDismissed' => get_option( WC_Payments_Onboarding_Service::ONBOARDING_CONNECTION_SUCCESS_MODAL_OPTION, false ),
|
|
'isOverviewSurveySubmitted' => get_option( 'wcpay_survey_payment_overview_submitted', false ),
|
|
'trackingInfo' => $this->account->get_tracking_info(),
|
|
'lifetimeTPV' => $this->account->get_lifetime_total_payment_volume(),
|
|
'defaultExpressCheckoutBorderRadius' => WC_Payments_Express_Checkout_Button_Handler::DEFAULT_BORDER_RADIUS_IN_PX,
|
|
'isWooPayGlobalThemeSupportEligible' => WC_Payments_Features::is_woopay_global_theme_support_eligible(),
|
|
'woopayAppearance' => WC_Payments_Styles_Cache::get_woopay_appearance(),
|
|
'woopayFontRules' => WC_Payments_Styles_Cache::get_woopay_font_rules(),
|
|
'dateFormat' => wc_date_format(),
|
|
'timeFormat' => get_option( 'time_format' ),
|
|
'formattedStoreAddress' => WC()->countries->get_formatted_address(
|
|
[
|
|
'address_1' => get_option( 'woocommerce_store_address', '' ),
|
|
'address_2' => get_option( 'woocommerce_store_address_2', '' ),
|
|
'city' => get_option( 'woocommerce_store_city', '' ),
|
|
'state' => WC()->countries->get_base_state(),
|
|
'postcode' => get_option( 'woocommerce_store_postcode', '' ),
|
|
'country' => WC()->countries->get_base_country(),
|
|
],
|
|
', '
|
|
),
|
|
];
|
|
|
|
/**
|
|
* Filter the WCPay JS settings.
|
|
*
|
|
* @since 6.1.0
|
|
*/
|
|
return apply_filters( 'wcpay_js_settings', $this->wcpay_js_settings );
|
|
}
|
|
|
|
/**
|
|
* Get the WCPay plugins page settings to be sent to JS.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function get_plugins_page_js_settings(): array {
|
|
$plugins_page_settings = [
|
|
'exitSurveyLastShown' => get_option( 'wcpay_exit_survey_last_shown', null ),
|
|
];
|
|
|
|
/**
|
|
* Filter the plugins page settings.
|
|
*
|
|
* @since 7.8.0
|
|
*/
|
|
return apply_filters( 'wcpay_plugins_page_js_settings', $plugins_page_settings );
|
|
}
|
|
|
|
/**
|
|
* Creates an array of features enabled only when external dependencies are of certain versions.
|
|
*
|
|
* @return array An associative array containing the flags as booleans.
|
|
*/
|
|
private function get_frontend_feature_flags(): array {
|
|
return array_merge(
|
|
[
|
|
'paymentTimeline' => self::version_compare( WC_ADMIN_VERSION_NUMBER, '1.4.0', '>=' ),
|
|
'customSearch' => self::version_compare( WC_ADMIN_VERSION_NUMBER, '1.3.0', '>=' ),
|
|
],
|
|
WC_Payments_Features::to_array()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* A wrapper around version_compare to allow comparing two version numbers even when they are suffixed with a dash and a string, for example 1.3.0-beta.
|
|
*
|
|
* @param string $version1 First version number.
|
|
* @param string $version2 Second version number.
|
|
* @param string $operator A boolean operator to use when comparing.
|
|
*
|
|
* @return bool True if the relationship is the one specified by the operator.
|
|
*/
|
|
private static function version_compare( $version1, $version2, string $operator ): bool {
|
|
// Attempt to extract version numbers.
|
|
$version_regex = '/^([\d\.]+)(-.*)?$/';
|
|
if ( preg_match( $version_regex, $version1, $matches1 ) && preg_match( $version_regex, $version2, $matches2 ) ) {
|
|
// Only compare the numeric parts of the versions, ignore the bit after the dash.
|
|
$version1 = $matches1[1];
|
|
$version2 = $matches2[1];
|
|
}
|
|
return (bool) version_compare( $version1, $version2, $operator );
|
|
}
|
|
|
|
/**
|
|
* Checks whether it's necessary to display a ToS agreement modal.
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function is_tos_agreement_required() {
|
|
// The gateway might already be disabled because of ToS.
|
|
if ( ! $this->wcpay_gateway->is_enabled() ) {
|
|
return false;
|
|
}
|
|
|
|
// Retrieve the latest agreement and check whether it's regarding the latest ToS version.
|
|
$agreement = $this->account->get_latest_tos_agreement();
|
|
if ( empty( $agreement ) ) {
|
|
// Account data couldn't be fetched, let the merchant solve that first.
|
|
return false;
|
|
}
|
|
|
|
return ! $agreement['is_current_version'];
|
|
}
|
|
|
|
/**
|
|
* Attempts to add a notification badge on WordPress menu next to Payments menu item
|
|
* to remind user that setup is required.
|
|
*/
|
|
public function add_menu_notification_badge() {
|
|
global $menu;
|
|
|
|
// If plugin activation date is less than 3 days, do not show the badge.
|
|
$past_3_days = time() - get_option( 'wcpay_activation_timestamp', 0 ) >= ( 3 * DAY_IN_SECONDS );
|
|
if ( false === $past_3_days ) {
|
|
return;
|
|
}
|
|
|
|
// First, lets see what the DB option says.
|
|
$hide_badge = 'yes' === get_option( 'wcpay_menu_badge_hidden', 'no' );
|
|
|
|
// There are situations where we need to force show the badge.
|
|
// If we have:
|
|
// - a broken Jetpack connection and a connected account;
|
|
// - or working Jetpack connection and a connected but invalid account.
|
|
// show the badge since the merchant needs to take action.
|
|
if ( ( ! $this->account->has_working_jetpack_connection() && $this->account->has_account_data() )
|
|
|| ( $this->account->has_working_jetpack_connection() && $this->account->has_account_data() && ! $this->account->is_stripe_account_valid() ) ) {
|
|
|
|
$hide_badge = false;
|
|
} elseif ( $this->account->has_working_jetpack_connection() && $this->account->is_stripe_account_valid() ) {
|
|
// If everything is working fine, hide the badge regardless of the DB option.
|
|
$hide_badge = true;
|
|
}
|
|
|
|
if ( $hide_badge ) {
|
|
return;
|
|
}
|
|
|
|
$badge = self::MENU_NOTIFICATION_BADGE;
|
|
foreach ( $menu as $index => $menu_item ) {
|
|
if ( false === strpos( $menu_item[0], $badge ) && ( 'wc-admin&path=/payments/connect' === $menu_item[2] ) ) {
|
|
$menu[ $index ][0] .= $badge; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
|
|
|
// One menu item with a badge is more than enough.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check whether a setup task needs to be displayed prompting the user to update
|
|
* their business details.
|
|
*
|
|
* @param array $account_status_data An array containing the account status data.
|
|
*
|
|
* @return bool True if we should show the task, false otherwise.
|
|
*/
|
|
public function get_should_show_update_business_details_task( array $account_status_data ) {
|
|
$status = $account_status_data['status'] ?? '';
|
|
$current_deadline = $account_status_data['currentDeadline'] ?? false;
|
|
$past_due = $account_status_data['pastDue'] ?? false;
|
|
|
|
// If the account is restricted_soon, but there's no current deadline, no action is needed.
|
|
if ( ( 'restricted_soon' === $status && $current_deadline ) || ( 'restricted' === $status && $past_due ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the name to display for the "Payments > Settings" submenu item.
|
|
*
|
|
* The name will also contain a notification badge if the UPE settings preview is enabled but UPE is not.
|
|
*
|
|
* @return string
|
|
*/
|
|
private function get_settings_menu_item_name() {
|
|
return __( 'Settings', 'woocommerce' ); // PHPCS:Ignore WordPress.WP.I18n.TextDomainMismatch
|
|
}
|
|
|
|
/**
|
|
* Redirects WCPay admin pages to the Connect page for stores that
|
|
* don't have a working Jetpack connection or a valid connected Stripe account.
|
|
*
|
|
* Please note that the overview page is handled separately in the
|
|
* `WC_Payments_Account::maybe_redirect_from_overview_page` method, before this method is called (priority 15 vs 16).
|
|
*
|
|
* IMPORTANT: The logic should be kept in sync with the one in maybe_redirect_from_connect_page to avoid loops.
|
|
*
|
|
* @see WC_Payments_Account::maybe_redirect_from_overview_page() for overview page handling.
|
|
* @see WC_Payments_Account::maybe_handle_onboarding() for connect links handling.
|
|
*
|
|
* @return bool True if a redirection happened, false otherwise.
|
|
*/
|
|
public function maybe_redirect_from_payments_admin_child_pages(): bool {
|
|
if ( wp_doing_ajax() || ! current_user_can( 'manage_woocommerce' ) ) {
|
|
return false;
|
|
}
|
|
|
|
$url_params = wp_unslash( $_GET ); // phpcs:ignore WordPress.Security.NonceVerification
|
|
if ( empty( $url_params['page'] ) || 'wc-admin' !== $url_params['page'] ) {
|
|
return false;
|
|
}
|
|
|
|
$current_path = ! empty( $url_params['path'] ) ? $url_params['path'] : '';
|
|
if ( empty( $current_path ) ) {
|
|
return false;
|
|
}
|
|
|
|
// If the current path doesn't match any of the paths we're interested in, do not redirect.
|
|
$page_paths = [];
|
|
foreach ( $this->admin_child_pages as $payments_child_page ) {
|
|
$page_paths[] = preg_quote( $payments_child_page['path'], '/' );
|
|
}
|
|
if ( ! preg_match( '/^(' . implode( '|', $page_paths ) . ')/', $current_path ) ) {
|
|
return false;
|
|
}
|
|
|
|
// If everything is NOT in good working condition, redirect to Payments Connect page.
|
|
if ( ! $this->account->has_working_jetpack_connection() || ! $this->account->is_stripe_account_valid() ) {
|
|
$this->account->redirect_to_onboarding_welcome_page(
|
|
sprintf(
|
|
/* translators: 1: WooPayments. */
|
|
__( 'Please <b>complete your %1$s setup</b> to continue using it.', 'woocommerce-payments' ),
|
|
'WooPayments'
|
|
)
|
|
);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Add woopay as a payment method to the edit order on admin.
|
|
*
|
|
* @param int $order_id order_id.
|
|
*/
|
|
public function show_woopay_payment_method_name_admin( $order_id ) {
|
|
$order = wc_get_order( $order_id );
|
|
if ( ! $order || ! $order->get_meta( 'is_woopay' ) ) {
|
|
return;
|
|
}
|
|
?>
|
|
<div class="wc-payment-gateway-method-name-woopay-wrapper">
|
|
<?php echo esc_html_e( 'Paid with', 'woocommerce-payments' ) . ' '; ?>
|
|
<img alt="WooPay" src="<?php echo esc_url_raw( plugins_url( 'assets/images/payment-methods/woo-short.svg', WCPAY_PLUGIN_FILE ) ); ?>">
|
|
<?php
|
|
if ( $order->get_meta( 'last4' ) ) {
|
|
echo esc_html_e( 'Card ending in', 'woocommerce-payments' ) . ' ';
|
|
echo esc_html( $order->get_meta( 'last4' ) );
|
|
}
|
|
?>
|
|
</div>
|
|
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Display the _wcpay_transaction_fee from order metadata to the Order Edit screen on admin.
|
|
*
|
|
* @param int $order_id order_id.
|
|
*/
|
|
public function display_wcpay_transaction_fee( $order_id ) {
|
|
$order = wc_get_order( $order_id );
|
|
if ( ! $order || Intent_Status::REQUIRES_CAPTURE === $order->get_meta( WC_Payments_Order_Service::INTENTION_STATUS_META_KEY ) ) {
|
|
return;
|
|
}
|
|
|
|
$transaction_fee = $order->get_meta( '_wcpay_transaction_fee' );
|
|
|
|
if ( ! $transaction_fee ) {
|
|
return;
|
|
}
|
|
|
|
?>
|
|
<tr>
|
|
<td class="label wcpay-transaction-fee">
|
|
<?php
|
|
// phpcs:ignore WordPress.Security.EscapeOutput
|
|
echo wc_help_tip(
|
|
sprintf(
|
|
/* translators: %s: WooPayments */
|
|
__( 'This represents the fee %s collects for the transaction.', 'woocommerce-payments' ),
|
|
'WooPayments'
|
|
)
|
|
);
|
|
?>
|
|
<?php esc_html_e( 'Transaction Fee:', 'woocommerce-payments' ); ?>
|
|
</td>
|
|
<td width="1%"></td>
|
|
<td class="total">
|
|
-<?php echo wp_kses( wc_price( $transaction_fee, [ 'currency' => $order->get_currency() ] ), 'post' ); ?>
|
|
</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Adds a notification badge to the Payments > Disputes admin menu item to
|
|
* indicate the number of disputes that need a response.
|
|
*/
|
|
public function add_disputes_notification_badge() {
|
|
global $submenu;
|
|
|
|
if ( ! isset( $submenu[ self::PAYMENTS_SUBMENU_SLUG ] ) ) {
|
|
return;
|
|
}
|
|
|
|
$disputes_needing_response = $this->get_disputes_awaiting_response_count();
|
|
|
|
if ( $disputes_needing_response <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
foreach ( $submenu[ self::PAYMENTS_SUBMENU_SLUG ] as $index => $menu_item ) {
|
|
if ( 'wc-admin&path=/payments/disputes' === $menu_item[2] ) {
|
|
// Direct the user to the disputes which need a response by default.
|
|
$submenu[ self::PAYMENTS_SUBMENU_SLUG ][ $index ][2] = admin_url( add_query_arg( [ 'filter' => 'awaiting_response' ], 'admin.php?page=' . $menu_item[2] ) ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
|
|
|
// Append the dispute notification badge to indicate the number of disputes needing a response.
|
|
$submenu[ self::PAYMENTS_SUBMENU_SLUG ][ $index ][0] .= sprintf( self::UNRESOLVED_NOTIFICATION_BADGE_FORMAT, esc_html( $disputes_needing_response ) ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a notification badge to the Payments > Transactions admin menu item to
|
|
* indicate the number of transactions that need to be captured.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function add_transactions_notification_badge() {
|
|
global $submenu;
|
|
|
|
if ( ! isset( $submenu[ self::PAYMENTS_SUBMENU_SLUG ] ) ) {
|
|
return;
|
|
}
|
|
|
|
$uncaptured_transactions = $this->get_uncaptured_transactions_count();
|
|
if ( $uncaptured_transactions <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
foreach ( $submenu[ self::PAYMENTS_SUBMENU_SLUG ] as $index => $menu_item ) {
|
|
if ( 'wc-admin&path=/payments/transactions' === $menu_item[2] ) {
|
|
$submenu[ self::PAYMENTS_SUBMENU_SLUG ][ $index ][0] .= sprintf( self::UNRESOLVED_NOTIFICATION_BADGE_FORMAT, esc_html( $uncaptured_transactions ) ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add new custom css classes.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function add_css_classes() {
|
|
global $current_tab;
|
|
|
|
if ( 'checkout' === $current_tab ) {
|
|
add_filter(
|
|
'admin_body_class',
|
|
static function ( $classes ) {
|
|
return "$classes woocommerce-payments-checkout-section";
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the number of disputes which need a response. ie have a 'needs_response' or 'warning_needs_response' status.
|
|
* Used to display a notification badge on the Payments > Disputes menu item.
|
|
*
|
|
* @return int The number of disputes which need a response.
|
|
*/
|
|
private function get_disputes_awaiting_response_count() {
|
|
$test_mode = WC_Payments::mode()->is_test();
|
|
$cache_key = $test_mode ? Database_Cache::DISPUTE_STATUS_COUNTS_KEY_TEST_MODE : Database_Cache::DISPUTE_STATUS_COUNTS_KEY;
|
|
|
|
$send_callback = function () {
|
|
$request = Request::get( WC_Payments_API_Client::DISPUTES_API . '/status_counts' );
|
|
$request->assign_hook( 'wcpay_get_dispute_status_counts' );
|
|
return $request->send();
|
|
};
|
|
|
|
$disputes_status_counts = $this->database_cache->get_or_add(
|
|
$cache_key,
|
|
$send_callback,
|
|
// We'll consider all array values to be valid as the cache is only invalidated when it is deleted or it expires.
|
|
'is_array'
|
|
);
|
|
|
|
if ( empty( $disputes_status_counts ) ) {
|
|
return 0;
|
|
}
|
|
|
|
$needs_response_statuses = [ 'needs_response', 'warning_needs_response' ];
|
|
return (int) array_sum( array_intersect_key( $disputes_status_counts, array_flip( $needs_response_statuses ) ) );
|
|
}
|
|
|
|
/**
|
|
* Gets the number of uncaptured transactions, that is authorizations that need to be captured within 7 days.
|
|
*
|
|
* @return int The number of uncaptured transactions.
|
|
*/
|
|
private function get_uncaptured_transactions_count() {
|
|
$test_mode = WC_Payments::mode()->is_test();
|
|
$cache_key = $test_mode ? DATABASE_CACHE::AUTHORIZATION_SUMMARY_KEY_TEST_MODE : DATABASE_CACHE::AUTHORIZATION_SUMMARY_KEY;
|
|
|
|
$send_callback = function () {
|
|
$request = Request::get( WC_Payments_API_Client::AUTHORIZATIONS_API . '/summary' );
|
|
$request->assign_hook( 'wc_pay_get_authorizations_summary' );
|
|
return $request->send();
|
|
};
|
|
$authorization_summary = $this->database_cache->get_or_add(
|
|
$cache_key,
|
|
$send_callback,
|
|
// We'll consider all array values to be valid as the cache is only invalidated when it is deleted or it expires.
|
|
'is_array'
|
|
);
|
|
|
|
if ( empty( $authorization_summary ) ) {
|
|
return 0;
|
|
}
|
|
|
|
return $authorization_summary['count'];
|
|
}
|
|
|
|
/**
|
|
* Enqueue the spotlight promotion script on WooCommerce Payments Settings page.
|
|
* Only runs on WooCommerce 9.9.2+ (when the new WooCommerce Payments Settings UI was enabled for all stores).
|
|
*/
|
|
public function enqueue_wc_payment_settings_spotlight() {
|
|
// Check for minimum WooCommerce version 9.9.2.
|
|
if ( ! Constants::is_defined( 'WC_VERSION' ) || version_compare( Constants::get_constant( 'WC_VERSION' ), '9.9.2', '<' ) ) {
|
|
return;
|
|
}
|
|
|
|
// Only enqueue on the WooCommerce Payments Settings page.
|
|
if ( ! $this->is_wc_admin_payments_settings_page() ) {
|
|
return;
|
|
}
|
|
|
|
// Only enqueue if there are visible spotlight promotions.
|
|
$promotions = $this->pm_promotions_service->get_visible_promotions();
|
|
if ( empty( $promotions ) ) {
|
|
return;
|
|
}
|
|
|
|
$has_spotlight = false;
|
|
foreach ( $promotions as $promotion ) {
|
|
if ( isset( $promotion['type'] ) && 'spotlight' === $promotion['type'] ) {
|
|
$has_spotlight = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ! $has_spotlight ) {
|
|
return;
|
|
}
|
|
|
|
wp_enqueue_script( 'WCPAY_WC_PAYMENTS_SETTINGS_SPOTLIGHT' );
|
|
wp_enqueue_style( 'WCPAY_WC_PAYMENTS_SETTINGS_SPOTLIGHT' );
|
|
}
|
|
|
|
/**
|
|
* Inject the container div for the spotlight promotion on WooCommerce payment settings page.
|
|
* Only runs on WooCommerce 9.9.2+ (when the new WooCommerce Payments Settings UI was enabled for all stores).
|
|
*/
|
|
public function inject_payment_settings_spotlight_container() {
|
|
// Check for minimum WooCommerce version 9.9.2.
|
|
if ( ! Constants::is_defined( 'WC_VERSION' ) || version_compare( Constants::get_constant( 'WC_VERSION' ), '9.9.2', '<' ) ) {
|
|
return;
|
|
}
|
|
|
|
// Only inject on the WooCommerce Payments settings page.
|
|
if ( ! $this->is_wc_admin_payments_settings_page() ) {
|
|
return;
|
|
}
|
|
|
|
echo '<div id="wcpay-payments-settings-spotlight"></div>';
|
|
}
|
|
|
|
/**
|
|
* Check if we're on the WooCommerce Payments Settings page (general payments tab, no specific section).
|
|
*
|
|
* @return bool True if on the WC payment settings page.
|
|
*/
|
|
private function is_wc_admin_payments_settings_page(): bool {
|
|
// phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
|
return isset( $_REQUEST['page'] ) && 'wc-settings' === wp_unslash( $_REQUEST['page'] ) &&
|
|
isset( $_REQUEST['tab'] ) && 'checkout' === wp_unslash( $_REQUEST['tab'] ) &&
|
|
! isset( $_REQUEST['section'] )
|
|
&& is_admin();
|
|
// phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
|
}
|
|
|
|
/**
|
|
* Check if the review prompt should be shown based on eligibility and user state.
|
|
*
|
|
* @return bool True if the prompt should be shown, false otherwise.
|
|
*/
|
|
public function should_show_review_prompt() {
|
|
// Only show on top-level Payments Settings page.
|
|
if ( ! $this->is_wc_admin_payments_settings_page() ) {
|
|
return false;
|
|
}
|
|
|
|
// Check account eligibility.
|
|
if ( ! $this->account->is_review_prompt_eligible() ) {
|
|
return false;
|
|
}
|
|
|
|
// Check user dismissal/cooldown state.
|
|
$user_id = get_current_user_id();
|
|
$dismissed = (int) get_user_meta( $user_id, 'woocommerce_admin_wc_payments_review_prompt_dismissed', true );
|
|
$maybe_later = (int) get_user_meta( $user_id, 'woocommerce_admin_wc_payments_review_prompt_maybe_later', true );
|
|
|
|
// If dismissed permanently, don't show.
|
|
if ( $dismissed > 0 ) {
|
|
return false;
|
|
}
|
|
|
|
// If cooldown is active (within 10 days), don't show.
|
|
if ( $maybe_later > 0 ) {
|
|
$cooldown_seconds = 10 * DAY_IN_SECONDS;
|
|
$now = time();
|
|
if ( $now < ( $maybe_later + $cooldown_seconds ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Enqueue the review prompt script on top-level Payments Settings page.
|
|
*/
|
|
public function enqueue_wc_payments_review_prompt() {
|
|
if ( ! $this->should_show_review_prompt() ) {
|
|
return;
|
|
}
|
|
|
|
add_action( 'admin_footer', [ $this, 'inject_review_prompt_container' ] );
|
|
|
|
wp_localize_script(
|
|
'WCPAY_REVIEW_PROMPT',
|
|
'wcpayReviewPromptSettings',
|
|
[
|
|
'isLive' => WC_Payments::mode()->is_live(),
|
|
'version' => WCPAY_VERSION_NUMBER,
|
|
]
|
|
);
|
|
|
|
wp_enqueue_script( 'WCPAY_REVIEW_PROMPT' );
|
|
wp_enqueue_style( 'WCPAY_REVIEW_PROMPT' );
|
|
}
|
|
|
|
/**
|
|
* Inject the container div for the review prompt on top-level Payments settings page.
|
|
*/
|
|
public function inject_review_prompt_container() {
|
|
echo '<div id="wcpay-review-prompt"></div>';
|
|
}
|
|
}
|