From 35150e598c26ce45e672d7327fec48cf34ab9f84 Mon Sep 17 00:00:00 2001 From: Rey C Date: Mon, 15 Dec 2025 14:56:27 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Fix:=20Add=20a=20new=20button=20for=20Strip?= =?UTF-8?q?e=20integration=20to=20"Fetch=20Products=E2=80=9D=20in=20the=20?= =?UTF-8?q?WPUM=20Stripe=20settings=20to=20refresh=20the=20transient=20cac?= =?UTF-8?q?he?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add product.created, product.updated, and product.deleted stripe event hook handler @polevaultweb Resolves #416 --- includes/integrations/stripe/Settings.php | 70 ++++++++++++++++++- .../stripe/StripeWebhookController.php | 64 +++++++++++++++++ 2 files changed, 132 insertions(+), 2 deletions(-) diff --git a/includes/integrations/stripe/Settings.php b/includes/integrations/stripe/Settings.php index 9dd98a99..fb6ca4cd 100644 --- a/includes/integrations/stripe/Settings.php +++ b/includes/integrations/stripe/Settings.php @@ -45,6 +45,7 @@ public function init() { add_action( 'update_option_wpum_settings', array( $this, 'flush_product_cache' ) ); add_action( 'wp_ajax_wpum_stripe_connect_account_info', array( $this, 'stripe_connect_account_info_ajax_response' ) ); add_action( 'admin_init', array( $this, 'handle_stripe_connect_disconnect' ) ); + add_action( 'admin_init', array( $this, 'handle_fetch_stripe_products' ) ); } /** @@ -256,11 +257,22 @@ public function register_settings( $settings ) { 'type' => 'hidden', ); + $fetch_products_url = add_query_arg( + array( + 'page' => 'wpum-settings', + 'fetch-products' => true + ), + admin_url( 'users.php' ) + ); + + $fetch_products_url = wp_nonce_url( $fetch_products_url, 'wpum-stripe-fetch-products' ); + $fetch_product_btn = sprintf( '

Fetch Stripe Products

