mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2026-07-30 02:17:46 +08:00
Some checks failed
CI / coding-standards-analysis-php (push) Waiting to run
CI / static-code-analysis-php (push) Waiting to run
CI / tests-unit-php (7.4) (push) Waiting to run
CI / tests-unit-php (8.0) (push) Waiting to run
CI / tests-unit-php (8.1) (push) Waiting to run
CI / tests-unit-php (8.2) (push) Waiting to run
CI / tests-unit-php (8.3) (push) Waiting to run
CI / tests-unit-php (8.4) (push) Waiting to run
PR Playground Demo / prepare_version (push) Has been skipped
PR Playground Demo / build_plugin (push) Has been skipped
PR Playground Demo / create_archive (push) Has been skipped
PR Playground Demo / Comment on PR with Playground details (push) Has been skipped
Build and distribute / build-and-distribute (push) Has been cancelled
Replace Psalm with PHPstan
360 lines
8.6 KiB
PHP
360 lines
8.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|
use WooCommerce\PayPalCommerce\PayPalSubscriptions\SubscriptionStatus;
|
|
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
|
|
|
class Context {
|
|
|
|
protected SessionHandler $session_handler;
|
|
protected SubscriptionStatus $subscription_status;
|
|
|
|
public function __construct(
|
|
SessionHandler $session_handler,
|
|
SubscriptionStatus $subscription_status
|
|
) {
|
|
|
|
$this->session_handler = $session_handler;
|
|
$this->subscription_status = $subscription_status;
|
|
}
|
|
|
|
/**
|
|
* Initializes context preconditions like is_cart() and is_checkout().
|
|
*
|
|
* @return void
|
|
*/
|
|
public function init_context(): void {
|
|
if ( ! apply_filters( 'woocommerce_paypal_payments_block_classic_compat', true ) ) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Activate is_checkout() on woocommerce/classic-shortcode checkout blocks.
|
|
*
|
|
* @psalm-suppress MissingClosureParamType
|
|
*/
|
|
add_filter(
|
|
'woocommerce_is_checkout',
|
|
function ( $is_checkout ) {
|
|
if ( $is_checkout ) {
|
|
return $is_checkout;
|
|
}
|
|
|
|
if ( has_block( 'woocommerce/classic-shortcode' ) ) {
|
|
$classic_block = $this->find_classic_shortcode_block();
|
|
$type = $classic_block['attrs']['shortcode'] ?? '';
|
|
return $type === 'checkout';
|
|
}
|
|
|
|
return $is_checkout;
|
|
}
|
|
);
|
|
|
|
// Activate is_cart() on woocommerce/classic-shortcode cart blocks.
|
|
if ( ! is_cart() && is_callable( 'wc_maybe_define_constant' ) ) { // @phpstan-ignore function.alreadyNarrowedType
|
|
if ( has_block( 'woocommerce/classic-shortcode' ) ) {
|
|
$classic_block = $this->find_classic_shortcode_block();
|
|
$type = $classic_block['attrs']['shortcode'] ?? '';
|
|
if ( $type !== 'checkout' ) { // There is no 'cart' type, the attribute is just missing.
|
|
wc_maybe_define_constant( 'WOOCOMMERCE_CART', true );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the parsed data of the classic shortcode block, or null if missing on the current page.
|
|
* Slower than has_block( 'woocommerce/classic-shortcode' )
|
|
*
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
protected function find_classic_shortcode_block(): ?array {
|
|
$post = get_post();
|
|
if ( ! $post || empty( $post->post_content ) ) {
|
|
return null;
|
|
}
|
|
|
|
$blocks = parse_blocks( $post->post_content );
|
|
foreach ( $blocks as $block ) {
|
|
if ( $block['blockName'] === 'woocommerce/classic-shortcode' ) {
|
|
return $block;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Checks WC is_checkout() + WC checkout ajax requests.
|
|
*/
|
|
public function is_checkout(): bool {
|
|
if ( is_checkout() ) {
|
|
return true;
|
|
}
|
|
|
|
if ( $this->is_checkout_ajax() ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if performing the WC checkout ajax requests.
|
|
*/
|
|
private function is_checkout_ajax(): bool {
|
|
/**
|
|
* The filter returning whether to detect WC checkout ajax requests.
|
|
*/
|
|
if ( ! apply_filters( 'ppcp_check_ajax_checkout', true ) ) {
|
|
return false;
|
|
}
|
|
|
|
$wc_ajax = $this->wc_ajax_endpoint_name();
|
|
return in_array( $wc_ajax, array( 'update_order_review' ), true );
|
|
}
|
|
|
|
/**
|
|
* Checks WC is_cart() + WC cart ajax requests.
|
|
*/
|
|
private function is_cart(): bool {
|
|
if ( is_cart() ) {
|
|
return true;
|
|
}
|
|
|
|
if ( $this->is_cart_ajax() ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if performing the WC cart ajax requests.
|
|
*/
|
|
private function is_cart_ajax(): bool {
|
|
/**
|
|
* The filter returning whether to detect WC checkout ajax requests.
|
|
*/
|
|
if ( ! apply_filters( 'ppcp_check_ajax_cart', true ) ) {
|
|
return false;
|
|
}
|
|
|
|
$wc_ajax = $this->wc_ajax_endpoint_name();
|
|
return in_array( $wc_ajax, array( 'update_shipping_method' ), true );
|
|
}
|
|
|
|
/**
|
|
* Returns the current WC ajax endpoint name or an empty string if not in ajax.
|
|
*/
|
|
private function wc_ajax_endpoint_name(): string {
|
|
// phpcs:ignore WordPress.Security
|
|
$wc_ajax = $_GET['wc-ajax'] ?? '';
|
|
if ( ! is_string( $wc_ajax ) ) {
|
|
return '';
|
|
}
|
|
return $wc_ajax;
|
|
}
|
|
|
|
/**
|
|
* The current context.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function context(): string {
|
|
// Default context.
|
|
$context = 'mini-cart';
|
|
|
|
switch ( true ) {
|
|
case $this->is_cart_ajax():
|
|
$context = 'cart';
|
|
break;
|
|
|
|
case $this->is_checkout_ajax() && ! $this->is_paypal_continuation():
|
|
$context = 'checkout';
|
|
break;
|
|
|
|
case is_product() || wc_post_content_has_shortcode( 'product_page' ):
|
|
// Do this check here instead of reordering outside conditions.
|
|
// In order to have more control over the context.
|
|
if ( $this->is_checkout() && ! $this->is_paypal_continuation() ) {
|
|
$context = 'checkout';
|
|
} else {
|
|
$context = 'product';
|
|
}
|
|
break;
|
|
|
|
// has_block may not work if called too early, such as during the block registration.
|
|
case has_block( 'woocommerce/cart' ):
|
|
$context = 'cart-block';
|
|
break;
|
|
|
|
case $this->is_cart():
|
|
$context = 'cart';
|
|
break;
|
|
|
|
case is_checkout_pay_page():
|
|
$context = 'pay-now';
|
|
break;
|
|
|
|
case has_block( 'woocommerce/checkout' ):
|
|
$context = 'checkout-block';
|
|
break;
|
|
|
|
case $this->is_checkout() && ! $this->is_paypal_continuation():
|
|
$context = 'checkout';
|
|
break;
|
|
|
|
case $this->is_add_payment_method_page():
|
|
$context = 'add-payment-method';
|
|
break;
|
|
|
|
case $this->is_block_editor():
|
|
$context = 'block-editor';
|
|
break;
|
|
}
|
|
|
|
return apply_filters( 'woocommerce_paypal_payments_context', $context );
|
|
}
|
|
|
|
/**
|
|
* The current location.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function location(): string {
|
|
$context = $this->context();
|
|
if ( $context !== 'mini-cart' ) {
|
|
return $context;
|
|
}
|
|
|
|
if ( is_shop() || is_product_category() ) {
|
|
return 'shop';
|
|
}
|
|
|
|
if ( is_front_page() ) {
|
|
return 'home';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Checks if PayPal payment was already initiated (on the product or cart pages).
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_paypal_continuation(): bool {
|
|
/**
|
|
* Property is already defined in trait consumers.
|
|
*
|
|
* @psalm-suppress UndefinedThisPropertyFetch
|
|
*/
|
|
$order = $this->session_handler->order();
|
|
if ( ! $order ) {
|
|
return false;
|
|
}
|
|
|
|
/** @var string $subscription_id */
|
|
$subscription_id = wc()->session->get( 'ppcp_subscription_id' );
|
|
|
|
if ( ! $order->status()->is( OrderStatus::APPROVED )
|
|
&& ! $order->status()->is( OrderStatus::COMPLETED )
|
|
&& ! $subscription_id
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
$subscription_status = '';
|
|
if ( $subscription_id ) {
|
|
try {
|
|
$subscription_status = $this->subscription_status->get_status( $subscription_id );
|
|
} catch ( RuntimeException | PayPalApiException $exception ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ( $subscription_id &&
|
|
'ACTIVE' !== $subscription_status
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
$source = $order->payment_source();
|
|
if ( $source && $source->name() === 'card' ) {
|
|
return false; // Ignore for DCC.
|
|
}
|
|
|
|
if ( 'card' === $this->session_handler->funding_source() ) {
|
|
return false; // Ignore for card buttons.
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks whether current page is Add payment method.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_add_payment_method_page(): bool {
|
|
/**
|
|
* Needed for WordPress `query_vars`.
|
|
*
|
|
* @psalm-suppress InvalidGlobal
|
|
*/
|
|
global $wp;
|
|
|
|
$page_id = wc_get_page_id( 'myaccount' );
|
|
|
|
return $page_id && is_page( $page_id ) && isset( $wp->query_vars['add-payment-method'] );
|
|
}
|
|
|
|
/**
|
|
* Checks whether this user is changing the payment method for a subscription.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_subscription_change_payment_method_page(): bool {
|
|
// phpcs:disable WordPress.Security.NonceVerification
|
|
if ( isset( $_GET['change_payment_method'] ) ) {
|
|
return wcs_is_subscription( wc_clean( wp_unslash( $_GET['change_payment_method'] ) ) );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if it is the block editor page.
|
|
*/
|
|
public function is_block_editor(): bool {
|
|
if ( ! function_exists( 'get_current_screen' ) ) {
|
|
return false;
|
|
}
|
|
$screen = get_current_screen();
|
|
return $screen && $screen->is_block_editor();
|
|
}
|
|
|
|
/**
|
|
* Checks if is WooCommerce Settings Payments tab screen (/wp-admin/admin.php?page=wc-settings&tab=checkout).
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_wc_settings_payments_tab(): bool {
|
|
// phpcs:disable WordPress.Security.NonceVerification
|
|
if ( ! is_admin() || isset( $_GET['section'] ) ) {
|
|
return false;
|
|
}
|
|
|
|
$page = wc_clean( wp_unslash( $_GET['page'] ?? '' ) );
|
|
$tab = wc_clean( wp_unslash( $_GET['tab'] ?? '' ) );
|
|
// phpcs:enable WordPress.Security.NonceVerification
|
|
|
|
return $page === 'wc-settings' && $tab === 'checkout';
|
|
}
|
|
}
|