From 99ca470d3f493d3334a038dff669eb53b6e8c969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Fri, 31 Jan 2025 08:25:03 +0100 Subject: [PATCH 01/47] Moved code for payment process order to subscriptions module by adding a new filter --- modules/ppcp-applepay/src/ApplePayGateway.php | 15 +++++++- modules/ppcp-axo/src/Gateway/AxoGateway.php | 13 ++++++- .../ppcp-googlepay/src/GooglePayGateway.php | 15 +++++++- .../src/PayPalSubscriptionsModule.php | 38 +++++++++++++++++++ .../src/Gateway/CardButtonGateway.php | 13 ++++++- .../src/Gateway/CreditCardGateway.php | 13 ++++++- .../src/Gateway/PayPalGateway.php | 35 ++++++----------- .../src/Processor/OrderMetaTrait.php | 2 +- .../Processor/TransactionIdHandlingTrait.php | 4 +- .../src/Handler/CheckoutOrderApproved.php | 13 ++++++- 10 files changed, 127 insertions(+), 34 deletions(-) diff --git a/modules/ppcp-applepay/src/ApplePayGateway.php b/modules/ppcp-applepay/src/ApplePayGateway.php index fbbdac900..da80dd488 100644 --- a/modules/ppcp-applepay/src/ApplePayGateway.php +++ b/modules/ppcp-applepay/src/ApplePayGateway.php @@ -180,11 +180,22 @@ class ApplePayGateway extends WC_Payment_Gateway { ); } - do_action( 'woocommerce_paypal_payments_before_process_order', $wc_order ); + do_action_deprecated('woocommerce_paypal_payments_before_process_order', [ $wc_order ], '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead. ', 'woocommerce-paypal-payments' ) ); try { try { - $this->order_processor->process( $wc_order ); + /** + * This filter controls if the method 'precess()' from OrderProcessor will be called. + * So you can implement your own for example on subscriptions + * + * - true bool controls execution of 'OrderProcessor::precess()' + * @var $this \WC_Payment_Gateway + * @var $wc_order \WC_Order + */ + $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); + if ( $process ) { + $this->order_processor->process( $wc_order ); + } do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order ); diff --git a/modules/ppcp-axo/src/Gateway/AxoGateway.php b/modules/ppcp-axo/src/Gateway/AxoGateway.php index cd0ec8579..7390df485 100644 --- a/modules/ppcp-axo/src/Gateway/AxoGateway.php +++ b/modules/ppcp-axo/src/Gateway/AxoGateway.php @@ -253,7 +253,18 @@ class AxoGateway extends WC_Payment_Gateway { $order = $this->create_paypal_order( $wc_order, $token ); - $this->order_processor->process_captured_and_authorized( $wc_order, $order ); + /** + * This filter controls if the method 'precess()' from OrderProcessor will be called. + * So you can implement your own for example on subscriptions + * + * - true bool controls execution of 'OrderProcessor::precess()' + * @var $this \WC_Payment_Gateway + * @var $wc_order \WC_Order + */ + $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); + if ( $process ) { + $this->order_processor->process_captured_and_authorized( $wc_order, $order ); + } } catch ( Exception $exception ) { return $this->handle_payment_failure( $wc_order, $exception ); } diff --git a/modules/ppcp-googlepay/src/GooglePayGateway.php b/modules/ppcp-googlepay/src/GooglePayGateway.php index 16fe5f690..29e8fae0b 100644 --- a/modules/ppcp-googlepay/src/GooglePayGateway.php +++ b/modules/ppcp-googlepay/src/GooglePayGateway.php @@ -189,11 +189,22 @@ class GooglePayGateway extends WC_Payment_Gateway { } //phpcs:enable WordPress.Security.NonceVerification.Recommended - do_action( 'woocommerce_paypal_payments_before_process_order', $wc_order ); + do_action_deprecated('woocommerce_paypal_payments_before_process_order', [ $wc_order ], '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead. ', 'woocommerce-paypal-payments' ) ); try { try { - $this->order_processor->process( $wc_order ); + /** + * This filter controls if the method 'precess()' from OrderProcessor will be called. + * So you can implement your own for example on subscriptions + * + * - true bool controls execution of 'OrderProcessor::precess()' + * @var $this \WC_Payment_Gateway + * @var $wc_order \WC_Order + */ + $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); + if ( $process ) { + $this->order_processor->process( $wc_order ); + } do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order ); diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 48c3a71af..09148543b 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -28,6 +28,7 @@ use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameI use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WP_Post; @@ -56,6 +57,43 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu * {@inheritDoc} */ public function run( ContainerInterface $c ): bool { + + add_filter( + 'woocommerce_paypal_payments_before_order_process', + function ( bool $process, \WC_Payment_Gateway $gateway, \WC_Order $wc_order ) use ( $c ) { + if ( ! $gateway instanceof PayPalGateway || $gateway::ID !== 'ppcp-gateway' ) { + return $process; + } + + $paypal_subscription_id = \WC()->session->get( 'ppcp_subscription_id' ) ?? ''; + if ( ! $paypal_subscription_id ) { + return $process; + } + + $order = $c->get( 'session.handler' )->order(); + $gateway->add_paypal_meta( $wc_order, $order, $c->get( 'onboarding.environment' ) ); + + $subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $wc_order ) : array(); + foreach ( $subscriptions as $subscription ) { + $subscription->update_meta_data( 'ppcp_subscription', $paypal_subscription_id ); + $subscription->save(); + + $subscription->add_order_note( "PayPal subscription {$paypal_subscription_id} added." ); + } + + $transaction_id = $gateway->get_paypal_order_transaction_id( $order ); + if ( $transaction_id ) { + $gateway->update_transaction_id( $transaction_id, $wc_order, $c->get( 'woocommerce.logger.woocommerce' ) ); + } + + $wc_order->payment_complete(); + + return false; + }, + 10, + 3 + ); + add_action( 'save_post', /** diff --git a/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php index ffb0fe55c..feec7db5b 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php @@ -295,7 +295,18 @@ class CardButtonGateway extends \WC_Payment_Gateway { try { try { - $this->order_processor->process( $wc_order ); + /** + * This filter controls if the method 'precess()' from OrderProcessor will be called. + * So you can implement your own for example on subscriptions + * + * - true bool controls execution of 'OrderProcessor::precess()' + * @var $this \WC_Payment_Gateway + * @var $wc_order \WC_Order + */ + $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); + if ( $process ) { + $this->order_processor->process( $wc_order ); + } do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php index a5e897548..e5420a65b 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php @@ -523,7 +523,18 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC { //phpcs:enable WordPress.Security.NonceVerification.Recommended try { - $this->order_processor->process( $wc_order ); + /** + * This filter controls if the method 'precess()' from OrderProcessor will be called. + * So you can implement your own for example on subscriptions + * + * - true bool controls execution of 'OrderProcessor::precess()' + * @var $this \WC_Payment_Gateway + * @var $wc_order \WC_Order + */ + $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); + if ( $process ) { + $this->order_processor->process( $wc_order ); + } do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index 5ffbeec9d..fc7a06c67 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -625,30 +625,19 @@ class PayPalGateway extends \WC_Payment_Gateway { //phpcs:enable WordPress.Security.NonceVerification.Recommended try { - $paypal_subscription_id = WC()->session->get( 'ppcp_subscription_id' ) ?? ''; - if ( $paypal_subscription_id ) { - $order = $this->session_handler->order(); - $this->add_paypal_meta( $wc_order, $order, $this->environment ); - - $subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $order_id ) : array(); - foreach ( $subscriptions as $subscription ) { - $subscription->update_meta_data( 'ppcp_subscription', $paypal_subscription_id ); - $subscription->save(); - - $subscription->add_order_note( "PayPal subscription {$paypal_subscription_id} added." ); - } - - $transaction_id = $this->get_paypal_order_transaction_id( $order ); - if ( $transaction_id ) { - $this->update_transaction_id( $transaction_id, $wc_order ); - } - - $wc_order->payment_complete(); - - return $this->handle_payment_success( $wc_order ); - } try { - $this->order_processor->process( $wc_order ); + /** + * This filter controls if the method 'precess()' from OrderProcessor will be called. + * So you can implement your own for example on subscriptions + * + * - true bool controls execution of 'OrderProcessor::precess()' + * @var $this \WC_Payment_Gateway + * @var $wc_order \WC_Order + */ + $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); + if ( $process ) { + $this->order_processor->process( $wc_order ); + } do_action( 'woocommerce_paypal_payments_before_handle_payment_success', $wc_order ); diff --git a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php index 62a80456a..7af20ce16 100644 --- a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php +++ b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php @@ -28,7 +28,7 @@ trait OrderMetaTrait { * @param Environment $environment The environment. * @param OrderTransient|null $order_transient The order transient helper. */ - protected function add_paypal_meta( + public function add_paypal_meta( WC_Order $wc_order, Order $order, Environment $environment, diff --git a/modules/ppcp-wc-gateway/src/Processor/TransactionIdHandlingTrait.php b/modules/ppcp-wc-gateway/src/Processor/TransactionIdHandlingTrait.php index c6e666176..1b0b4c0f0 100644 --- a/modules/ppcp-wc-gateway/src/Processor/TransactionIdHandlingTrait.php +++ b/modules/ppcp-wc-gateway/src/Processor/TransactionIdHandlingTrait.php @@ -28,7 +28,7 @@ trait TransactionIdHandlingTrait { * * @return bool */ - protected function update_transaction_id( + public function update_transaction_id( string $transaction_id, WC_Order $wc_order, LoggerInterface $logger = null @@ -67,7 +67,7 @@ trait TransactionIdHandlingTrait { * * @return string|null */ - protected function get_paypal_order_transaction_id( Order $order ): ?string { + public function get_paypal_order_transaction_id( Order $order ): ?string { $purchase_unit = $order->purchase_units()[0] ?? null; if ( ! $purchase_unit ) { return null; diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php b/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php index d93ca5b4c..4bb80c524 100644 --- a/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php +++ b/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php @@ -230,7 +230,18 @@ class CheckoutOrderApproved implements RequestHandler { } try { - $this->order_processor->process( $wc_order ); + /** + * This filter controls if the method 'precess()' from OrderProcessor will be called. + * So you can implement your own for example on subscriptions + * + * - true bool controls execution of 'OrderProcessor::precess()' + * @var $this \WC_Payment_Gateway + * @var $wc_order \WC_Order + */ + $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); + if ( $process ) { + $this->order_processor->process( $wc_order ); + } } catch ( RuntimeException $exception ) { return $this->failure_response( sprintf( From a4ccd02902173c2bd74a2f3284cbcfa9c1e761e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Fri, 31 Jan 2025 08:28:15 +0100 Subject: [PATCH 02/47] fixed PHPCS --- modules/ppcp-applepay/src/ApplePayGateway.php | 4 ++-- modules/ppcp-axo/src/Gateway/AxoGateway.php | 4 ++-- modules/ppcp-googlepay/src/GooglePayGateway.php | 4 ++-- modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php | 4 ++-- modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php | 4 ++-- modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php | 4 ++-- modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/ppcp-applepay/src/ApplePayGateway.php b/modules/ppcp-applepay/src/ApplePayGateway.php index da80dd488..cdbabde9f 100644 --- a/modules/ppcp-applepay/src/ApplePayGateway.php +++ b/modules/ppcp-applepay/src/ApplePayGateway.php @@ -189,8 +189,8 @@ class ApplePayGateway extends WC_Payment_Gateway { * So you can implement your own for example on subscriptions * * - true bool controls execution of 'OrderProcessor::precess()' - * @var $this \WC_Payment_Gateway - * @var $wc_order \WC_Order + * - $this \WC_Payment_Gateway + * - $wc_order \WC_Order */ $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); if ( $process ) { diff --git a/modules/ppcp-axo/src/Gateway/AxoGateway.php b/modules/ppcp-axo/src/Gateway/AxoGateway.php index 7390df485..a77ec00ee 100644 --- a/modules/ppcp-axo/src/Gateway/AxoGateway.php +++ b/modules/ppcp-axo/src/Gateway/AxoGateway.php @@ -258,8 +258,8 @@ class AxoGateway extends WC_Payment_Gateway { * So you can implement your own for example on subscriptions * * - true bool controls execution of 'OrderProcessor::precess()' - * @var $this \WC_Payment_Gateway - * @var $wc_order \WC_Order + * - $this \WC_Payment_Gateway + * - $wc_order \WC_Order */ $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); if ( $process ) { diff --git a/modules/ppcp-googlepay/src/GooglePayGateway.php b/modules/ppcp-googlepay/src/GooglePayGateway.php index 29e8fae0b..36ddc580a 100644 --- a/modules/ppcp-googlepay/src/GooglePayGateway.php +++ b/modules/ppcp-googlepay/src/GooglePayGateway.php @@ -198,8 +198,8 @@ class GooglePayGateway extends WC_Payment_Gateway { * So you can implement your own for example on subscriptions * * - true bool controls execution of 'OrderProcessor::precess()' - * @var $this \WC_Payment_Gateway - * @var $wc_order \WC_Order + * - $this \WC_Payment_Gateway + * - $wc_order \WC_Order */ $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); if ( $process ) { diff --git a/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php index feec7db5b..773965bf7 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php @@ -300,8 +300,8 @@ class CardButtonGateway extends \WC_Payment_Gateway { * So you can implement your own for example on subscriptions * * - true bool controls execution of 'OrderProcessor::precess()' - * @var $this \WC_Payment_Gateway - * @var $wc_order \WC_Order + * - $this \WC_Payment_Gateway + * - $wc_order \WC_Order */ $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); if ( $process ) { diff --git a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php index e5420a65b..2ef5c53e4 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php @@ -528,8 +528,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC { * So you can implement your own for example on subscriptions * * - true bool controls execution of 'OrderProcessor::precess()' - * @var $this \WC_Payment_Gateway - * @var $wc_order \WC_Order + * - $this \WC_Payment_Gateway + * - $wc_order \WC_Order */ $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); if ( $process ) { diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index fc7a06c67..9719c29e6 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -631,8 +631,8 @@ class PayPalGateway extends \WC_Payment_Gateway { * So you can implement your own for example on subscriptions * * - true bool controls execution of 'OrderProcessor::precess()' - * @var $this \WC_Payment_Gateway - * @var $wc_order \WC_Order + * - $this \WC_Payment_Gateway + * - $wc_order \WC_Order */ $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); if ( $process ) { diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php b/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php index 4bb80c524..b3c73ef80 100644 --- a/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php +++ b/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php @@ -235,8 +235,8 @@ class CheckoutOrderApproved implements RequestHandler { * So you can implement your own for example on subscriptions * * - true bool controls execution of 'OrderProcessor::precess()' - * @var $this \WC_Payment_Gateway - * @var $wc_order \WC_Order + * - $this \WC_Payment_Gateway + * - $wc_order \WC_Order */ $process = apply_filters( 'woocommerce_paypal_payments_before_order_process', true, $this, $wc_order ); if ( $process ) { From 6826e0cafc0410e162749a3f23f4e493171e2c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Fri, 31 Jan 2025 08:34:47 +0100 Subject: [PATCH 03/47] fixed PHPCS --- .../ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 09148543b..014224dde 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -65,7 +65,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return $process; } - $paypal_subscription_id = \WC()->session->get( 'ppcp_subscription_id' ) ?? ''; + $paypal_subscription_id = (string) \WC()->session->get( 'ppcp_subscription_id' ) ?? ''; if ( ! $paypal_subscription_id ) { return $process; } From 51575fde647847aad24931a57f12da960a0cf454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Fri, 31 Jan 2025 08:45:44 +0100 Subject: [PATCH 04/47] make string translatable and improved checking of subscription id from session --- .../src/PayPalSubscriptionsModule.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 014224dde..68092b28e 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -65,8 +65,8 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return $process; } - $paypal_subscription_id = (string) \WC()->session->get( 'ppcp_subscription_id' ) ?? ''; - if ( ! $paypal_subscription_id ) { + $paypal_subscription_id = \WC()->session->get( 'ppcp_subscription_id' ); + if ( empty( $paypal_subscription_id ) || ! is_string( $paypal_subscription_id ) ) { return $process; } @@ -77,8 +77,8 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu foreach ( $subscriptions as $subscription ) { $subscription->update_meta_data( 'ppcp_subscription', $paypal_subscription_id ); $subscription->save(); - - $subscription->add_order_note( "PayPal subscription {$paypal_subscription_id} added." ); + // translators: %s PayPal Subscription id. + $subscription->add_order_note( sprintf( __( 'PayPal subscription %s added.', 'woocommerce-paypal-payments' ), $paypal_subscription_id ) ); } $transaction_id = $gateway->get_paypal_order_transaction_id( $order ); From 1f6bd8b7926a8322c8059dcf6ca0c5b8bc9f2337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Mon, 3 Feb 2025 15:29:16 +0100 Subject: [PATCH 05/47] Moved code to pp subscriptions from generell subscriptions --- .../src/PayPalSubscriptionsModule.php | 31 ++++++++++++++++ .../src/WcSubscriptionsModule.php | 35 +++---------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 68092b28e..8a542322d 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -58,6 +58,37 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu */ public function run( ContainerInterface $c ): bool { + add_filter( + 'woocommerce_paypal_payments_paypal_gateway_supports', + function ( array $supports ) use ( $c ): array { + $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); + assert( $subscriptions_helper instanceof SubscriptionHelper ); + + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; + + if ( 'subscriptions_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { + $supports = array( + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_date_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_customer', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', + 'gateway_scheduled_payments', + ); + } + + return $supports; + } + ); + add_filter( 'woocommerce_paypal_payments_before_order_process', function ( bool $process, \WC_Payment_Gateway $gateway, \WC_Order $wc_order ) use ( $c ) { diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php index 77fd27bbc..d28f6b608 100644 --- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php +++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php @@ -236,31 +236,6 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl } ); - // Remove `gateway_scheduled_payments` feature support for non PayPal Subscriptions at subscription level. - add_filter( - 'woocommerce_subscription_payment_gateway_supports', - /** - * Param types removed to avoid third-party issues. - * - * @psalm-suppress MissingClosureParamType - */ - function( $is_supported, $feature, $subscription ) { - if ( - $subscription->get_payment_method() === PayPalGateway::ID - && $feature === 'gateway_scheduled_payments' - ) { - $subscription_connected = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; - if ( ! $subscription_connected ) { - $is_supported = false; - } - } - - return $is_supported; - }, - 10, - 3 - ); - return true; } @@ -417,7 +392,7 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - if ( 'disable_paypal_subscriptions' !== $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { + if ( 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { $supports = array( 'subscriptions', 'subscription_cancellation', @@ -429,7 +404,6 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl 'subscription_payment_method_change_customer', 'subscription_payment_method_change_admin', 'multiple_subscriptions', - 'gateway_scheduled_payments', ); } @@ -446,9 +420,10 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); - $vaulting_enabled = $settings->has( 'vault_enabled_dcc' ) && $settings->get( 'vault_enabled_dcc' ); + $vaulting_enabled = $settings->has( 'vault_enabled_dcc' ) && $settings->get( 'vault_enabled_dcc' ); + $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - if ( $vaulting_enabled && $subscriptions_helper->plugin_is_active() ) { + if ( $vaulting_enabled && 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { $supports = array( 'subscriptions', 'subscription_cancellation', @@ -478,7 +453,7 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - if ( 'disable_paypal_subscriptions' !== $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { + if ( 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { $supports = array( 'subscriptions', 'subscription_cancellation', From 96ce1fb7a43b7a37198e3abf6c6b52690f080f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 4 Feb 2025 09:27:27 +0100 Subject: [PATCH 06/47] Use PP Subscriptions suspend when subscription is in pending-cancel state. --- .../src/PayPalSubscriptionsModule.php | 136 ++++-------------- .../src/SubscriptionStatus.php | 27 ++-- .../src/WcSubscriptionsModule.php | 75 +++++----- 3 files changed, 87 insertions(+), 151 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 8a542322d..4cc164fe2 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -70,18 +70,20 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; if ( 'subscriptions_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', - 'gateway_scheduled_payments', + $supports = array_merge( + $supports, + array( + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_customer', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', + 'gateway_scheduled_payments', + ) ); } @@ -89,6 +91,18 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu } ); + add_filter( + 'woocommerce_can_subscription_be_updated_to_active', + function ( bool $can_be_updated, \WC_Subscription $subscription ) use ( $c ) { + if ( $subscription->payment_method_supports( 'gateway_scheduled_payments' ) && $subscription->get_status() === 'pending-cancel' && $subscription->get_payment_method() === PayPalGateway::ID ) { + return true; + } + return $can_be_updated; + }, + 10, + 2 + ); + add_filter( 'woocommerce_paypal_payments_before_order_process', function ( bool $process, \WC_Payment_Gateway $gateway, \WC_Order $wc_order ) use ( $c ) { @@ -326,104 +340,6 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu 2 ); - add_filter( - 'wcs_view_subscription_actions', - /** - * Param types removed to avoid third-party issues. - * - * @psalm-suppress MissingClosureParamType - */ - function( $actions, $subscription ): array { - if ( ! is_a( $subscription, WC_Subscription::class ) ) { - return $actions; - } - - $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; - if ( $subscription_id && $subscription->get_status() === 'active' ) { - $url = wp_nonce_url( - add_query_arg( - array( - 'change_subscription_to' => 'cancelled', - 'ppcp_cancel_subscription' => $subscription->get_id(), - ) - ), - 'ppcp_cancel_subscription_nonce' - ); - - array_unshift( - $actions, - array( - 'url' => esc_url( $url ), - 'name' => esc_html__( 'Cancel', 'woocommerce-paypal-payments' ), - ) - ); - - $actions['cancel']['name'] = esc_html__( 'Suspend', 'woocommerce-paypal-payments' ); - unset( $actions['subscription_renewal_early'] ); - } - - return $actions; - }, - 11, - 2 - ); - - add_action( - 'wp_loaded', - function() use ( $c ) { - if ( ! function_exists( 'wcs_get_subscription' ) ) { - return; - } - - $cancel_subscription_id = wc_clean( wp_unslash( $_GET['ppcp_cancel_subscription'] ?? '' ) ); - $subscription = wcs_get_subscription( absint( $cancel_subscription_id ) ); - if ( ! wcs_is_subscription( $subscription ) || $subscription === false ) { - return; - } - - $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; - $nonce = wc_clean( wp_unslash( $_GET['_wpnonce'] ?? '' ) ); - if ( ! is_string( $nonce ) ) { - return; - } - - if ( - $subscription_id - && $cancel_subscription_id - && $nonce - ) { - if ( - ! wp_verify_nonce( $nonce, 'ppcp_cancel_subscription_nonce' ) - || ! user_can( get_current_user_id(), 'edit_shop_subscription_status', $subscription->get_id() ) - ) { - return; - } - - $subscriptions_endpoint = $c->get( 'api.endpoint.billing-subscriptions' ); - $subscription_id = $subscription->get_meta( 'ppcp_subscription' ); - try { - $subscriptions_endpoint->cancel( $subscription_id ); - - $subscription->update_status( 'cancelled' ); - $subscription->add_order_note( __( 'Subscription cancelled by the subscriber from their account page.', 'woocommerce-paypal-payments' ) ); - wc_add_notice( __( 'Your subscription has been cancelled.', 'woocommerce-paypal-payments' ) ); - - wp_safe_redirect( $subscription->get_view_order_url() ); - exit; - } catch ( RuntimeException $exception ) { - $error = $exception->getMessage(); - if ( is_a( $exception, PayPalApiException::class ) ) { - $error = $exception->get_details( $error ); - } - - $logger = $c->get( 'woocommerce.logger.woocommerce' ); - $logger->error( 'Could not cancel subscription product on PayPal. ' . $error ); - } - } - }, - 100 - ); - add_action( 'woocommerce_subscription_before_actions', /** diff --git a/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php b/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php index 1fbec3926..077e5856f 100644 --- a/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php +++ b/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php @@ -55,7 +55,7 @@ class SubscriptionStatus { * @return void */ public function update_status( string $subscription_status, string $subscription_id ): void { - if ( $subscription_status === 'pending-cancel' || $subscription_status === 'cancelled' ) { + if ( $subscription_status === 'cancelled' ) { try { $current_subscription = $this->subscriptions_endpoint->subscription( $subscription_id ); if ( $current_subscription->status === 'CANCELLED' ) { @@ -81,14 +81,25 @@ class SubscriptionStatus { } } - if ( $subscription_status === 'on-hold' ) { + if ( $subscription_status === 'on-hold' || $subscription_status === 'pending-cancel' ) { try { - $this->logger->info( - sprintf( - 'Suspending PayPal subscription #%s.', - $subscription_id - ) - ); + if ( $subscription_status === 'on-hold' ) { + $this->logger->info( + sprintf( + 'Suspending PayPal subscription #%s.', + $subscription_id + ) + ); + } + if ( $subscription_status === 'pending-cancel' ) { + $this->logger->info( + sprintf( + 'Suspending PayPal subscription #%s till cancellation', + $subscription_id + ) + ); + } + $this->subscriptions_endpoint->suspend( $subscription_id ); } catch ( RuntimeException $exception ) { diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php index d28f6b608..cd7a386dd 100644 --- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php +++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php @@ -393,17 +393,20 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; if ( 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', + $supports = array_merge( + $supports, + array( + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_date_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_customer', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', + ) ); } @@ -424,17 +427,20 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; if ( $vaulting_enabled && 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', + $supports = array_merge( + $supports, + array( + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_date_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_customer', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', + ) ); } @@ -454,17 +460,20 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; if ( 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', + $supports = array_merge( + $supports, + array( + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_date_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_customer', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', + ) ); } From 5959ea71a286cd373e075e7e5e217b1e75142b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 4 Feb 2025 09:44:14 +0100 Subject: [PATCH 07/47] Change unneeded code --- .../src/PayPalSubscriptionsModule.php | 23 ------------------- .../src/SubscriptionStatus.php | 23 +++++-------------- 2 files changed, 6 insertions(+), 40 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 4cc164fe2..6378cb4cb 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -317,29 +317,6 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu } ); - add_filter( - 'woocommerce_order_actions', - /** - * Param types removed to avoid third-party issues. - * - * @psalm-suppress MissingClosureParamType - */ - function( $actions, $subscription = null ): array { - if ( ! is_array( $actions ) || ! is_a( $subscription, WC_Subscription::class ) ) { - return $actions; - } - - $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; - if ( $subscription_id && isset( $actions['wcs_process_renewal'] ) ) { - unset( $actions['wcs_process_renewal'] ); - } - - return $actions; - }, - 20, - 2 - ); - add_action( 'woocommerce_subscription_before_actions', /** diff --git a/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php b/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php index 077e5856f..65d991abe 100644 --- a/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php +++ b/modules/ppcp-paypal-subscriptions/src/SubscriptionStatus.php @@ -83,23 +83,12 @@ class SubscriptionStatus { if ( $subscription_status === 'on-hold' || $subscription_status === 'pending-cancel' ) { try { - if ( $subscription_status === 'on-hold' ) { - $this->logger->info( - sprintf( - 'Suspending PayPal subscription #%s.', - $subscription_id - ) - ); - } - if ( $subscription_status === 'pending-cancel' ) { - $this->logger->info( - sprintf( - 'Suspending PayPal subscription #%s till cancellation', - $subscription_id - ) - ); - } - + $this->logger->info( + sprintf( + 'Suspending PayPal subscription #%s.', + $subscription_id + ) + ); $this->subscriptions_endpoint->suspend( $subscription_id ); } catch ( RuntimeException $exception ) { From 55b758793818f5462a19d47117b933b76ad1a2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 4 Feb 2025 09:54:25 +0100 Subject: [PATCH 08/47] fix phpcs --- modules/ppcp-applepay/src/ApplePayGateway.php | 2 +- modules/ppcp-googlepay/src/GooglePayGateway.php | 3 ++- modules/ppcp-settings/src/SettingsModule.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-applepay/src/ApplePayGateway.php b/modules/ppcp-applepay/src/ApplePayGateway.php index cdbabde9f..857144038 100644 --- a/modules/ppcp-applepay/src/ApplePayGateway.php +++ b/modules/ppcp-applepay/src/ApplePayGateway.php @@ -180,7 +180,7 @@ class ApplePayGateway extends WC_Payment_Gateway { ); } - do_action_deprecated('woocommerce_paypal_payments_before_process_order', [ $wc_order ], '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead. ', 'woocommerce-paypal-payments' ) ); + do_action_deprecated( 'woocommerce_paypal_payments_before_process_order', array( $wc_order ), '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead.', 'woocommerce-paypal-payments' ) ); try { try { diff --git a/modules/ppcp-googlepay/src/GooglePayGateway.php b/modules/ppcp-googlepay/src/GooglePayGateway.php index 36ddc580a..725ffe5a2 100644 --- a/modules/ppcp-googlepay/src/GooglePayGateway.php +++ b/modules/ppcp-googlepay/src/GooglePayGateway.php @@ -189,7 +189,8 @@ class GooglePayGateway extends WC_Payment_Gateway { } //phpcs:enable WordPress.Security.NonceVerification.Recommended - do_action_deprecated('woocommerce_paypal_payments_before_process_order', [ $wc_order ], '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead. ', 'woocommerce-paypal-payments' ) ); + do_action_deprecated( 'woocommerce_paypal_payments_before_process_order', array( $wc_order ), '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead.', 'woocommerce-paypal-payments' ) ); + try { try { diff --git a/modules/ppcp-settings/src/SettingsModule.php b/modules/ppcp-settings/src/SettingsModule.php index 742f0527c..f0fbbdf57 100644 --- a/modules/ppcp-settings/src/SettingsModule.php +++ b/modules/ppcp-settings/src/SettingsModule.php @@ -185,7 +185,7 @@ class SettingsModule implements ServiceModule, ExecutableModule { 'wcPaymentsTabUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout' ), 'debug' => defined( 'WP_DEBUG' ) && WP_DEBUG, 'isPayLaterConfiguratorAvailable' => $is_pay_later_configurator_available, - 'storeCountry' => $container->get( 'wcgateway.store-country' ), + 'storeCountry' => $container->get( 'wcgateway.store-country' ), ); if ( $is_pay_later_configurator_available ) { From cec5b0da2c1cdddfe7690ccdeba69d1d912eca4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 4 Feb 2025 10:11:27 +0100 Subject: [PATCH 09/47] fix phpcs --- modules/ppcp-applepay/src/ApplePayGateway.php | 2 +- modules/ppcp-googlepay/src/GooglePayGateway.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-applepay/src/ApplePayGateway.php b/modules/ppcp-applepay/src/ApplePayGateway.php index 857144038..1fc09c6a6 100644 --- a/modules/ppcp-applepay/src/ApplePayGateway.php +++ b/modules/ppcp-applepay/src/ApplePayGateway.php @@ -180,7 +180,7 @@ class ApplePayGateway extends WC_Payment_Gateway { ); } - do_action_deprecated( 'woocommerce_paypal_payments_before_process_order', array( $wc_order ), '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead.', 'woocommerce-paypal-payments' ) ); + do_action_deprecated( 'woocommerce_paypal_payments_before_process_order', array( $wc_order ), '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead.', 'woocommerce-paypal-payments' ) ); try { try { diff --git a/modules/ppcp-googlepay/src/GooglePayGateway.php b/modules/ppcp-googlepay/src/GooglePayGateway.php index 725ffe5a2..4c4a4dbf1 100644 --- a/modules/ppcp-googlepay/src/GooglePayGateway.php +++ b/modules/ppcp-googlepay/src/GooglePayGateway.php @@ -189,8 +189,7 @@ class GooglePayGateway extends WC_Payment_Gateway { } //phpcs:enable WordPress.Security.NonceVerification.Recommended - do_action_deprecated( 'woocommerce_paypal_payments_before_process_order', array( $wc_order ), '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead.', 'woocommerce-paypal-payments' ) ); - + do_action_deprecated( 'woocommerce_paypal_payments_before_process_order', array( $wc_order ), '2.9.7', 'woocommerce_paypal_payments_before_order_process', __( 'Usage of this action is deprecated. Please use the filter woocommerce_paypal_payments_before_order_process instead.', 'woocommerce-paypal-payments' ) ); try { try { From aca125934a164cbd6b2427ab424e1459eb217830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 4 Feb 2025 15:36:02 +0100 Subject: [PATCH 10/47] handle old subscriptions if setting is changed --- .../src/PayPalSubscriptionsModule.php | 91 +++++++++++---- .../src/WcSubscriptionsModule.php | 106 +++++++----------- 2 files changed, 108 insertions(+), 89 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 6378cb4cb..62b4318f4 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -59,38 +59,83 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu public function run( ContainerInterface $c ): bool { add_filter( - 'woocommerce_paypal_payments_paypal_gateway_supports', - function ( array $supports ) use ( $c ): array { - $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); - assert( $subscriptions_helper instanceof SubscriptionHelper ); - + 'woocommerce_available_payment_gateways', + function ( array $gateways ) use ( $c ) { + if ( ! WC()->cart || WC()->cart->is_empty() ) { + return $gateways; + } $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - - if ( 'subscriptions_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array_merge( - $supports, - array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', - 'gateway_scheduled_payments', - ) - ); + if ( $subscriptions_mode !== 'subscriptions_api' ) { + return $gateways; } - return $supports; + $subscriptions_product = false; + $pp_subscriptions_product = false; + foreach ( WC()->cart->get_cart() as $cart_item ) { + $cart_product = wc_get_product( $cart_item['product_id'] ); + if ( $cart_product instanceof \WC_Product_Subscription || $cart_product instanceof \WC_Product_Variable_Subscription ) { + $subscriptions_product = true; + if ( $cart_product->get_meta( '_ppcp_enable_subscription_product', true ) === 'yes' ) { + $pp_subscriptions_product = true; + } + } + } + + if ( $pp_subscriptions_product ) { + foreach ( $gateways as $id => $gateway ) { + if ( $gateway->id !== PayPalGateway::ID ) { + unset( $gateways[ $id ] ); + } + } + return $gateways; + } + + if ( $subscriptions_product ) { + foreach ( $gateways as $id => $gateway ) { + if ( $gateway->id === PayPalGateway::ID ) { + unset( $gateways[ $id ] ); + } + } + } + + return $gateways; } ); + add_filter( + 'woocommerce_subscription_payment_gateway_supports', + function ( bool $payment_gateway_supports, string $payment_gateway_feature, \WC_Subscription $wc_order ): bool { + if ( ! in_array( $payment_gateway_feature, array( 'gateway_scheduled_payments', 'subscription_date_changes' ), true ) ) { + return $payment_gateway_supports; + } + + $subscription = wcs_get_subscription( $wc_order->get_id() ); + if ( ! is_a( $subscription, WC_Subscription::class ) ) { + return $payment_gateway_supports; + } + + $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; + if ( ! $subscription_id ) { + return $payment_gateway_supports; + } + + if ( $payment_gateway_feature === 'gateway_scheduled_payments' ) { + return true; + } + + if ( $payment_gateway_feature === 'subscription_date_changes' ) { + return false; + } + + return $payment_gateway_supports; + }, + 10, + 3 + ); + add_filter( 'woocommerce_can_subscription_be_updated_to_active', function ( bool $can_be_updated, \WC_Subscription $subscription ) use ( $c ) { diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php index cd7a386dd..1a0b5e151 100644 --- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php +++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php @@ -37,6 +37,19 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl use ModuleClassNameIdTrait; use TransactionIdHandlingTrait; + private const VAULT_SUPPORTS_SUBSCRIPTIONS = array( + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_date_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_customer', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', + ); + /** * {@inheritDoc} */ @@ -56,6 +69,7 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl */ public function run( ContainerInterface $c ): bool { $this->add_gateways_support( $c ); + add_action( 'woocommerce_scheduled_subscription_payment_' . PayPalGateway::ID, /** @@ -384,100 +398,60 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl add_filter( 'woocommerce_paypal_payments_paypal_gateway_supports', function ( array $supports ) use ( $c ): array { - $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); - assert( $subscriptions_helper instanceof SubscriptionHelper ); - $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - - if ( 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array_merge( - $supports, - array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', - ) - ); + if ( 'disable_paypal_subscriptions' === $subscriptions_mode ) { + return $supports; } - return $supports; + return array_merge( + $supports, + self::VAULT_SUPPORTS_SUBSCRIPTIONS + ); } ); add_filter( 'woocommerce_paypal_payments_credit_card_gateway_supports', function ( array $supports ) use ( $c ): array { - $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); - assert( $subscriptions_helper instanceof SubscriptionHelper ); - $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); - $vaulting_enabled = $settings->has( 'vault_enabled_dcc' ) && $settings->get( 'vault_enabled_dcc' ); $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - - if ( $vaulting_enabled && 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array_merge( - $supports, - array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', - ) - ); + if ( 'disable_paypal_subscriptions' === $subscriptions_mode ) { + return $supports; } - - return $supports; + $vaulting_enabled = $settings->has( 'vault_enabled_dcc' ) && $settings->get( 'vault_enabled_dcc' ); + if ( ! $vaulting_enabled ) { + return $supports; + } + return array_merge( + $supports, + self::VAULT_SUPPORTS_SUBSCRIPTIONS + ); } ); add_filter( 'woocommerce_paypal_payments_card_button_gateway_supports', function ( array $supports ) use ( $c ): array { - $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); - assert( $subscriptions_helper instanceof SubscriptionHelper ); - $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - - if ( 'vaulting_api' === $subscriptions_mode && $subscriptions_helper->plugin_is_active() ) { - $supports = array_merge( - $supports, - array( - 'subscriptions', - 'subscription_cancellation', - 'subscription_suspension', - 'subscription_reactivation', - 'subscription_amount_changes', - 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_customer', - 'subscription_payment_method_change_admin', - 'multiple_subscriptions', - ) - ); + if ( 'disable_paypal_subscriptions' === $subscriptions_mode ) { + return $supports; } - - return $supports; + $vaulting_enabled = $settings->has( 'vault_enabled' ) && $settings->get( 'vault_enabled' ); + if ( ! $vaulting_enabled ) { + return $supports; + } + return array_merge( + $supports, + self::VAULT_SUPPORTS_SUBSCRIPTIONS + ); } ); } From e0ef3f8418eec90431956d680cccb9e466c02036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 4 Feb 2025 15:48:15 +0100 Subject: [PATCH 11/47] fix phpcs --- .../src/PayPalSubscriptionsModule.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 62b4318f4..347029c71 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -126,11 +126,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return true; } - if ( $payment_gateway_feature === 'subscription_date_changes' ) { - return false; - } - - return $payment_gateway_supports; + return false; }, 10, 3 From ff3cfd3b66a686ccb0fe95cd817d2e19218d5b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Wed, 5 Feb 2025 12:30:54 +0100 Subject: [PATCH 12/47] not filter GW in admin or account page --- .../ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 347029c71..4045c4d3d 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -61,7 +61,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu add_filter( 'woocommerce_available_payment_gateways', function ( array $gateways ) use ( $c ) { - if ( ! WC()->cart || WC()->cart->is_empty() ) { + if ( ! WC()->cart || WC()->cart->is_empty() || is_account_page() || is_admin() ) { return $gateways; } $settings = $c->get( 'wcgateway.settings' ); From 916a4d40c3147ec883ffbc74e650913372df4b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Thu, 6 Feb 2025 14:42:26 +0100 Subject: [PATCH 13/47] improved some logic --- .../src/PayPalSubscriptionsModule.php | 30 +++++++++++-------- .../src/WcSubscriptionsModule.php | 6 ++++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 4045c4d3d..4df30e1c3 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -58,6 +58,12 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu */ public function run( ContainerInterface $c ): bool { + $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); + assert( $subscriptions_helper instanceof SubscriptionHelper ); + if ( ! $subscriptions_helper->plugin_is_active() ) { + return true; + } + add_filter( 'woocommerce_available_payment_gateways', function ( array $gateways ) use ( $c ) { @@ -68,7 +74,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu assert( $settings instanceof Settings ); $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - if ( $subscriptions_mode !== 'subscriptions_api' ) { + if ( $subscriptions_mode === 'disable_paypal_subscriptions' ) { return $gateways; } @@ -76,10 +82,18 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu $pp_subscriptions_product = false; foreach ( WC()->cart->get_cart() as $cart_item ) { $cart_product = wc_get_product( $cart_item['product_id'] ); - if ( $cart_product instanceof \WC_Product_Subscription || $cart_product instanceof \WC_Product_Variable_Subscription ) { + if ( isset( $cart_item['subscription_renewal']['subscription_id'] ) ) { + $subscription_renewal = wcs_get_subscription( $cart_item['subscription_renewal']['subscription_id'] ); + $subscription_id = $subscription_renewal->get_meta( 'ppcp_subscription' ) ?? ''; + if ( $subscription_id ) { + $pp_subscriptions_product = true; + break; + } + } elseif ( $cart_product instanceof \WC_Product_Subscription || $cart_product instanceof \WC_Product_Variable_Subscription ) { $subscriptions_product = true; if ( $cart_product->get_meta( '_ppcp_enable_subscription_product', true ) === 'yes' ) { $pp_subscriptions_product = true; + break; } } } @@ -188,12 +202,6 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu * @psalm-suppress MissingClosureParamType */ function( $product_id ) use ( $c ) { - $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); - assert( $subscriptions_helper instanceof SubscriptionHelper ); - if ( ! $subscriptions_helper->plugin_is_active() ) { - return; - } - $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); @@ -291,8 +299,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu assert( $subscriptions_helper instanceof SubscriptionHelper ); if ( - ! $subscriptions_helper->plugin_is_active() - || ! WC_Subscriptions_Product::is_subscription( $variation_id ) + ! WC_Subscriptions_Product::is_subscription( $variation_id ) || ! is_string( $wcsnonce_save_variations ) || ! wp_verify_nonce( $wcsnonce_save_variations, 'wcs_subscription_variations' ) ) { @@ -550,8 +557,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu assert( $subscriptions_helper instanceof SubscriptionHelper ); if ( - ! $subscriptions_helper->plugin_is_active() - || ! ( + ! ( is_a( $product, WC_Product_Subscription::class ) || is_a( $product, WC_Product_Variable_Subscription::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php index 1a0b5e151..97ae9ba44 100644 --- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php +++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php @@ -395,6 +395,12 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl * @return void */ private function add_gateways_support( ContainerInterface $c ): void { + $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); + assert( $subscriptions_helper instanceof SubscriptionHelper ); + if ( ! $subscriptions_helper->plugin_is_active() ) { + return; + } + add_filter( 'woocommerce_paypal_payments_paypal_gateway_supports', function ( array $supports ) use ( $c ): array { From 7c974e62494b2add6b3446709b8e56de810adcc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Thu, 6 Feb 2025 15:08:12 +0100 Subject: [PATCH 14/47] fix php cs --- .../src/PayPalSubscriptionsModule.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 4df30e1c3..ca9944284 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -84,8 +84,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu $cart_product = wc_get_product( $cart_item['product_id'] ); if ( isset( $cart_item['subscription_renewal']['subscription_id'] ) ) { $subscription_renewal = wcs_get_subscription( $cart_item['subscription_renewal']['subscription_id'] ); - $subscription_id = $subscription_renewal->get_meta( 'ppcp_subscription' ) ?? ''; - if ( $subscription_id ) { + if ($subscription_renewal && $subscription_renewal->get_meta( 'ppcp_subscription' ) ) { $pp_subscriptions_product = true; break; } From b7ad5f7f4b28c04577ddee3d20f950121e295810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Thu, 6 Feb 2025 15:08:32 +0100 Subject: [PATCH 15/47] fix php cs --- .../ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index ca9944284..df943a63c 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -84,7 +84,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu $cart_product = wc_get_product( $cart_item['product_id'] ); if ( isset( $cart_item['subscription_renewal']['subscription_id'] ) ) { $subscription_renewal = wcs_get_subscription( $cart_item['subscription_renewal']['subscription_id'] ); - if ($subscription_renewal && $subscription_renewal->get_meta( 'ppcp_subscription' ) ) { + if ( $subscription_renewal && $subscription_renewal->get_meta( 'ppcp_subscription' ) ) { $pp_subscriptions_product = true; break; } From a43f12db6d6e151d88d8939848e701c0f5b3b63d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Fri, 7 Feb 2025 09:37:48 +0100 Subject: [PATCH 16/47] fix missing invoice id --- .../ppcp-wc-gateway/src/Endpoint/CaptureCardPayment.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Endpoint/CaptureCardPayment.php b/modules/ppcp-wc-gateway/src/Endpoint/CaptureCardPayment.php index a2289acee..3b7436f4b 100644 --- a/modules/ppcp-wc-gateway/src/Endpoint/CaptureCardPayment.php +++ b/modules/ppcp-wc-gateway/src/Endpoint/CaptureCardPayment.php @@ -190,7 +190,12 @@ class CaptureCardPayment { throw new RuntimeException( $response->get_error_message() ); } - return json_decode( $response['body'] ); + $decoded_response = json_decode( $response['body'] ); + if ( ! isset( $decoded_response->invoice_id ) ) { + $decoded_response->invoice_id = $invoice_id; + } + + return $decoded_response; } } From 262e711a36bee15f7de9ba0ae24343d0f029fade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Fri, 7 Feb 2025 16:07:44 +0100 Subject: [PATCH 17/47] some improvements --- .../src/PayPalSubscriptionsModule.php | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 48827de8c..805b83492 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -67,7 +67,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu add_filter( 'woocommerce_available_payment_gateways', function ( array $gateways ) use ( $c ) { - if ( ! WC()->cart || WC()->cart->is_empty() || is_account_page() || is_admin() ) { + if ( is_account_page() || is_admin() || wcs_is_manual_renewal_enabled() || ! WC()->cart || WC()->cart->is_empty() ) { return $gateways; } $settings = $c->get( 'wcgateway.settings' ); @@ -121,7 +121,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu add_filter( 'woocommerce_subscription_payment_gateway_supports', function ( bool $payment_gateway_supports, string $payment_gateway_feature, \WC_Subscription $wc_order ): bool { - if ( ! in_array( $payment_gateway_feature, array( 'gateway_scheduled_payments', 'subscription_date_changes' ), true ) ) { + if ( ! in_array( $payment_gateway_feature, array( 'gateway_scheduled_payments', 'subscription_date_changes', 'subscription_amount_changes' ), true ) ) { return $payment_gateway_supports; } @@ -148,7 +148,8 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu add_filter( 'woocommerce_can_subscription_be_updated_to_active', function ( bool $can_be_updated, \WC_Subscription $subscription ) use ( $c ) { - if ( $subscription->payment_method_supports( 'gateway_scheduled_payments' ) && $subscription->get_status() === 'pending-cancel' && $subscription->get_payment_method() === PayPalGateway::ID ) { + $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; + if ( $subscription_id && $subscription->get_status() === 'pending-cancel' ) { return true; } return $can_be_updated; @@ -172,7 +173,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu $order = $c->get( 'session.handler' )->order(); $gateway->add_paypal_meta( $wc_order, $order, $c->get( 'onboarding.environment' ) ); - $subscriptions = function_exists( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order( $wc_order ) : array(); + $subscriptions = wcs_get_subscriptions_for_order( $wc_order ); foreach ( $subscriptions as $subscription ) { $subscription->update_meta_data( 'ppcp_subscription', $paypal_subscription_id ); $subscription->save(); @@ -249,14 +250,9 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return false; } - $settings = $c->get( 'wcgateway.settings' ); - assert( $settings instanceof Settings ); - - $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - $is_paypal_subscription = static function ( $product ) use ( $subscriptions_mode ): bool { + $is_paypal_subscription = static function ( $product ): bool { return $product && in_array( $product->get_type(), array( 'subscription', 'variable-subscription' ), true ) && - 'subscriptions_api' === $subscriptions_mode && $product->get_meta( '_ppcp_enable_subscription_product', true ) === 'yes'; }; From ffb3026d7dfa7814aeee31d53da5e78adb335791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Mon, 10 Feb 2025 17:02:23 +0100 Subject: [PATCH 18/47] some improvements --- .../src/PayPalSubscriptionsModule.php | 84 ++++++++++--------- .../src/WcSubscriptionsModule.php | 5 -- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 805b83492..7dbafb46b 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -60,14 +60,14 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); assert( $subscriptions_helper instanceof SubscriptionHelper ); - if ( ! $subscriptions_helper->plugin_is_active() ) { + if ( ! $subscriptions_helper->plugin_is_active() || wcs_is_manual_renewal_enabled() ) { return true; } add_filter( 'woocommerce_available_payment_gateways', function ( array $gateways ) use ( $c ) { - if ( is_account_page() || is_admin() || wcs_is_manual_renewal_enabled() || ! WC()->cart || WC()->cart->is_empty() ) { + if ( is_account_page() || is_admin() || ! WC()->cart || WC()->cart->is_empty() ) { return $gateways; } $settings = $c->get( 'wcgateway.settings' ); @@ -78,7 +78,6 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return $gateways; } - $subscriptions_product = false; $pp_subscriptions_product = false; foreach ( WC()->cart->get_cart() as $cart_item ) { $cart_product = wc_get_product( $cart_item['product_id'] ); @@ -89,8 +88,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu break; } } elseif ( $cart_product instanceof \WC_Product_Subscription || $cart_product instanceof \WC_Product_Variable_Subscription ) { - $subscriptions_product = true; - if ( $cart_product->get_meta( '_ppcp_enable_subscription_product', true ) === 'yes' ) { + if ( $cart_product->get_meta( '_ppcp_enable_subscription_product' ) === 'yes' ) { $pp_subscriptions_product = true; break; } @@ -106,14 +104,6 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return $gateways; } - if ( $subscriptions_product ) { - foreach ( $gateways as $id => $gateway ) { - if ( $gateway->id === PayPalGateway::ID ) { - unset( $gateways[ $id ] ); - } - } - } - return $gateways; } ); @@ -121,7 +111,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu add_filter( 'woocommerce_subscription_payment_gateway_supports', function ( bool $payment_gateway_supports, string $payment_gateway_feature, \WC_Subscription $wc_order ): bool { - if ( ! in_array( $payment_gateway_feature, array( 'gateway_scheduled_payments', 'subscription_date_changes', 'subscription_amount_changes' ), true ) ) { + if ( ! in_array( $payment_gateway_feature, array( 'gateway_scheduled_payments', 'subscription_date_changes', 'subscription_amount_changes', 'subscription_payment_method_change', 'subscription_payment_method_change_customer', 'subscription_payment_method_change_admin' ), true ) ) { return $payment_gateway_supports; } @@ -141,7 +131,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return false; }, - 10, + 100, 3 ); @@ -158,6 +148,19 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu 2 ); + add_filter( + 'woocommerce_can_subscription_be_updated_to_new-payment-method', + function ( bool $can_be_updated, \WC_Subscription $subscription ) use ( $c ) { + $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; + if ( $subscription_id ) { + return false; + } + return $can_be_updated; + }, + 10, + 2 + ); + add_filter( 'woocommerce_paypal_payments_before_order_process', function ( bool $process, \WC_Payment_Gateway $gateway, \WC_Order $wc_order ) use ( $c ) { @@ -250,9 +253,14 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu return false; } - $is_paypal_subscription = static function ( $product ): bool { + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; + $is_paypal_subscription = static function ( $product ) use ( $subscriptions_mode ): bool { return $product && in_array( $product->get_type(), array( 'subscription', 'variable-subscription' ), true ) && + 'subscriptions_api' === $subscriptions_mode && $product->get_meta( '_ppcp_enable_subscription_product', true ) === 'yes'; }; @@ -290,9 +298,6 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu function( $variation_id ) use ( $c ) { $wcsnonce_save_variations = wc_clean( wp_unslash( $_POST['_wcsnonce_save_variations'] ?? '' ) ); - $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); - assert( $subscriptions_helper instanceof SubscriptionHelper ); - if ( ! WC_Subscriptions_Product::is_subscription( $variation_id ) || ! is_string( $wcsnonce_save_variations ) @@ -537,28 +542,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu } $settings = $c->get( 'wcgateway.settings' ); $subscription_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - if ( $hook !== 'post.php' || $subscription_mode !== 'subscriptions_api' ) { - return; - } - - //phpcs:disable WordPress.Security.NonceVerification.Recommended - $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); - $product = wc_get_product( $post_id ); - if ( ! ( is_a( $product, WC_Product::class ) ) ) { - return; - } - - $subscriptions_helper = $c->get( 'wc-subscriptions.helper' ); - assert( $subscriptions_helper instanceof SubscriptionHelper ); - - if ( - ! ( - is_a( $product, WC_Product_Subscription::class ) - || is_a( $product, WC_Product_Variable_Subscription::class ) - || is_a( $product, WC_Product_Subscription_Variation::class ) - ) - || ! WC_Subscriptions_Product::is_subscription( $product ) - ) { + if ( $hook !== 'post.php' && $hook !== 'post-new.php' && $subscription_mode !== 'subscriptions_api' ) { return; } @@ -571,6 +555,24 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu true ); + //phpcs:disable WordPress.Security.NonceVerification.Recommended + $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); + $product = wc_get_product( $post_id ); + if ( ! ( is_a( $product, WC_Product::class ) ) ) { + return; + } + + if ( + ! ( + is_a( $product, WC_Product_Subscription::class ) + || is_a( $product, WC_Product_Variable_Subscription::class ) + || is_a( $product, WC_Product_Subscription_Variation::class ) + ) + || ! WC_Subscriptions_Product::is_subscription( $product ) + ) { + return; + } + $products = array( $this->set_product_config( $product ) ); if ( $product->get_type() === 'variable-subscription' ) { $products = array(); diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php index 97ae9ba44..d8f7525ed 100644 --- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php +++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php @@ -411,7 +411,6 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl if ( 'disable_paypal_subscriptions' === $subscriptions_mode ) { return $supports; } - return array_merge( $supports, self::VAULT_SUPPORTS_SUBSCRIPTIONS @@ -450,10 +449,6 @@ class WcSubscriptionsModule implements ServiceModule, ExtendingModule, Executabl if ( 'disable_paypal_subscriptions' === $subscriptions_mode ) { return $supports; } - $vaulting_enabled = $settings->has( 'vault_enabled' ) && $settings->get( 'vault_enabled' ); - if ( ! $vaulting_enabled ) { - return $supports; - } return array_merge( $supports, self::VAULT_SUPPORTS_SUBSCRIPTIONS From bbc0b61553025be102fdf3d0b2eedaed6ec594a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 11 Feb 2025 09:56:43 +0100 Subject: [PATCH 19/47] JavaScript improvement so that it works also for new products --- .../resources/js/paypal-subscription.js | 35 ++++---- .../src/PayPalSubscriptionsModule.php | 90 ++++--------------- 2 files changed, 39 insertions(+), 86 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/resources/js/paypal-subscription.js b/modules/ppcp-paypal-subscriptions/resources/js/paypal-subscription.js index ec56861bb..01f242053 100644 --- a/modules/ppcp-paypal-subscriptions/resources/js/paypal-subscription.js +++ b/modules/ppcp-paypal-subscriptions/resources/js/paypal-subscription.js @@ -9,7 +9,7 @@ document.addEventListener( 'DOMContentLoaded', () => { const variableId = children[ i ] .querySelector( 'h3' ) .getElementsByClassName( 'variable_post_id' )[ 0 ].value; - if ( parseInt( variableId ) === productId ) { + if ( variableId === productId ) { children[ i ] .querySelector( '.woocommerce_variable_attributes' ) .getElementsByClassName( @@ -122,21 +122,26 @@ document.addEventListener( 'DOMContentLoaded', () => { jQuery( '.wc_input_subscription_price' ).trigger( 'change' ); - PayPalCommerceGatewayPayPalSubscriptionProducts?.forEach( - ( product ) => { - if ( product.product_connected === 'yes' ) { - disableFields( product.product_id ); - } + let variationProductIds = [ PayPalCommerceGatewayPayPalSubscriptionProducts.product_id ]; + const variationsInput = document.querySelectorAll( '.variable_post_id' ); + for ( let i = 0; i < variationsInput.length; i++ ) { + variationProductIds.push( variationsInput[ i ].value ); + } + variationProductIds?.forEach( + ( productId ) => { const linkBtn = document.getElementById( - `ppcp_enable_subscription_product-${ product.product_id }` + `ppcp_enable_subscription_product-${ productId }` ); + if ( linkBtn.checked && linkBtn.value === 'yes' ) { + disableFields( productId ); + } linkBtn?.addEventListener( 'click', ( event ) => { const unlinkBtnP = document.getElementById( - `ppcp-enable-subscription-${ product.product_id }` + `ppcp-enable-subscription-${ productId }` ); const titleP = document.getElementById( - `ppcp_subscription_plan_name_p-${ product.product_id }` + `ppcp_subscription_plan_name_p-${ productId }` ); if (event.target.checked === true) { if ( unlinkBtnP ) { @@ -156,26 +161,26 @@ document.addEventListener( 'DOMContentLoaded', () => { }); const unlinkBtn = document.getElementById( - `ppcp-unlink-sub-plan-${ product.product_id }` + `ppcp-unlink-sub-plan-${ productId }` ); unlinkBtn?.addEventListener( 'click', ( event ) => { event.preventDefault(); unlinkBtn.disabled = true; const spinner = document.getElementById( - 'spinner-unlink-plan' + `spinner-unlink-plan-${ productId }` ); spinner.style.display = 'inline-block'; - fetch( product.ajax.deactivate_plan.endpoint, { + fetch( PayPalCommerceGatewayPayPalSubscriptionProducts.ajax.deactivate_plan.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'same-origin', body: JSON.stringify( { - nonce: product.ajax.deactivate_plan.nonce, - plan_id: product.plan_id, - product_id: product.product_id, + nonce: PayPalCommerceGatewayPayPalSubscriptionProducts.ajax.deactivate_plan.nonce, + plan_id: linkBtn.dataset.subsPlan, + product_id: productId, } ), } ) .then( function ( res ) { diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index d806213c0..8334c1bbb 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -74,7 +74,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu assert( $settings instanceof Settings ); $subscriptions_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; - if ( $subscriptions_mode === 'disable_paypal_subscriptions' ) { + if ( $subscriptions_mode !== 'subscriptions_api' ) { return $gateways; } @@ -560,52 +560,23 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu 'woocommerce-paypal-payments' ); - //phpcs:disable WordPress.Security.NonceVerification.Recommended - $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); - $product = wc_get_product( $post_id ); - if ( ! ( is_a( $product, WC_Product::class ) ) ) { + $product = wc_get_product(); + if ( ! $product ) { return; } - if ( - ! ( - is_a( $product, WC_Product_Subscription::class ) - || is_a( $product, WC_Product_Variable_Subscription::class ) - || is_a( $product, WC_Product_Subscription_Variation::class ) - ) - || ! WC_Subscriptions_Product::is_subscription( $product ) - ) { - return; - } - - $products = array( $this->set_product_config( $product ) ); - if ( $product->get_type() === 'variable-subscription' ) { - $products = array(); - - /** - * Suppress pslam. - * - * @psalm-suppress TypeDoesNotContainType - * - * WC_Product_Variable_Subscription extends WC_Product_Variable. - */ - assert( $product instanceof WC_Product_Variable ); - $available_variations = $product->get_available_variations(); - foreach ( $available_variations as $variation ) { - /** - * The method is defined in WooCommerce. - * - * @psalm-suppress UndefinedMethod - */ - $variation = wc_get_product_object( 'variation', $variation['variation_id'] ); - $products[] = $this->set_product_config( $variation ); - } - } - wp_localize_script( 'ppcp-paypal-subscription', 'PayPalCommerceGatewayPayPalSubscriptionProducts', - $products + array( + 'ajax' => array( + 'deactivate_plan' => array( + 'endpoint' => \WC_AJAX::get_endpoint( DeactivatePlanEndpoint::ENDPOINT ), + 'nonce' => wp_create_nonce( DeactivatePlanEndpoint::ENDPOINT ), + ), + ), + 'product_id' => $product->get_id(), + ) ); } ); @@ -753,29 +724,6 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu } } - /** - * Returns subscription product configuration. - * - * @param WC_Product $product The product. - * @return array - */ - private function set_product_config( WC_Product $product ): array { - $plan = $product->get_meta( 'ppcp_subscription_plan' ) ?? array(); - $plan_id = $plan['id'] ?? ''; - - return array( - 'product_connected' => $product->get_meta( '_ppcp_enable_subscription_product' ) ?? '', - 'plan_id' => $plan_id, - 'product_id' => $product->get_id(), - 'ajax' => array( - 'deactivate_plan' => array( - 'endpoint' => \WC_AJAX::get_endpoint( DeactivatePlanEndpoint::ENDPOINT ), - 'nonce' => wp_create_nonce( DeactivatePlanEndpoint::ENDPOINT ), - ), - ), - ); - } - /** * Render PayPal Subscriptions fields. * @@ -786,15 +734,18 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu private function render_paypal_subscription_fields( WC_Product $product, Environment $environment ): void { $enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' ); $style = $product->get_type() === 'subscription_variation' ? 'float:left; width:150px;' : ''; + $subscription_product = $product->get_meta( 'ppcp_subscription_product' ); + $subscription_plan = $product->get_meta( 'ppcp_subscription_plan' ); + $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); echo '