', esc_url( $fetch_products_url ) ); + if ( $this->products && $this->products->totalRecurringProducts() > 1 ) { $settings['stripe'][] = array( 'id' => 'test_stripe_products', 'name' => __( 'Eligible Products', 'wp-user-manager' ), - 'desc' => sprintf( 'Select the product prices users can subscribe to on the account page. This should be the same as the products defined in the Stripe Customer Portal Subscription settings.', 'https://wpusermanager.com/article/337-recurring-subscriptions/#configure-eligible-products' ), + 'desc' => sprintf( 'Select the product prices users can subscribe to on the account page. This should be the same as the products defined in the Stripe Customer Portal Subscription settings. %s', 'https://wpusermanager.com/article/337-recurring-subscriptions/#configure-eligible-products ', $fetch_product_btn ), 'type' => 'multiselect', 'multiple' => true, 'options' => $this->products->get_plans(), @@ -280,7 +292,7 @@ public function register_settings( $settings ) { $settings['stripe'][] = array( 'id' => 'live_stripe_products', 'name' => __( 'Eligible Products', 'wp-user-manager' ), - 'desc' => sprintf( 'Select the product prices users can subscribe to on the account page. This should be the same as the products defined in the Stripe Customer Portal Subscription settings.', 'https://wpusermanager.com/article/337-recurring-subscriptions/#configure-eligible-products' ), + 'desc' => sprintf( 'Select the product prices users can subscribe to on the account page. This should be the same as the products defined in the Stripe Customer Portal Subscription settings. %s', 'https://wpusermanager.com/article/337-recurring-subscriptions/#configure-eligible-products', $fetch_product_btn ), 'type' => 'multiselect', 'multiple' => true, 'options' => $this->products->get_plans(), @@ -602,4 +614,58 @@ public function handle_stripe_connect_disconnect() { return wp_safe_redirect( esc_url_raw( $redirect ) ); } + + /** + * Fetch Stripe Products + */ + public function handle_fetch_stripe_products() { + $page = filter_input( INPUT_GET, 'page', FILTER_UNSAFE_RAW ); + $page = sanitize_text_field( $page ); + + if ( empty( $page ) ) { + return; + } + + if ( 'wpum-settings' !== $page ) { + return; + } + + $fetch_products = filter_input( INPUT_GET, 'fetch-products', FILTER_UNSAFE_RAW ); + $fetch_products = sanitize_text_field( $fetch_products ); + + if ( empty( $fetch_products ) ) { + return; + } + + // Current user cannot handle this request, bail. + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + $nonce = filter_input( INPUT_GET, '_wpnonce', FILTER_UNSAFE_RAW ); + $nonce = sanitize_text_field( $nonce ); + + if ( empty( $nonce ) ) { + return; + } + + if ( ! wp_verify_nonce( $nonce, 'wpum-stripe-fetch-products' ) ) { + return; + } + + // Clear product cache + $this->flush_product_cache(); + + $products = new Products( $this->connect->get_stripe_secret(), $this->connect->get_gateway_mode() ); + $products->all( true ); + + $redirect = remove_query_arg( + array( + '_wpnonce', + 'fetch-products' + ) + ); + + return wp_safe_redirect( esc_url_raw( $redirect ) ); + } } diff --git a/includes/integrations/stripe/StripeWebhookController.php b/includes/integrations/stripe/StripeWebhookController.php index ab94ac3c..ea7bfe45 100644 --- a/includes/integrations/stripe/StripeWebhookController.php +++ b/includes/integrations/stripe/StripeWebhookController.php @@ -17,6 +17,7 @@ use WPUserManager\Stripe\Controllers\Subscriptions; use WPUserManager\Stripe\Models\Product; use WPUserManager\Stripe\Models\User; +use WPUserManager\Stripe\Controllers\products; /** * StripeWebhookController @@ -38,6 +39,16 @@ class StripeWebhookController { */ protected $invoices; + /** + * @var string + */ + protected $gateway_mode; + + /** + * @var string + */ + protected $secret_key; + /** * StripeWebhookController constructor. * @@ -53,6 +64,8 @@ public function __construct( $secret_key, $webhook_secret, $gateway_mode ) { $this->subscriptions = new Subscriptions( $gateway_mode ); $this->invoices = new Invoices( $gateway_mode ); $this->webhook_secret = $webhook_secret; + $this->gateway_mode = $gateway_mode; + $this->secret_key = $secret_key; } /** @@ -310,4 +323,55 @@ protected function handleInvoicePaymentSucceeded( $payload ) { return new \WP_REST_Response( 'Webhook handled', 200 ); } + + /** + * Handle the product.created webhook to update the cached Stripe products. + * + * @param array $payload + * + * @return \WP_REST_Response + * @throws \Exception + */ + protected function handleProductCreated( $payload ) { + $products = new Products( $this->secret_key, $this->gateway_mode ); + $products->all( true ); + + do_action( 'wpum_stripe_webhook_product_updated', $subscription ); + + return new \WP_REST_Response( 'Webhook handled', 200 ); + } + + /** + * Handle the product.deleted webhook to update the cached Stripe products. + * + * @param array $payload + * + * @return \WP_REST_Response + * @throws \Exception + */ + protected function handleProductDeleted( $payload ) { + $products = new Products( $this->secret_key, $this->gateway_mode ); + $products->all( true ); + + do_action( 'wpum_stripe_webhook_product_updated', $subscription ); + + return new \WP_REST_Response( 'Webhook handled', 200 ); + } + + /** + * Handle the product.updated webhook to update the cached Stripe products. + * + * @param array $payload + * + * @return \WP_REST_Response + * @throws \Exception + */ + protected function handleProductUpdated( $payload ) { + $products = new Products( $this->secret_key, $this->gateway_mode ); + $products->all( true ); + + do_action( 'wpum_stripe_webhook_product_updated', $subscription ); + + return new \WP_REST_Response( 'Webhook handled', 200 ); + } } From a6df7b747c83eece247cf018f48ca178c7d33d44 Mon Sep 17 00:00:00 2001 From: Rey C Date: Mon, 15 Dec 2025 15:31:45 +0800 Subject: [PATCH 2/2] Fix PHPCS validation error @polevaultweb --- includes/integrations/stripe/Settings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/integrations/stripe/Settings.php b/includes/integrations/stripe/Settings.php index fb6ca4cd..ee53761a 100644 --- a/includes/integrations/stripe/Settings.php +++ b/includes/integrations/stripe/Settings.php @@ -260,7 +260,7 @@ public function register_settings( $settings ) { $fetch_products_url = add_query_arg( array( 'page' => 'wpum-settings', - 'fetch-products' => true + 'fetch-products' => true, ), admin_url( 'users.php' ) ); @@ -662,7 +662,7 @@ public function handle_fetch_stripe_products() { $redirect = remove_query_arg( array( '_wpnonce', - 'fetch-products' + 'fetch-products', ) );