Skip to content

Fix: Add a new button for Stripe integration to "Fetch Products” in t…#417

Open
reygcalantaol wants to merge 8 commits intodevelopfrom
Stripe-product-is-not-showing-in-registration-form
Open

Fix: Add a new button for Stripe integration to "Fetch Products” in t…#417
reygcalantaol wants to merge 8 commits intodevelopfrom
Stripe-product-is-not-showing-in-registration-form

Conversation

@reygcalantaol
Copy link
Copy Markdown
Collaborator

@reygcalantaol reygcalantaol commented Dec 15, 2025

Resolves #416

Summary

Adds a Fetch Stripe Products button to the Stripe settings page and webhook handlers to keep the local product cache in sync when products change in Stripe.

Changes:

  1. New "Fetch Stripe Products" button on the Stripe settings page — flushes and re-fetches products from the Stripe API
  2. New webhook handlers for product.created, product.updated, and product.deleted events — automatically refreshes the product cache when Stripe products change

Manual Test Plan

Prerequisites

  • WP User Manager + Stripe addon active
  • A connected Stripe account (test mode is fine)
  • At least one product/price in Stripe

1. Verify Fetch Products button appears

  • Go to Users > Settings > Stripe
  • Scroll to the Eligible Products section
  • Expected: A "Fetch Stripe Products" button appears below the product multi-select
  • Expected: The button is a standard WordPress secondary button style

2. Test manual product fetch

  • In the Stripe Dashboard, create a new product with a recurring price
  • Back in WordPress, click Fetch Stripe Products
  • Expected: The page reloads, redirecting back to the Stripe settings tab
  • Expected: The new product/price appears in the Eligible Products dropdown
  • Expected: No errors or warnings displayed

3. Test with no new products

  • Click Fetch Stripe Products again without changing anything in Stripe
  • Expected: Page reloads cleanly, no errors — existing products still listed

4. Test security (nonce/permissions)

  • Copy the Fetch Products URL from the button
  • Change the _wpnonce value in the URL to something invalid
  • Visit the modified URL
  • Expected: Nothing happens — the handler silently returns (nonce check fails)
  • Log in as a non-admin user (e.g. Subscriber)
  • Visit the original Fetch Products URL
  • Expected: Nothing happens — the handler requires manage_options capability

5. Test webhook sync (if webhook endpoint configured)

  • In the Stripe Dashboard, update a product name
  • Expected: The product name updates in the WPUM Eligible Products list (after the webhook fires)
  • Delete a product in Stripe
  • Expected: The product is removed from the list after the webhook fires
  • (Webhooks require the WPUM Stripe webhook endpoint to be configured — skip if not set up)

6. Test both gateway modes

  • If both test and live mode sections show Eligible Products, verify the Fetch button appears in both
  • Expected: Each mode has its own Fetch button that fetches products for that mode

WPUnit Test Coverage

21 tests in tests/wpunit/Stripe/StripeFetchProductsTest.php:

  • handle_fetch_stripe_products method exists and is hooked to admin_init
  • Security guards: nonce verification, manage_options capability check, query param validation
  • Webhook handler methods exist (handleProductCreated, handleProductDeleted, handleProductUpdated)
  • Webhook handlers are protected (only accessible via dispatch)
  • Studly case mapping routes product.* events to correct handler methods

🤖 Generated with Claude Code

reygcalantaol and others added 8 commits December 15, 2025 14:56
…he WPUM Stripe settings to refresh the transient cache

- Add product.created, product.updated, and product.deleted stripe event hook handler

@polevaultweb

Resolves #416
…hooks

- Fix `use` statement: `Controllers\products` → `Controllers\Products`
- Replace undefined `$subscription` with `$payload` in handleProductCreated,
  handleProductDeleted, and handleProductUpdated webhook handlers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Merge develop into PR branch to resolve conflicts
- Add stripe-fetch-products.spec.ts with 3 tests:
  - Fetch Products button visible on Stripe settings page
  - Button click refreshes products and redirects back
  - Non-admin users cannot access the fetch endpoint

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…l transient delete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds admin UX + backend hooks to refresh Stripe product caching in WPUM Stripe integration, including a manual “Fetch Stripe Products” action and webhook-driven cache refresh when products change in Stripe.

Changes:

  • Adds a “Fetch Stripe Products” button on the Stripe settings tab that flushes and re-fetches products from Stripe.
  • Adds webhook handlers for product.created, product.updated, and product.deleted to refresh the cached products list.
  • Adds WPUnit + Playwright E2E coverage around the fetch handler behavior and webhook method wiring.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