'; echo sprintf( // translators: %1$s and %2$s are label open and close tags. esc_html__( '%1$sConnect to PayPal%2$s', 'woocommerce-paypal-payments' ), - '

'; - $subscription_product = $product->get_meta( 'ppcp_subscription_product' ); - $subscription_plan = $product->get_meta( 'ppcp_subscription_plan' ); - $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); if ( $subscription_product || $subscription_plan ) { $display_unlink_p = 'display:none;'; if ( $enable_subscription_product !== 'yes' ) { @@ -817,7 +765,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu // translators: %1$s and %2$s are button and wrapper html tags. esc_html__( '%1$sUnlink PayPal Subscription Plan%2$s', 'woocommerce-paypal-payments' ), '

' + '

' ); echo sprintf( // translators: %1$s and %2$s is open and closing paragraph tag. @@ -845,7 +793,7 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu } } else { $display_plan_name_p = ''; - if ( $enable_subscription_product !== 'yes' && $product->get_name() !== 'AUTO-DRAFT' ) { + if ( $enable_subscription_product !== 'yes' ) { $display_plan_name_p = 'display:none;'; } echo sprintf( From 26b3f68a6f974f71128cc41225ad341298a0ffaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 11 Feb 2025 10:16:38 +0100 Subject: [PATCH 20/47] add missing function to stub --- .psalm/wcs.php | 10 ++++++++++ .../src/PayPalSubscriptionsModule.php | 3 --- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.psalm/wcs.php b/.psalm/wcs.php index 07c3c044c..f952dc116 100644 --- a/.psalm/wcs.php +++ b/.psalm/wcs.php @@ -2094,6 +2094,16 @@ function wcs_order_contains_product($order, $product) */ function wc_get_page_screen_id( $for ) {} +/** + * Checks if manual renewals are enabled. + * + * @since 1.0.0 - Migrated from WooCommerce Subscriptions v4.0.0 + * @return bool Whether manual renewal is enabled. + */ +function wcs_is_manual_renewal_enabled() +{ +} + /** * Subscription Product Variation Class * diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 8334c1bbb..f938cf645 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -12,10 +12,7 @@ namespace WooCommerce\PayPalCommerce\PayPalSubscriptions; use ActionScheduler_Store; use WC_Order; use WC_Product; -use WC_Product_Subscription; use WC_Product_Subscription_Variation; -use WC_Product_Variable; -use WC_Product_Variable_Subscription; use WC_Subscription; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions; From cb2e17491dac10b084e44020239c6f3f41ac295c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Tue, 11 Feb 2025 10:34:08 +0100 Subject: [PATCH 21/47] fix phpcs --- .../src/PayPalSubscriptionsModule.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index f938cf645..d90b54275 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -739,10 +739,10 @@ class PayPalSubscriptionsModule implements ServiceModule, ExtendingModule, Execu echo sprintf( // translators: %1$s and %2$s are label open and close tags. esc_html__( '%1$sConnect to PayPal%2$s', 'woocommerce-paypal-payments' ), - '