From 96f6ad715a502486e93b71c8a3fe6acc36771d9b Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 15 May 2023 11:53:25 +0200 Subject: [PATCH 1/3] Cache ppec subscriptions check response --- modules/ppcp-compat/src/PPEC/PPECHelper.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-compat/src/PPEC/PPECHelper.php b/modules/ppcp-compat/src/PPEC/PPECHelper.php index 71e16e544..70e882457 100644 --- a/modules/ppcp-compat/src/PPEC/PPECHelper.php +++ b/modules/ppcp-compat/src/PPEC/PPECHelper.php @@ -67,8 +67,12 @@ class PPECHelper { * @return bool */ public static function site_has_ppec_subscriptions() { - global $wpdb; + $has_ppec_subscriptions = get_transient( 'ppcp_has_ppec_subscriptions' ); + if ( $has_ppec_subscriptions !== false ) { + return $has_ppec_subscriptions === 'true'; + } + global $wpdb; $result = $wpdb->get_var( $wpdb->prepare( "SELECT 1 FROM {$wpdb->posts} p JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID @@ -80,6 +84,12 @@ class PPECHelper { ) ); + set_transient( + 'ppcp_has_ppec_subscriptions', + ! empty( $result ) ? 'true' : 'false', + 3 * MONTH_IN_SECONDS + ); + return ! empty( $result ); } @@ -92,7 +102,9 @@ class PPECHelper { /** * The filter returning whether the compatibility layer for PPEC Subscriptions should be initialized. */ - return ( ! self::is_gateway_available() ) && self::site_has_ppec_subscriptions() && apply_filters( 'woocommerce_paypal_payments_process_legacy_subscriptions', true ); + return ( ! self::is_gateway_available() ) + && self::site_has_ppec_subscriptions() + && apply_filters( 'woocommerce_paypal_payments_process_legacy_subscriptions', true ); } } From 86b7e5a1b8abdd8b7dde10ff4524ce8882134a1d Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 15 May 2023 11:56:39 +0200 Subject: [PATCH 2/3] Fix phpunit --- tests/PHPUnit/TestCase.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/PHPUnit/TestCase.php b/tests/PHPUnit/TestCase.php index f13497885..f2e4867c7 100644 --- a/tests/PHPUnit/TestCase.php +++ b/tests/PHPUnit/TestCase.php @@ -33,6 +33,7 @@ class TestCase extends \PHPUnit\Framework\TestCase }); when('get_plugin_data')->justReturn(['Version' => '1.0']); when('plugin_basename')->justReturn('woocommerce-paypal-payments/woocommerce-paypal-payments.php'); + when('get_transient')->returnArg(); setUp(); } From a028eafeef66ffe0ff625d6170613a8fe88fa23f Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 16 May 2023 10:15:42 +0300 Subject: [PATCH 3/3] Cache webhook verification results Looks like `permission_callback` can be called multiple times in some cases/newer WP, resulting in difficult to read logs and other issues, such as slower request handling or possible lack of idempotence (first returned true, but then request failed and returned false). So now caching it in a variable. --- .../src/IncomingWebhookEndpoint.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/modules/ppcp-webhooks/src/IncomingWebhookEndpoint.php b/modules/ppcp-webhooks/src/IncomingWebhookEndpoint.php index 4a7631572..b228139e0 100644 --- a/modules/ppcp-webhooks/src/IncomingWebhookEndpoint.php +++ b/modules/ppcp-webhooks/src/IncomingWebhookEndpoint.php @@ -83,6 +83,14 @@ class IncomingWebhookEndpoint { */ private $last_webhook_event_storage; + /** + * Cached webhook verification results + * to avoid repeating requests when permission_callback is called multiple times. + * + * @var array + */ + private $verification_results = array(); + /** * IncomingWebhookEndpoint constructor. * @@ -160,7 +168,17 @@ class IncomingWebhookEndpoint { try { $event = $this->event_from_request( $request ); + } catch ( RuntimeException $exception ) { + $this->logger->error( 'Webhook parsing failed: ' . $exception->getMessage() ); + return false; + } + $cache_key = $event->id(); + if ( isset( $this->verification_results[ $cache_key ] ) ) { + return $this->verification_results[ $cache_key ]; + } + + try { if ( $this->simulation->is_simulation_event( $event ) ) { return true; } @@ -169,9 +187,11 @@ class IncomingWebhookEndpoint { if ( ! $result ) { $this->logger->error( 'Webhook verification failed.' ); } + $this->verification_results[ $cache_key ] = $result; return $result; } catch ( RuntimeException $exception ) { $this->logger->error( 'Webhook verification failed: ' . $exception->getMessage() ); + $this->verification_results[ $cache_key ] = false; return false; } }