@@ -31,14 +31,14 @@ class Plugin_Updater {
3131 *
3232 * @var $result_count
3333 */
34- private $ api_url_update = 'https://my.gravitywp.com /wp-json/paddlepress-api/v1/update ' ;
34+ private $ api_url_update = 'https://stg-mygravitywpcom-mygwpstage.kinsta.cloud /wp-json/paddlepress-api/v1/update ' ;
3535
3636 /**
3737 * GravityWP license url endpoint of the API
3838 *
3939 * @var $result_count
4040 */
41- private $ api_url_license = 'https://my.gravitywp.com /wp-json/paddlepress-api/v1/license ' ;
41+ private $ api_url_license = 'https://stg-mygravitywpcom-mygwpstage.kinsta.cloud /wp-json/paddlepress-api/v1/license ' ;
4242
4343 /**
4444 * HTTP parameters on API requests
@@ -224,7 +224,36 @@ public function request_is_activate( $field_setting ) {
224224 $ this ->error_messages = nl2br ( $ this ->generateErrorMessage ( $ json_data ['message ' ] ) );
225225 return false ;
226226 } else {
227- $ this ->error_messages = nl2br ( $ this ->generateErrorMessage ( 'Please try again later. If the issue persists, please contact support. ' ) );
227+ // Retrieve HTTP status code and headers for additional context.
228+ $ http_code = wp_remote_retrieve_response_code ( $ response );
229+ $ headers = wp_remote_retrieve_headers ( $ response );
230+
231+ // Check for block by Cloudflare.
232+ if ( $ http_code === 403 && strpos ( strtolower ( $ body ), 'cloudflare ' ) !== false ) {
233+ $ this ->error_messages = nl2br (
234+ $ this ->generateErrorMessage (
235+ 'Access to the license server was denied by Cloudflare. This happens when malicious activity was detected from your website \'s outgoing IP address. This often happens on shared hosting where other users use the same IP address for malicious activity. Contact your hosting provider to resolve this issue. For more information, visit <a href="https://gravitywp.com/doc/license-activation-issues/">this page</a>. '
236+ )
237+ );
238+ return false ;
239+ }
240+
241+ // Format additional information into a string for logging or support use.
242+ $ extra_info = sprintf (
243+ "HTTP Status Code: %d \nResponse Headers: %s " ,
244+ $ http_code ,
245+ json_encode ( $ headers )
246+ );
247+
248+ // Provide a detailed error message including the response code, extra info, and a reference URL.
249+ $ this ->error_messages = nl2br (
250+ $ this ->generateErrorMessage (
251+ sprintf (
252+ 'An unexpected error occurred. Please try again later. You can also refer to <a href="https://gravitywp.com/doc/license-activation-issues/">this page</a> for more details. If the issue persists, provide the following information to support: %s. ' ,
253+ esc_html ( $ extra_info ) // Ensure special characters in the info are safely included in an HTML context.
254+ )
255+ )
256+ );
228257 return false ;
229258 }
230259 }
@@ -260,7 +289,7 @@ public function generateErrorMessage( $error ) {
260289 }
261290 } else {
262291 $ sanitized_message = sanitize_text_field ( $ messages );
263- $ error_message .= "- $ sanitized_message \n" ;
292+ $ error_message .= "- $ sanitized_message \n" ;
264293 }
265294 }
266295 } else {
@@ -323,65 +352,60 @@ public function gwp_is_valid( $cached, $key = null ) {
323352 }
324353
325354 /**
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.
355+ * Checks the plugin's license status using the centralized Hub cache.
342356 *
343- * @param stdClass $_transient_data Transient data object containing update information.
344- * If not provided as an object, it initializes a new stdClass object.
357+ * Since v2.1.0: Reads from Hub_Manager's shared cache instead of
358+ * making individual API calls. This is the key optimization —
359+ * one hub request serves ALL plugins.
345360 *
346- * @global string $pagenow Current admin page identifier .
361+ * @param stdClass $_transient_data Transient data object .
347362 *
348363 * @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.
353364 */
354- public function check_update_license ($ _transient_data ) {
365+ public function check_update_license ( $ _transient_data ) {
355366 global $ pagenow ;
356367
357- // Ensure $_transient_data is an object.
358- if (!is_object ($ _transient_data )) {
368+ if ( ! is_object ( $ _transient_data ) ) {
359369 $ _transient_data = new stdClass ();
360370 }
361371
362- // Return early if on the plugins page in a multisite network.
363- if ('plugins.php ' === $ pagenow && is_multisite ()) {
372+ if ( 'plugins.php ' === $ pagenow && is_multisite () ) {
364373 return $ _transient_data ;
365374 }
366375
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 ) {
376+ if ( ! empty ( $ _transient_data ->response ) && ! empty ( $ _transient_data ->response [ $ this ->name ] ) && false === $ this ->wp_override ) {
369377 return $ _transient_data ;
370378 }
371379
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
380+ // Use Hub_Manager if available (v2.1.0+) .
381+ if ( class_exists ( ' \GravityWP\Shared\Hub_Manager ' ) ) {
382+ $ has_access = \ GravityWP \ Shared \Hub_Manager:: has_access ( $ this ->slug );
375383
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 );
384+ if ( $ has_access ) {
385+ remove_action ( 'admin_notices ' , array ( $ this ->handler_class , 'action_admin_notices ' ) );
386+ } else {
387+ add_action ( 'admin_notices ' , array ( $ this ->handler_class , 'action_admin_notices ' ) );
388+ }
389+
390+ return $ _transient_data ;
391+ }
392+
393+ // Fallback to direct API call if Hub_Manager not loaded yet.
394+ $ license_key = get_option ( 'gravitywp_global_license_key ' , '' );
395+
396+ if ( empty ( $ license_key ) ) {
397+ add_action ( 'admin_notices ' , array ( $ this ->handler_class , 'action_admin_notices ' ) );
398+ return $ _transient_data ;
399+ }
379400
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 ' ));
401+ $ status_cache_key = 'paddlepress_status_request_ ' . md5 ( serialize ( $ this ->slug . $ license_key . $ this ->beta ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
402+ $ status = $ this ->request_is_activate ( $ license_key );
403+ $ this ->set_version_info_cache ( $ status , $ status_cache_key );
404+
405+ if ( $ this ->gwp_is_valid ( false , $ license_key ) ) {
406+ remove_action ( 'admin_notices ' , array ( $ this ->handler_class , 'action_admin_notices ' ) );
383407 } else {
384- add_action ('admin_notices ' , array ($ this ->handler_class , 'action_admin_notices ' ) );
408+ add_action ( 'admin_notices ' , array ( $ this ->handler_class , 'action_admin_notices ' ) );
385409 }
386410
387411 return $ _transient_data ;
@@ -418,8 +442,35 @@ public function check_update( $_transient_data ) {
418442 return $ _transient_data ;
419443 }
420444
421- $ version_info = false ; // $this->get_cached_version_info();
445+ $ version_info = false ;
446+
447+ // Try Hub_Manager first (no extra API call needed).
448+ if ( class_exists ( '\GravityWP\Shared\Hub_Manager ' ) ) {
449+ $ hub_plugin_data = \GravityWP \Shared \Hub_Manager::get_plugin_data ( $ this ->slug );
450+
451+ if ( ! empty ( $ hub_plugin_data ) && ! empty ( $ hub_plugin_data ['new_version ' ] ) ) {
452+ $ version_info = new stdClass ();
453+ $ version_info ->name = $ hub_plugin_data ['name ' ] ?? '' ;
454+ $ version_info ->slug = $ hub_plugin_data ['slug ' ] ?? $ this ->slug ;
455+ $ version_info ->new_version = $ hub_plugin_data ['new_version ' ];
456+ $ version_info ->url = '' ;
457+ $ version_info ->plugin = $ this ->name ;
458+ $ version_info ->icons = $ hub_plugin_data ['icons ' ] ?? array ();
459+ $ version_info ->banners = $ hub_plugin_data ['banners ' ] ?? array ();
460+ $ version_info ->sections = $ hub_plugin_data ['sections ' ] ?? array ();
461+ $ version_info ->requires = $ hub_plugin_data ['requires ' ] ?? '' ;
462+ $ version_info ->tested = $ hub_plugin_data ['tested ' ] ?? '' ;
463+ $ version_info ->requires_php = $ hub_plugin_data ['requires_php ' ] ?? '' ;
464+
465+ // Only include download link if license covers this plugin.
466+ if ( ! empty ( $ hub_plugin_data ['has_access ' ] ) && ! empty ( $ hub_plugin_data ['download_link ' ] ) ) {
467+ $ version_info ->package = $ hub_plugin_data ['download_link ' ];
468+ $ version_info ->download_link = $ hub_plugin_data ['download_link ' ];
469+ }
470+ }
471+ }
422472
473+ // Fallback to direct API call if Hub didn't provide data.
423474 if ( false === $ version_info ) {
424475 $ version_info = $ this ->api_request (
425476 'get_version ' ,
@@ -430,7 +481,6 @@ public function check_update( $_transient_data ) {
430481 )
431482 );
432483
433- // Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now:
434484 if ( isset ( $ version_info ->banners ) && ! is_array ( $ version_info ->banners ) ) {
435485 $ version_info ->banners = $ this ->convert_object_to_array ( $ version_info ->banners );
436486 }
@@ -455,9 +505,7 @@ public function check_update( $_transient_data ) {
455505 $ no_update = false ;
456506 if ( version_compare ( $ this ->version , $ version_info ->new_version , '< ' ) ) {
457507
458- $ _transient_data ->response [ $ this ->name ] = $ version_info ;
459-
460- // Make sure the plugin property is set to the plugin's name/location.
508+ $ _transient_data ->response [ $ this ->name ] = $ version_info ;
461509 $ _transient_data ->response [ $ this ->name ]->plugin = $ this ->name ;
462510 } else {
463511 $ no_update = new stdClass ();
@@ -522,7 +570,7 @@ public function show_update_notification( $file, $plugin ) {
522570
523571 if ( empty ( $ update_cache ->response ) || empty ( $ update_cache ->response [ $ this ->name ] ) ) {
524572
525- $ version_info = $ this ->get_cached_version_info (); // || false;
573+ $ version_info = $ this ->get_cached_version_info (); // || false;
526574
527575 if ( false === $ version_info ) {
528576 $ version_info = $ this ->api_request (
0 commit comments