includes/integrations/stripe/Settings.php Adds fetch-products button URL + admin_init handler to flush and refetch Stripe products.
includes/integrations/stripe/StripeWebhookController.php Adds product webhook handlers and stores gateway mode/secret key for refreshing products cache.
tests/wpunit/Stripe/StripeFetchProductsTest.php Introduces WPUnit coverage for handler guards and webhook handler method existence/visibility.
tests/e2e/stripe-fetch-products.spec.ts Adds Playwright E2E coverage for button presence, redirect behavior, and permissions guard.
tests/e2e/helpers/stripe.ts Adjusts Stripe settings helper to tolerate transient deletion failures in some environments.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +75 to +79
public function test_init_registers_admin_init_hook_for_fetch_products() {
// Remove any existing hooks from previous calls, then re-init.
remove_all_actions( 'admin_init' );

$this->settings->init();
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove_all_actions('admin_init') wipes all admin_init handlers globally and can leak into other wpunit tests, causing unrelated failures depending on execution order. Prefer asserting the hook registration without clearing global hooks, or remove only the specific callbacks you add within this test.

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +93
public function test_init_registers_admin_init_hook_for_disconnect() {
remove_all_actions( 'admin_init' );

$this->settings->init();

Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove_all_actions('admin_init') wipes all admin_init handlers globally and can leak into other wpunit tests, causing unrelated failures depending on execution order. Prefer asserting the hook registration without clearing global hooks, or remove only the specific callbacks you add within this test.

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +8
/**
* Tests for the Stripe fetch-products handler and webhook controller methods
* introduced in PR #417.
*
* Verifies security guards (nonce, capability, query parameter) on
* Settings::handle_fetch_stripe_products() and confirms the new webhook
* handler methods exist on StripeWebhookController.
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file header comment references "PR #417", but this change set is tied to issue #416 and the PR title suggests a different number. Update/remove the PR number to avoid stale or misleading test documentation.

Copilot uses AI. Check for mistakes.
Comment on lines +335 to +342
protected function handleProductCreated( $payload ) {
$products = new Products( $this->secret_key, $this->gateway_mode );
$products->all( true );

do_action( 'wpum_stripe_webhook_product_updated', $payload );

return new \WP_REST_Response( 'Webhook handled', 200 );
}
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three product webhook handlers duplicate the same cache-refresh logic and action dispatch. Consider extracting the shared "refresh products cache" behavior into a single protected/private helper to reduce maintenance risk if this flow changes later.

Copilot uses AI. Check for mistakes.
Comment on lines 273 to 276
'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 <a target="_blank" href="%s">Stripe Customer Portal Subscription settings</a>.', '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 <a target="_blank" href="%s">Stripe Customer Portal Subscription settings</a>. %s', 'https://wpusermanager.com/article/337-recurring-subscriptions/#configure-eligible-products ', $fetch_product_btn ),
'type' => 'multiselect',
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation URL in this description has a trailing space at the end of the href string, which will be URL-encoded and can break the link target. Remove the trailing space so the anchor points to the intended section.

Copilot uses AI. Check for mistakes.
Comment on lines +656 to +661
// Clear product cache
$this->flush_product_cache();

$products = new Products( $this->connect->get_stripe_secret(), $this->connect->get_gateway_mode() );
$products->all( true );

Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handler triggers a Stripe API fetch via Products::all(true). Products::getProducts() does not catch exceptions from the per-product Price::all() call, so an API error here can throw and break the settings page load. Consider wrapping the fetch in a try/catch and redirecting back (optionally with an admin_notice / query flag) when the refresh fails.

Copilot uses AI. Check for mistakes.
'_wpnonce',
'fetch-products',
)
);
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After removing the query args, the redirect URL no longer includes the "#/stripe" fragment, so users may be redirected away from the Stripe tab (fragments are not sent to the server). Consider appending "#/stripe" to the redirect target so the UI reliably returns to the Stripe settings tab after fetching.

Suggested change
);
);
$redirect .= '#/stripe';

Copilot uses AI. Check for mistakes.
)
);

return wp_safe_redirect( esc_url_raw( $redirect ) );
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wp_safe_redirect() does not terminate execution. To avoid any additional processing after sending the Location header (and to match common WP redirect patterns), call exit immediately after the redirect.

Suggested change
return wp_safe_redirect( esc_url_raw( $redirect ) );
wp_safe_redirect( esc_url_raw( $redirect ) );
exit;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a new button for Stripe integration to "Fetch Products” in the WPUM Stripe settings to refresh the transient cache.

3 participants