Skip to content

Commit a037f2e

Browse files
committed
fix: reduce number of API calls
1 parent 99e9e11 commit a037f2e

File tree

5 files changed

+163
-55
lines changed

5 files changed

+163
-55
lines changed

includes/AjaxHandler.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -522,11 +522,11 @@ private function get_services() {
522522
$profile_service = new ProfileService( $api_key );
523523
$reader_service = new ReaderService( $api_key );
524524

525-
// Set merchant ID if available.
526-
$merchant_code = $profile_service->get_merchant_code();
527-
if ( $merchant_code ) {
528-
$reader_service->set_merchant_id( $merchant_code );
529-
}
525+
// Set the profile service on the reader service for lazy merchant ID loading
526+
$reader_service->set_profile_service( $profile_service );
527+
528+
// Note: We no longer fetch merchant_code here to avoid unnecessary API calls.
529+
// The merchant_code will be fetched lazily when needed and cached.
530530

531531
return array(
532532
'profile' => $profile_service,

includes/Gateway.php

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -254,21 +254,23 @@ public function payment_fields(): void {
254254
// Description for the payment method.
255255
echo '<p>' . esc_html( $this->get_option( 'description' ) ) . '</p>';
256256

257-
// Check if merchant_id is available
258-
if ( ! $this->reader_service || ! $this->reader_service->get_merchant_id() ) {
259-
// Try to reinitialize services if they're missing
260-
if ( ! empty( $this->api_key ) ) {
261-
$this->init_services();
262-
}
263-
264-
// Check again after potential reinitialization
265-
if ( ! $this->reader_service || ! $this->reader_service->get_merchant_id() ) {
266-
echo '<div class="woocommerce-error">';
267-
echo '<p>' . esc_html__( 'SumUp Terminal is not properly configured. Please contact the store administrator.', 'sumup-terminal-for-woocommerce' ) . '</p>';
268-
echo '</div>';
257+
// Check if services are available and API key is valid
258+
if ( ! $this->profile_service || ! $this->reader_service || empty( $this->api_key ) ) {
259+
echo '<div class="woocommerce-error">';
260+
echo '<p>' . esc_html__( 'SumUp Terminal is not properly configured. Please contact the store administrator.', 'sumup-terminal-for-woocommerce' ) . '</p>';
261+
echo '</div>';
269262

270-
return;
271-
}
263+
return;
264+
}
265+
266+
// Check if we can get the merchant code (this will use caching)
267+
$merchant_code = $this->profile_service->get_merchant_code();
268+
if ( ! $merchant_code ) {
269+
echo '<div class="woocommerce-error">';
270+
echo '<p>' . esc_html__( 'SumUp Terminal is not properly configured. Please contact the store administrator.', 'sumup-terminal-for-woocommerce' ) . '</p>';
271+
echo '</div>';
272+
273+
return;
272274
}
273275

274276
// Get available readers
@@ -347,10 +349,17 @@ public function payment_fields(): void {
347349
* @return bool
348350
*/
349351
public function process_admin_options() {
350-
$result = parent::process_admin_options();
352+
$old_api_key = $this->api_key;
353+
$result = parent::process_admin_options();
351354

352355
// Reload the API key and reinitialize services.
353356
$this->api_key = $this->get_option( 'api_key' );
357+
358+
// Clear cache if API key changed
359+
if ( $old_api_key !== $this->api_key && $this->profile_service ) {
360+
$this->profile_service->clear_cache();
361+
}
362+
354363
$this->init_services();
355364

356365
return $result;
@@ -467,14 +476,11 @@ private function init_services(): void {
467476
$this->profile_service = new ProfileService( $this->api_key );
468477
$this->reader_service = new ReaderService( $this->api_key );
469478

470-
// Set merchant ID if available and API key is set.
471-
if ( ! empty( $this->api_key ) ) {
472-
$merchant_code = $this->profile_service->get_merchant_code();
473-
474-
if ( $merchant_code ) {
475-
$this->reader_service->set_merchant_id( $merchant_code );
476-
}
477-
}
479+
// Set the profile service on the reader service for lazy merchant ID loading
480+
$this->reader_service->set_profile_service( $this->profile_service );
481+
482+
// Note: We no longer fetch merchant_code here to avoid unnecessary API calls.
483+
// The merchant_code will be fetched lazily when needed and cached.
478484
}
479485

480486

@@ -489,10 +495,10 @@ private function get_connection_status_html() {
489495
return $this->render_status_card( 'error', __( 'API Key Required', 'sumup-terminal-for-woocommerce' ), __( 'Enter your SumUp API Key above to connect to SumUp.', 'sumup-terminal-for-woocommerce' ) );
490496
}
491497

492-
// Test the API key.
493-
$api_key_valid = $this->test_api_key();
498+
// Get the profile once and use it for all checks (this will use caching)
499+
$profile = $this->profile_service->get_profile();
494500

495-
if ( ! $api_key_valid ) {
501+
if ( ! $profile ) {
496502
return $this->render_status_card( 'error', __( 'Connection Failed', 'sumup-terminal-for-woocommerce' ), __( 'Unable to connect to SumUp. Please check your API key.', 'sumup-terminal-for-woocommerce' ) );
497503
}
498504

@@ -502,9 +508,9 @@ private function get_connection_status_html() {
502508
// 1. API Connection Status.
503509
$html .= $this->render_status_card( 'success', __( 'Connected to SumUp', 'sumup-terminal-for-woocommerce' ), __( 'API key is valid and ready to process payments.', 'sumup-terminal-for-woocommerce' ) );
504510

505-
// 2. Merchant Information.
511+
// 2. Merchant Information (pass the profile to avoid another API call).
506512
try {
507-
$html .= $this->get_merchant_status_html();
513+
$html .= $this->get_merchant_status_html( $profile );
508514
} catch ( \Exception $e ) {
509515
// Silently continue if merchant info fails
510516
}
@@ -555,10 +561,15 @@ private function render_status_card( $type, $title, $message, $actions = '' ) {
555561
/**
556562
* Get merchant status HTML.
557563
*
564+
* @param null|array $profile Optional profile data to use instead of fetching.
565+
*
558566
* @return string HTML for merchant status.
559567
*/
560-
private function get_merchant_status_html() {
561-
$profile = $this->profile_service->get_profile();
568+
private function get_merchant_status_html( $profile = null ) {
569+
// Use provided profile or fetch if not provided
570+
if ( null === $profile ) {
571+
$profile = $this->profile_service->get_profile();
572+
}
562573

563574
if ( ! $profile ) {
564575
return $this->render_status_card( 'error', __( 'Merchant Profile Error', 'sumup-terminal-for-woocommerce' ), __( 'Unable to retrieve merchant profile information.', 'sumup-terminal-for-woocommerce' ) );

includes/Services/ProfileService.php

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,57 @@
1111
*/
1212
class ProfileService extends HttpClient {
1313
/**
14-
* Get the current user's profile.
14+
* @var null|array Cached profile data for the current request.
15+
*/
16+
private $cached_profile = null;
17+
18+
/**
19+
* @var bool Whether we've attempted to load the profile in this request.
20+
*/
21+
private $profile_loaded = false;
22+
23+
/**
24+
* Get the current user's profile with caching.
25+
*
26+
* @param bool $force_refresh Whether to force a fresh API call, bypassing cache.
1527
*
1628
* @return array|false Profile data or false on failure.
1729
*/
18-
public function get_profile() {
30+
public function get_profile( $force_refresh = false ) {
1931
if ( ! $this->has_api_key() ) {
2032
return false;
2133
}
2234

23-
return parent::get( '/me' );
35+
// Return cached data if available and not forcing refresh
36+
if ( ! $force_refresh && $this->profile_loaded ) {
37+
return $this->cached_profile;
38+
}
39+
40+
// Try to get from WordPress transient cache first (unless forcing refresh)
41+
$cache_key = 'sumup_profile_' . md5( $this->api_key );
42+
if ( ! $force_refresh ) {
43+
$cached_data = get_transient( $cache_key );
44+
if ( false !== $cached_data ) {
45+
$this->cached_profile = $cached_data;
46+
$this->profile_loaded = true;
47+
48+
return $this->cached_profile;
49+
}
50+
}
51+
52+
// Make API call to get fresh data
53+
$profile = parent::get( '/me' );
54+
55+
// Cache the result (even if false, to avoid repeated failed calls)
56+
$this->cached_profile = $profile;
57+
$this->profile_loaded = true;
58+
59+
// Store in WordPress transient for 5 minutes if successful
60+
if ( false !== $profile ) {
61+
set_transient( $cache_key, $profile, 5 * MINUTE_IN_SECONDS );
62+
}
63+
64+
return $this->cached_profile;
2465
}
2566

2667
/**
@@ -35,12 +76,14 @@ public function test_api_key() {
3576
}
3677

3778
/**
38-
* Get the merchant code from the user's profile.
79+
* Get the merchant code from the user's profile with caching.
80+
*
81+
* @param bool $force_refresh Whether to force a fresh API call.
3982
*
4083
* @return false|string Merchant code or false on failure.
4184
*/
42-
public function get_merchant_code() {
43-
$profile = $this->get_profile();
85+
public function get_merchant_code( $force_refresh = false ) {
86+
$profile = $this->get_profile( $force_refresh );
4487

4588
// Check if merchant profile exists and has merchant_code
4689
if ( $profile && isset( $profile['merchant_profile']['merchant_code'] ) ) {
@@ -53,13 +96,29 @@ public function get_merchant_code() {
5396
return false;
5497
}
5598

99+
/**
100+
* Clear the profile cache.
101+
* Should be called when the API key changes.
102+
*/
103+
public function clear_cache(): void {
104+
// Clear in-memory cache
105+
$this->cached_profile = null;
106+
$this->profile_loaded = false;
107+
108+
// Clear WordPress transient cache
109+
$cache_key = 'sumup_profile_' . md5( $this->api_key );
110+
delete_transient( $cache_key );
111+
}
112+
56113
/**
57114
* Get the merchant profile information.
58115
*
116+
* @param bool $force_refresh Whether to force a fresh API call.
117+
*
59118
* @return array|false Merchant profile data or false on failure.
60119
*/
61-
public function get_merchant_profile() {
62-
$merchant_code = $this->get_merchant_code();
120+
public function get_merchant_profile( $force_refresh = false ) {
121+
$merchant_code = $this->get_merchant_code( $force_refresh );
63122

64123
if ( ! $merchant_code ) {
65124
return false;

includes/Services/ReaderService.php

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,27 @@
1212
* Class ReaderService.
1313
*/
1414
class ReaderService extends HttpClient {
15+
/**
16+
* @var null|ProfileService Profile service instance for lazy loading merchant ID.
17+
*/
18+
private $profile_service;
19+
20+
/**
21+
* Set the profile service for lazy loading merchant ID.
22+
*
23+
* @param ProfileService $profile_service Profile service instance.
24+
*/
25+
public function set_profile_service( ProfileService $profile_service ): void {
26+
$this->profile_service = $profile_service;
27+
}
28+
1529
/**
1630
* Get all readers for the merchant.
1731
*
1832
* @return array|false Readers data or false on failure.
1933
*/
2034
public function get_all() {
21-
if ( ! $this->get_merchant_id() ) {
35+
if ( ! $this->ensure_merchant_id() ) {
2236
return false;
2337
}
2438

@@ -44,7 +58,7 @@ public function get_all() {
4458
* @return array|false Reader data or false on failure.
4559
*/
4660
public function get_reader( $reader_id ) {
47-
if ( ! $this->get_merchant_id() ) {
61+
if ( ! $this->ensure_merchant_id() ) {
4862
return false;
4963
}
5064

@@ -59,7 +73,7 @@ public function get_reader( $reader_id ) {
5973
* @return array|false Reader data or false on failure.
6074
*/
6175
public function create( array $data ) {
62-
if ( ! $this->get_merchant_id() ) {
76+
if ( ! $this->ensure_merchant_id() ) {
6377
return false;
6478
}
6579

@@ -74,7 +88,7 @@ public function create( array $data ) {
7488
* @return bool True on success, false on failure.
7589
*/
7690
public function destroy( $reader_id ) {
77-
if ( ! $this->get_merchant_id() ) {
91+
if ( ! $this->ensure_merchant_id() ) {
7892
return false;
7993
}
8094

@@ -92,7 +106,7 @@ public function destroy( $reader_id ) {
92106
* @return array|false Checkout response or false on failure.
93107
*/
94108
public function checkout( $reader_id, $checkout_data ) {
95-
if ( ! $this->get_merchant_id() ) {
109+
if ( ! $this->ensure_merchant_id() ) {
96110
return false;
97111
}
98112

@@ -111,7 +125,7 @@ public function checkout( $reader_id, $checkout_data ) {
111125
* @return array|false Checkout data or false on failure.
112126
*/
113127
public function create_checkout_for_order( $order, $reader_id ) {
114-
if ( ! $this->has_api_key() || ! $this->get_merchant_id() ) {
128+
if ( ! $this->has_api_key() || ! $this->ensure_merchant_id() ) {
115129
return false;
116130
}
117131

@@ -172,7 +186,7 @@ public function create_checkout_for_order( $order, $reader_id ) {
172186
* @return bool True if terminate request was accepted, false if rejected.
173187
*/
174188
public function cancel_checkout( $reader_id ) {
175-
if ( ! $this->get_merchant_id() ) {
189+
if ( ! $this->ensure_merchant_id() ) {
176190
return false;
177191
}
178192

@@ -195,7 +209,7 @@ public function cancel_checkout( $reader_id ) {
195209
* @return array|false Reader status or false on failure.
196210
*/
197211
public function get_status( $reader_id ) {
198-
if ( ! $this->get_merchant_id() ) {
212+
if ( ! $this->ensure_merchant_id() ) {
199213
return false;
200214
}
201215

@@ -210,7 +224,7 @@ public function get_status( $reader_id ) {
210224
* @return array|false Connection response or false on failure.
211225
*/
212226
public function connect( $reader_id ) {
213-
if ( ! $this->get_merchant_id() ) {
227+
if ( ! $this->ensure_merchant_id() ) {
214228
return false;
215229
}
216230

@@ -225,7 +239,7 @@ public function connect( $reader_id ) {
225239
* @return bool True on success, false on failure.
226240
*/
227241
public function disconnect( $reader_id ) {
228-
if ( ! $this->get_merchant_id() ) {
242+
if ( ! $this->ensure_merchant_id() ) {
229243
return false;
230244
}
231245

@@ -234,6 +248,30 @@ public function disconnect( $reader_id ) {
234248
return $response && ( $response['success'] ?? true );
235249
}
236250

251+
/**
252+
* Get merchant ID, fetching it lazily if not set.
253+
*
254+
* @return null|string Merchant ID or null if unavailable.
255+
*/
256+
private function ensure_merchant_id() {
257+
// If merchant ID is already set, return it
258+
if ( $this->get_merchant_id() ) {
259+
return $this->get_merchant_id();
260+
}
261+
262+
// Try to fetch it from the profile service
263+
if ( $this->profile_service ) {
264+
$merchant_code = $this->profile_service->get_merchant_code();
265+
if ( $merchant_code ) {
266+
$this->set_merchant_id( $merchant_code );
267+
268+
return $merchant_code;
269+
}
270+
}
271+
272+
return null;
273+
}
274+
237275
/**
238276
* Generate a webhook token for a specific order.
239277
* This is user-independent and suitable for external webhook validation.

0 commit comments

Comments
 (0)