Skip to content

Commit edc0427

Browse files
authored
Merge pull request #7 from gravitywpcom/develop
Optimizing the validation function caches the results
2 parents 3db7b7a + cd0911f commit edc0427

File tree

3 files changed

+143
-50
lines changed

3 files changed

+143
-50
lines changed

src/LicenseHandler.php

+3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ public function initialize_paddlepress_client( $field_setting = null ) {
197197
unset( $this->_paddlepress_client );
198198
unset( $this->_license_handler );
199199
$license_key = ! empty( $field_setting ) ? $field_setting : $this->_addon_license;
200+
200201
$this->_license_handler = new Plugin_Updater(
201202
$this->_addon_file_path,
202203
array(
@@ -205,6 +206,7 @@ public function initialize_paddlepress_client( $field_setting = null ) {
205206
'license_url' => home_url(), // license domain.
206207
'download_tag' => $this->_addon_slug, // download tag slug.
207208
'beta' => false,
209+
'handler_class' => $this,
208210
)
209211
);
210212

@@ -214,6 +216,7 @@ public function initialize_paddlepress_client( $field_setting = null ) {
214216
} else {
215217
add_action( 'admin_notices', array( $this, 'action_admin_notices' ) );
216218
}
219+
217220
} catch ( \Exception $e ) {
218221
$this->_addon_class::get_instance()->log_error( __CLASS__ . '::' . __METHOD__ . '(): License client failed to initialize: ' . $e->getMessage() );
219222
return false;

src/changelog.txt

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
= 2.0.4 =
2+
- Optimizing the validation function caches the result.
3+
14
= 2.0.3 =
25
- Fix plugin name not showing in admin notice.
36

src/pluginUpdater.php

+137-50
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Custom Plugin Updater
44
*
55
* @package gravitywp-license-handler
6-
*
76
*/
87

98
namespace GravityWP\Updater;
@@ -105,6 +104,15 @@ class Plugin_Updater {
105104

106105
public $error_messages;
107106

107+
/**
108+
* Store the Handler class
109+
*
110+
* @since 2.0.4
111+
* @access private
112+
* @var string $_addon_class the GravityWP GF Addon classname.
113+
*/
114+
private $handler_class;
115+
108116
/**
109117
* Health check timeout
110118
*
@@ -126,17 +134,17 @@ public function __construct( $_plugin_file, $_api_data = null ) {
126134

127135
global $paddlepress_plugin_data;
128136

129-
$this->api_url = trailingslashit( $this->api_url_update );
130-
$this->api_url_license = $this->api_url_license;
131-
$this->api_data = $_api_data;
132-
$this->name = plugin_basename( $_plugin_file );
133-
$this->version = $_api_data['version'];
134-
$this->download_tag = $_api_data['download_tag'];
135-
$this->slug = $_api_data['download_tag']; // the slug of download term
136-
$this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
137-
$this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
138-
$this->cache_key = 'paddlepress_' . md5( serialize( $this->slug . $this->api_data['license_key'] . $this->beta ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
139-
137+
$this->api_url = trailingslashit( $this->api_url_update );
138+
$this->api_url_license = $this->api_url_license;
139+
$this->api_data = $_api_data;
140+
$this->name = plugin_basename( $_plugin_file );
141+
$this->version = $_api_data['version'];
142+
$this->download_tag = $_api_data['download_tag'];
143+
$this->slug = $_api_data['download_tag']; // the slug of download term
144+
$this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
145+
$this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
146+
$this->cache_key = 'paddlepress_' . md5( serialize( $this->slug . $this->api_data['license_key'] . $this->beta ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
147+
$this->handler_class = $_api_data['handler_class'];
140148
$paddlepress_plugin_data[ $this->slug ] = $this->api_data;
141149

142150
/**
@@ -159,6 +167,7 @@ public function __construct( $_plugin_file, $_api_data = null ) {
159167
* @uses add_filter()
160168
*/
161169
public function init() {
170+
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update_license' ) );
162171
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
163172
add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
164173
remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
@@ -237,7 +246,7 @@ public function request_is_activate( $field_setting ) {
237246
*/
238247
public function generateErrorMessage( $error ) {
239248
// Initialize the error message string with a prefix.
240-
$errorMessage = "Something went wrong:\n";
249+
$error_message = "Something went wrong:\n";
241250
if ( is_array( $error ) ) {
242251
// Loop through each entry in the error array.
243252
foreach ( $error as $key => $messages ) {
@@ -247,66 +256,139 @@ public function generateErrorMessage( $error ) {
247256
// Sanitize the error message to remove any harmful content.
248257
$sanitized_message = sanitize_text_field( $message );
249258
// Append the sanitized message to the error message string.
250-
$errorMessage .= "- $sanitized_message\n";
259+
$error_message .= "- $sanitized_message\n";
251260
}
252261
} else {
253262
$sanitized_message = sanitize_text_field( $messages );
254-
$errorMessage .= "- $sanitized_message\n";
263+
$error_message .= "- $sanitized_message\n";
255264
}
256265
}
257266
} else {
258-
$errorMessage .= $error;
267+
$error_message .= $error;
259268
}
260269

261270
// Return the formatted error message string.
262-
return $errorMessage;
271+
return $error_message;
263272
}
264273

265274
/**
266-
* Validates the plugin's current against the defined API endpoint.
275+
* Validates the plugin's license key by checking against the API endpoint.
276+
*
277+
* This method ensures that the plugin's license key is valid by either retrieving
278+
* validation status from a locally stored cache or making an API request to verify the status.
279+
* If the cached status has expired or is unavailable, it will make an API call using the
280+
* 'request_is_activate' function to fetch the current status and update the cache accordingly.
281+
* The check includes parameters such as the license key, which can be passed directly or
282+
* fetched from the stored API data within the class.
283+
*
284+
* The method returns true if the license key is validated successfully; otherwise, it returns false.
267285
*
268-
* This method checks if the plugin's is valid by retrieving version information
269-
* from the defined API endpoint. If the version information is not cached, it makes
270-
* an API request to fetch it. It utilizes the 'get_version' endpoint and provides
271-
* necessary parameters such as the download tag, beta status, license key, and license URL.
272-
* The method returns true if the version information includes a download link, indicating
273-
* that the plugin is valid; otherwise, it returns false.
286+
* @param bool $cached Unused parameter but kept for maintaining signature consistency.
287+
* @param string|null $key Optional. License key to be used instead of the one stored in the object.
274288
*
275-
* @param array $_transient_data Update array built by WordPress.
289+
* @return bool True if the license key is valid, false otherwise.
276290
*
277-
* @return bool True if the plugin version is valid, false otherwise.
278-
* @uses api_request() This function is used to make an API request to fetch version information.
291+
* @uses request_is_activate() Makes an API request to validate the license key.
292+
* @uses set_version_info_cache() Caches the result of the license key validation.
279293
*/
280294
public function gwp_is_valid( $cached, $key = null ) {
281-
if ( $cached ) {
282-
$version_info = $this->get_cached_version_info();
283-
} else {
284-
$version_info = false;
285-
}
295+
286296
$license_key = ! empty( $key ) ? $key : $this->api_data['license_key'];
287297
if ( empty( $license_key ) ) {
288298
return false;
289299
}
290-
if ( $version_info === false ) {
291-
$version_info = $this->api_request(
292-
'get_version',
293-
array(
294-
'download_tag' => $this->download_tag,
295-
'beta' => $this->beta,
296-
'license_key' => $license_key,
297-
'license_url' => $this->api_data['license_url'],
298-
)
299-
);
300+
301+
$status_cache_key = 'paddlepress_status_request_' . md5( serialize( $this->slug . $this->api_data['license_key'] . $this->beta ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
302+
303+
$cache = get_option( $status_cache_key );
304+
305+
$cache_status = true;
306+
if ( empty( $cache ) || ! isset( $cache['timeout'] ) || empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
307+
$cache_status = false; // Cache is expired.
300308
}
301-
if ( $version_info ) {
302-
if ( isset( $version_info->download_link ) ) {
309+
if ( $cache_status === true ) {
310+
if ( $cache['value'] === 'true' ) {
311+
return true;
312+
}
313+
} else {
314+
$license_key = ! empty( $key ) ? $key : $this->api_data['license_key'];
315+
$status = $this->request_is_activate( $license_key );
316+
$this->set_version_info_cache( $status, $status_cache_key );
317+
if ( $status === true ) {
303318
return true;
304-
} else {
305-
return false;
306319
}
307320
}
321+
322+
return false;
308323
}
309324

325+
/**
326+
* Checks the plugin's license status and updates the transient data accordingly.
327+
*
328+
* This method verifies the validity of the plugin's license key and updates the cached
329+
* license status. It also manages admin notices based on the validation result. If the
330+
* license key is valid, it removes any existing admin notices. Otherwise, it adds an
331+
* admin notice to inform the user about the invalid license status.
332+
*
333+
* Key Details:
334+
* - Verifies if the current context is not the plugins page in a multisite network,
335+
* and returns early if true.
336+
* - Checks existing transient data for license status response, and skips further checks
337+
* if the data is already populated unless overridden.
338+
* - Retrieves the license key and generates a unique cache key for the status request.
339+
* - Calls the API to check the license activation status.
340+
* - Updates the license status cache with the API response.
341+
* - Based on the license validation result, either removes or adds admin notices.
342+
*
343+
* @param stdClass $_transient_data Transient data object containing update information.
344+
* If not provided as an object, it initializes a new stdClass object.
345+
*
346+
* @global string $pagenow Current admin page identifier.
347+
*
348+
* @return stdClass The (possibly modified) transient data object.
349+
*
350+
* @uses request_is_activate() Makes an API request to validate the license key.
351+
* @uses set_version_info_cache() Caches the result of the license key validation.
352+
* @uses gwp_is_valid() Validates the license key using cached data or via API.
353+
*/
354+
public function check_update_license($_transient_data) {
355+
global $pagenow;
356+
357+
// Ensure $_transient_data is an object.
358+
if (!is_object($_transient_data)) {
359+
$_transient_data = new stdClass();
360+
}
361+
362+
// Return early if on the plugins page in a multisite network.
363+
if ('plugins.php' === $pagenow && is_multisite()) {
364+
return $_transient_data;
365+
}
366+
367+
// Check if the transient data already has a response and is not being overridden.
368+
if (!empty($_transient_data->response) && !empty($_transient_data->response[$this->name]) && false === $this->wp_override) {
369+
return $_transient_data;
370+
}
371+
372+
// Retrieve license key and generate a unique cache key.
373+
$license_key = $this->api_data['license_key'];
374+
$status_cache_key = 'paddlepress_status_request_' . md5(serialize($this->slug . $this->api_data['license_key'] . $this->beta)); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
375+
376+
// Validate the license key through the API and update the cache.
377+
$status = $this->request_is_activate($license_key);
378+
$this->set_version_info_cache($status, $status_cache_key);
379+
380+
// Validate the license key and manage admin notices based on validity.
381+
if ($this->gwp_is_valid(false, $license_key)) {
382+
remove_action('admin_notices', array($this->handler_class, 'action_admin_notices'));
383+
} else {
384+
add_action('admin_notices', array($this->handler_class, 'action_admin_notices'));
385+
}
386+
387+
return $_transient_data;
388+
}
389+
390+
391+
310392
/**
311393
* Check for Updates at the defined API endpoint and modify the update array.
312394
*
@@ -336,7 +418,7 @@ public function check_update( $_transient_data ) {
336418
return $_transient_data;
337419
}
338420

339-
$version_info = $this->get_cached_version_info();
421+
$version_info = false; // $this->get_cached_version_info();
340422

341423
if ( false === $version_info ) {
342424
$version_info = $this->api_request(
@@ -440,7 +522,7 @@ public function show_update_notification( $file, $plugin ) {
440522

441523
if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
442524

443-
$version_info = false;// $this->get_cached_version_info();
525+
$version_info = $this->get_cached_version_info(); // || false;
444526

445527
if ( false === $version_info ) {
446528
$version_info = $this->api_request(
@@ -829,8 +911,13 @@ public function show_changelog() {
829911

830912
}
831913

832-
if ( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) {
833-
echo '<div style="background:#fff;padding:10px;">' . wp_kses_allowed_html( $version_info->sections['changelog'] ) . '</div>';
914+
if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
915+
// Ensure sections are converted to an array if they are an object.
916+
$sections = (array) $version_info->sections;
917+
918+
if ( isset( $sections['changelog'] ) ) {
919+
echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
920+
}
834921
}
835922

836923
exit;

0 commit comments

Comments
 (0)