Skip to content

Commit 588e3ed

Browse files
authored
Merge pull request #106 from Kit/add-hooks-on-request-error
Add Hooks on Access/Refresh Token Errors
2 parents f58a2ed + c0e0d63 commit 588e3ed

2 files changed

Lines changed: 62 additions & 71 deletions

File tree

src/class-convertkit-api-v4.php

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,17 @@ public function get_access_token( $authorization_code ) {
377377
// If an error occured, log and return it now.
378378
if ( is_wp_error( $result ) ) {
379379
$this->log( 'API: Error: ' . $result->get_error_message() );
380+
381+
/**
382+
* Perform any actions when obtaining an access token fails.
383+
*
384+
* @since 2.1.1
385+
*
386+
* @param WP_Error $result Error from API.
387+
* @param string $client_id OAuth Client ID.
388+
*/
389+
do_action( 'convertkit_api_get_access_token_error', $result, $this->client_id );
390+
380391
return $result;
381392
}
382393

@@ -414,6 +425,17 @@ public function refresh_token() {
414425
// If an error occured, log and return it now.
415426
if ( is_wp_error( $result ) ) {
416427
$this->log( 'API: Error: ' . $result->get_error_message() );
428+
429+
/**
430+
* Perform any actions when refreshing an expired access token fails.
431+
*
432+
* @since 2.1.1
433+
*
434+
* @param WP_Error $result Error from API.
435+
* @param string $client_id OAuth Client ID.
436+
*/
437+
do_action( 'convertkit_api_refresh_token_error', $result, $this->client_id );
438+
417439
return $result;
418440
}
419441

@@ -1432,39 +1454,55 @@ public function request( $endpoint, $method = 'get', $params = array(), $retry_i
14321454

14331455
// Return the API error message as a WP_Error if the HTTP response code is a 4xx code.
14341456
if ( $http_response_code >= 400 ) {
1457+
14351458
// Define the error message.
14361459
$error = $this->get_error_message_string( $response );
14371460

14381461
$this->log( 'API: Error: ' . $error );
14391462

14401463
switch ( $http_response_code ) {
1441-
// If the HTTP response code is 401, and the error matches 'The access token expired', refresh the access token now
1442-
// and re-attempt the request.
14431464
case 401:
1444-
if ( $error !== 'The access token expired' ) {
1445-
break;
1446-
}
1447-
1448-
// Don't automatically refresh the expired access token if we're not on a production environment.
1449-
// This prevents the same ConvertKit account used on both a staging and production site from
1450-
// reaching a race condition where the staging site refreshes the token first, resulting in
1451-
// the production site unable to later refresh its same expired access token.
1452-
if ( ! $this->is_production_site() ) {
1453-
break;
1454-
}
1455-
1456-
// Refresh the access token.
1457-
$result = $this->refresh_token();
1458-
1459-
// If an error occured, bail.
1460-
if ( is_wp_error( $result ) ) {
1461-
return $result;
1465+
switch ( $error ) {
1466+
case 'The access token expired':
1467+
// Attempt to refresh the access token.
1468+
$result = $this->refresh_token();
1469+
1470+
// If an error occured, bail.
1471+
if ( is_wp_error( $result ) ) {
1472+
return $result;
1473+
}
1474+
1475+
// Attempt the request again, now we have a new access token.
1476+
return $this->request( $endpoint, $method, $params, false );
1477+
1478+
case 'The access token is invalid':
1479+
$error = new WP_Error(
1480+
'convertkit_api_error',
1481+
$error,
1482+
$http_response_code
1483+
);
1484+
1485+
/**
1486+
* Perform any actions when an invalid access token was used.
1487+
*
1488+
* @since 2.1.1
1489+
*
1490+
* @param WP_Error $error WP_Error object.
1491+
* @param string $client_id OAuth Client ID.
1492+
*/
1493+
do_action( 'convertkit_api_access_token_invalid', $error, $this->client_id );
1494+
1495+
// Return error.
1496+
return $error;
1497+
1498+
default:
1499+
return new WP_Error(
1500+
'convertkit_api_error',
1501+
$error,
1502+
$http_response_code
1503+
);
14621504
}
14631505

1464-
// Attempt the request again, now we have a new access token.
1465-
return $this->request( $endpoint, $method, $params, false );
1466-
1467-
// If a rate limit was hit, maybe try again.
14681506
case 429:
14691507
// If retry on rate limit hit is disabled, return a WP_Error.
14701508
if ( ! $retry_if_rate_limit_hit ) {
@@ -1491,27 +1529,6 @@ public function request( $endpoint, $method = 'get', $params = array(), $retry_i
14911529

14921530
}
14931531

1494-
/**
1495-
* Helper method to determine the WordPress environment type, checking
1496-
* if the wp_get_environment_type() function exists in WordPress (versions
1497-
* older than WordPress 5.5 won't have this function).
1498-
*
1499-
* @since 2.0.2
1500-
*
1501-
* @return bool
1502-
*/
1503-
private function is_production_site() {
1504-
1505-
// If the WordPress wp_get_environment_type() function isn't available,
1506-
// assume this is a production site.
1507-
if ( ! function_exists( 'wp_get_environment_type' ) ) {
1508-
return true;
1509-
}
1510-
1511-
return ( wp_get_environment_type() === 'production' );
1512-
1513-
}
1514-
15151532
/**
15161533
* Inspects the given API response for errors, returning them as a string.
15171534
*

tests/Integration/APITest.php

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -528,32 +528,6 @@ public function testRefreshTokenWithInvalidToken()
528528
$this->assertEquals($result->get_error_code(), 'convertkit_api_error');
529529
}
530530

531-
/**
532-
* Test that making a call with an expired access token results in refresh_token()
533-
* not being automatically called, when the WordPress site isn't a production site.
534-
*
535-
* @since 2.0.2
536-
*
537-
* @return void
538-
*/
539-
public function testRefreshTokenWhenAccessTokenExpiredErrorOnNonProductionSite()
540-
{
541-
// If the refresh token action in the libraries is triggered when calling get_account(), the test failed.
542-
add_action(
543-
'convertkit_api_refresh_token',
544-
function() {
545-
$this->fail('`convertkit_api_refresh_token` was triggered when calling `get_account` with an expired access token on a non-production site.');
546-
}
547-
);
548-
549-
// Filter requests to mock the token expiry and refreshing the token.
550-
add_filter( 'pre_http_request', array( $this, 'mockAccessTokenExpiredResponse' ), 10, 3 );
551-
add_filter( 'pre_http_request', array( $this, 'mockRefreshTokenResponse' ), 10, 3 );
552-
553-
// Run request, which will trigger the above filters as if the token expired and refreshes automatically.
554-
$result = $this->api->get_account();
555-
}
556-
557531
/**
558532
* Test that supplying no API credentials to the API class returns a WP_Error.
559533
*

0 commit comments

Comments
 (0)