Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3cc982c
fix issue #9
JurriaanK Oct 14, 2024
283bd70
Implementing the global licensed key.
kimo-works Apr 29, 2025
5a813c7
fix Global_License_Key_Loader
kimo-works Apr 29, 2025
087bc72
fix missed echo
kimo-works Apr 29, 2025
3b16fce
fix display $version
kimo-works Apr 29, 2025
2d912f9
fix display $version part 2
kimo-works Apr 29, 2025
43bdd18
- changed messages
JurriaanK Apr 29, 2025
89b6185
Added more informative messages
JurriaanK Apr 30, 2025
b5b4009
added url
JurriaanK Apr 30, 2025
a429a06
improving the licence handler and more error messages
kimo-works Apr 30, 2025
9acbfb8
remove class prefix
JurriaanK May 1, 2025
0d72547
remove existing dismissible message after saving the global key
JurriaanK May 1, 2025
78c25a0
fix classname not being passed
JurriaanK May 1, 2025
a7ffa1a
implement message when global license is not valid for all plugins
JurriaanK May 2, 2025
cb746f1
fix uses capability
kimo-works Jul 8, 2025
ce8ff60
Merge branch 'fix_capability' into develop
kimo-works Jul 8, 2025
a959339
merge fix_capability and GLK
kimo-works Jul 8, 2025
bf34872
Merge remote-tracking branch 'origin/informative_edge_case_errors' in…
kimo-works Jul 8, 2025
942cb99
fixs and merge
kimo-works Jul 8, 2025
c258779
Implementing the global licensed key
kimo-works Jul 25, 2025
45c657e
adding glk_version for logs
kimo-works Jul 25, 2025
ac7bca6
Enqueues admin styles for the GravityWP settings page.
kimo-works Jul 25, 2025
cdb6232
fix enqueue_admin_styles
kimo-works Jul 25, 2025
da54c90
fix gwp-styles
kimo-works Jul 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 105 additions & 42 deletions src/LicenseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*
* @package gravitywp-license-handler
* @license MIT
*
*/

namespace GravityWP\LicenseHandler;
Expand All @@ -17,9 +16,10 @@
/**
* Handles GWP Licenses.
*
* @version 2.0.3
* @version 2.0.5
*/
class LicenseHandler {

/**
* Update endpoint of the API
*
Expand Down Expand Up @@ -53,7 +53,7 @@ class LicenseHandler {
*
* @var mixed|string
*/
private $version = '';
private $version = '2.1.0';

/**
* WP Override flag
Expand Down Expand Up @@ -129,13 +129,13 @@ class LicenseHandler {
private $_addon_license = '';

/**
* Store the GravityWP GF Addon license hash.
* Store the GravityWP Global License Key.
*
* @since 1.0
* @access private
* @var string $_addon_license_hash the GravityWP GF Addon license hash.
* @var string $_global_license_key Global License Key.
*/
private $_addon_license_hash = '';
private $_global_license_key = '';

/**
* Store the GravityWP GF Addon title
Expand Down Expand Up @@ -167,56 +167,71 @@ class LicenseHandler {
/**
* Constructor.
*
* @since 1.0
* @since 1.0
*
* @param string $gwp_addon_class GravityWP GF Addon classname.
* @param string $gwp_addon_class GravityWP GF Addon classname.
* @param string $plugin_file_path Path to main plugin file.
*
* @return void
*/
public function __construct( $gwp_addon_class, $plugin_file_path ) {
// Load the loader class (only once).
if ( ! class_exists( '\GravityWP\Shared\Global_License_Key_Loader' ) ) {
require_once __DIR__ . '/shared/class-global-license-key-loader.php';
}

if ( $this->version ) {
// Register this plugin’s version.
\GravityWP\Shared\Global_License_Key_Loader::register( $this->version, __DIR__ . '/shared/class-global-license-key-registry.php', $gwp_addon_class );
}

$doing_cron = defined( 'DOING_CRON' ) && DOING_CRON;
if ( ! current_user_can( 'manage_options' ) && ! $doing_cron ) {
if ( ! ( current_user_can( 'gform_full_access' ) || current_user_can( 'gravityforms_edit_settings' ) || current_user_can( 'gravityforms_view_settings' ) ) && ! $doing_cron ) {
return;
}
$this->_addon_class = $gwp_addon_class;
$this->_addon_file_path = $plugin_file_path;
$this->_addon_slug = $gwp_addon_class::get_instance()->get_slug();
$this->_addon_license = $gwp_addon_class::get_instance()->get_plugin_setting( $this->_addon_slug . '_license_key' );
$this->_addon_title = $gwp_addon_class::get_instance()->plugin_page_title();
$this->_addon_class = $gwp_addon_class;
$this->_addon_file_path = $plugin_file_path;
$this->_addon_slug = $gwp_addon_class::get_instance()->get_slug();
$this->_addon_license = $gwp_addon_class::get_instance()->get_plugin_setting( $this->_addon_slug . '_license_key' );
$this->_addon_title = $gwp_addon_class::get_instance()->plugin_page_title();
$this->_global_license_key = get_option( 'gravitywp_global_license_key', '' );
$this->initialize_paddlepress_client();
}

/**
* Initialize or reinitialize the Paddlepress client.
*
* @return bool
* @param string|null $field_setting Optional license key override from a field or custom setting.
* @return bool True if initialization succeeded, false otherwise.
*/
public function initialize_paddlepress_client( $field_setting = null ) {
try {
unset( $this->_paddlepress_client );
unset( $this->_license_handler );
$license_key = ! empty( $field_setting ) ? $field_setting : $this->_addon_license;
$license_key = ! empty( $field_setting ) ? $field_setting : $this->_addon_license;

if ( empty( $license_key ) ) {
$license_key = $this->_global_license_key;
}

$this->_license_handler = new Plugin_Updater(
$this->_addon_file_path,
array(
'version' => $this->_addon_class::get_instance()->get_version(), // current version number.
'license_key' => $license_key, // license key (used get_option above to retrieve from DB)..'error'
'license_url' => home_url(), // license domain.
'download_tag' => $this->_addon_slug, // download tag slug.
'beta' => false,
'version' => $this->_addon_class::get_instance()->get_version(), // current version number.
'license_key' => $license_key, // license key (used get_option above to retrieve from DB)..'error'.
'license_url' => home_url(), // license domain.
'download_tag' => $this->_addon_slug, // download tag slug.
'beta' => false,
'handler_class' => $this,
)
);

$use_cached_info = ! empty( $field_setting ) ? false : true;
if ( $this->_license_handler->gwp_is_valid( $use_cached_info, $license_key ) ) {
remove_action( 'admin_notices', array( $this, 'action_admin_notices' ) );
remove_action( 'admin_notices', array( $this, 'action_admin_notices' ) );
} else {
add_action( 'admin_notices', array( $this, 'action_admin_notices' ) );
}

} catch ( \Exception $e ) {
$this->_addon_class::get_instance()->log_error( __CLASS__ . '::' . __METHOD__ . '(): License client failed to initialize: ' . $e->getMessage() );
return false;
Expand All @@ -228,7 +243,7 @@ public function initialize_paddlepress_client( $field_setting = null ) {
/**
* Display an admin notice.
*
* @since 1.0
* @since 1.0
*
* @return void
*/
Expand All @@ -253,39 +268,87 @@ public function action_admin_notices() {
/**
* Define plugin settings fields.
*
* @since 1.0
* @since 1.0
*
* @return array
*/
public function plugin_settings_license_fields() {
$this->_addon_license = $this->_addon_class::get_instance()->get_plugin_setting( $this->_addon_slug . '_license_key' );
$this->_addon_license = $this->_addon_class::get_instance()->get_plugin_setting(
$this->_addon_slug . '_license_key'
);

$license_key_name = $this->_addon_slug . '_license_key';

// Main license input field.
$license_field = array(
'name' => $this->_addon_slug . '_license_key',
'tooltip' => esc_html__( 'Enter the license key you received after purchasing the plugin.', 'gravitywp-license-handler' ),
'label' => esc_html__( 'License Key', 'gravitywp-license-handler' ),
'type' => 'text',
'input_type' => 'password',
'class' => 'medium',
'default_value' => '',
'required' => true,
'validation_callback' => array( $this, 'license_validation' ),
'feedback_callback' => array( $this, 'license_feedback' ),
'error_message' => esc_html__( 'Invalid or expired license', 'gravitywp-license-handler' ),
'title' => esc_html__( 'To unlock plugin updates and support, please enter your license key below.', 'gravitywp-license-handler' ),
'fields' => array(
array(
'name' => $license_key_name,
'label' => esc_html__( 'Plugin License Key', 'gravitywp-license-handler' ),
'tooltip' => esc_html__( 'Enter the license key you received after purchasing the plugin.', 'gravitywp-license-handler' ),
'type' => 'text',
'input_type' => 'password',
'class' => 'medium',
'default_value' => '',
'required' => false,
'validation_callback' => array( $this, 'license_validation' ),
'feedback_callback' => array( $this, 'license_feedback' ),
'error_message' => esc_html__( 'Invalid or expired license.', 'gravitywp-license-handler' ),
),
),
);

$license_field['title'] = esc_html__( 'To unlock plugin updates and support, please enter your license key below', 'gravitywp-license-handler' );
$license_field['fields'] = array( $license_field );
// Determine current license state.
if ( isset( $_POST[ '_gform_setting_' . $this->_addon_slug . '_license_key' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
// If the form is submitted, use the posted value.
$plugin_license_key = rgpost( '_gform_setting_' . $this->_addon_slug . '_license_key' );
} else {
// Otherwise, use the stored value.
$plugin_license_key = $this->_addon_license ?? '';
}
$global_license_key = $this->_global_license_key ?? '';

// Add contextual note based on key presence.
$license_field['fields'][] = array(
'name' => 'license_note',
'type' => 'html',
'html' => function () use ( $plugin_license_key, $global_license_key ) {
$global_settings_url = admin_url( 'admin.php?page=gravitywp-settings' );
$global_settings_text = esc_html__( 'Global License Key', 'gravitywp-license-handler' );
$message_color = 'inherit';
if ( ! empty( $plugin_license_key ) && ! empty( $global_license_key ) ) {
/* translators: %s: link to global settings */
$message = sprintf( esc_html__( 'This Plugin License Key overrides the %s. To use the global key, leave this field empty.', 'gravitywp-license-handler' ), '<a href="' . esc_url( $global_settings_url ) . '">' . esc_html( $global_settings_text ) . '</a>' );
} elseif ( empty( $plugin_license_key ) && ! empty( $global_license_key ) ) {
/* translators: %s: link to global settings */
if ( $this->_license_handler->gwp_is_valid( true, $global_license_key ) ) {
/* translators: %s: link to global settings */
$message = sprintf( esc_html__( 'A %s is active. If needed you can override the Global Key with the Plugin Key.', 'gravitywp-license-handler' ), '<a href="' . esc_url( $global_settings_url ) . '">' . esc_html( $global_settings_text ) . '</a>' );
$message_color = 'green';
} else {
/* translators: %s: link to global settings, link to gravitywp.com */
$message = sprintf( esc_html__( 'A %1$s is active, but it is not valid for this addon. You can override the Global Key with a specific Plugin Key or purchase an All Access license on %2$s.', 'gravitywp-license-handler' ), '<a href="' . esc_url( $global_settings_url ) . '">' . esc_html( $global_settings_text ) . '</a>', '<a href="https://gravitywp.com">gravitywp.com</a>' );
$message_color = 'red';
}
} else {
$message_color = 'red';
/* translators: %s: link to global settings */
$message = sprintf( esc_html__( 'No active license. If you have an All Access License you can set up a %s.', 'gravitywp-license-handler' ), '<a href="' . esc_url( $global_settings_url ) . '">' . esc_html( $global_settings_text ) . '</a>' );
}
return '<span style="color:' . esc_attr( $message_color ) . ';">' . $message . '</span>';
},
);

return $license_field;
}

/**
* Handle license key activation or deactivation and on save the settings.
*
* @since 1.0
* @since 1.0
*
* @param array $field The field properties.
* @param array $field The field properties.
* @param string $field_setting The submitted value of the license_key field.
*/
public function license_validation( $field, $field_setting ) {
Expand All @@ -310,7 +373,7 @@ public function license_validation( $field, $field_setting ) {
* @param string $value The current value of the license_key field.
* @param array $field The field properties.
*
* @since 1.0
* @since 1.0
*
* @return bool|null
*/
Expand Down
6 changes: 6 additions & 0 deletions src/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
= 2.1.0 =
- Implementing the global licensed key.

= 2.0.5 =
- Fix non unique #id in plugin setting.

= 2.0.4 =
- Optimizing the validation function caches the result.

Expand Down
63 changes: 46 additions & 17 deletions src/pluginUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,36 @@ public function request_is_activate( $field_setting ) {
$this->error_messages = nl2br( $this->generateErrorMessage( $json_data['message'] ) );
return false;
} else {
$this->error_messages = nl2br( $this->generateErrorMessage( 'Please try again later. If the issue persists, please contact support.' ) );
// Retrieve HTTP status code and headers for additional context.
$http_code = wp_remote_retrieve_response_code( $response );
$headers = wp_remote_retrieve_headers( $response );

// Check for block by Cloudflare.
if ( $http_code === 403 && strpos( strtolower( $body ), 'cloudflare' ) !== false ) {
$this->error_messages = nl2br(
$this->generateErrorMessage(
'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>.'
)
);
return false;
}

// Format additional information into a string for logging or support use.
$extra_info = sprintf(
"HTTP Status Code: %d\nResponse Headers: %s",
$http_code,
json_encode( $headers )
);

// Provide a detailed error message including the response code, extra info, and a reference URL.
$this->error_messages = nl2br(
$this->generateErrorMessage(
sprintf(
'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.',
esc_html( $extra_info ) // Ensure special characters in the info are safely included in an HTML context.
)
)
);
return false;
}
}
Expand Down Expand Up @@ -260,7 +289,7 @@ public function generateErrorMessage( $error ) {
}
} else {
$sanitized_message = sanitize_text_field( $messages );
$error_message .= "- $sanitized_message\n";
$error_message .= "- $sanitized_message\n";
}
}
} else {
Expand Down Expand Up @@ -325,13 +354,13 @@ public function gwp_is_valid( $cached, $key = null ) {
/**
* Checks the plugin's license status and updates the transient data accordingly.
*
* This method verifies the validity of the plugin's license key and updates the cached
* license status. It also manages admin notices based on the validation result. If the
* license key is valid, it removes any existing admin notices. Otherwise, it adds an
* This method verifies the validity of the plugin's license key and updates the cached
* license status. It also manages admin notices based on the validation result. If the
* license key is valid, it removes any existing admin notices. Otherwise, it adds an
* admin notice to inform the user about the invalid license status.
*
* Key Details:
* - Verifies if the current context is not the plugins page in a multisite network,
* - Verifies if the current context is not the plugins page in a multisite network,
* and returns early if true.
* - Checks existing transient data for license status response, and skips further checks
* if the data is already populated unless overridden.
Expand All @@ -351,37 +380,37 @@ public function gwp_is_valid( $cached, $key = null ) {
* @uses set_version_info_cache() Caches the result of the license key validation.
* @uses gwp_is_valid() Validates the license key using cached data or via API.
*/
public function check_update_license($_transient_data) {
public function check_update_license( $_transient_data ) {
global $pagenow;

// Ensure $_transient_data is an object.
if (!is_object($_transient_data)) {
if ( ! is_object( $_transient_data ) ) {
$_transient_data = new stdClass();
}

// Return early if on the plugins page in a multisite network.
if ('plugins.php' === $pagenow && is_multisite()) {
if ( 'plugins.php' === $pagenow && is_multisite() ) {
return $_transient_data;
}

// Check if the transient data already has a response and is not being overridden.
if (!empty($_transient_data->response) && !empty($_transient_data->response[$this->name]) && false === $this->wp_override) {
if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
return $_transient_data;
}

// Retrieve license key and generate a unique cache key.
$license_key = $this->api_data['license_key'];
$status_cache_key = 'paddlepress_status_request_' . md5(serialize($this->slug . $this->api_data['license_key'] . $this->beta)); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
$status_cache_key = 'paddlepress_status_request_' . md5( serialize( $this->slug . $this->api_data['license_key'] . $this->beta ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize

// Validate the license key through the API and update the cache.
$status = $this->request_is_activate($license_key);
$this->set_version_info_cache($status, $status_cache_key);
$status = $this->request_is_activate( $license_key );
$this->set_version_info_cache( $status, $status_cache_key );

// Validate the license key and manage admin notices based on validity.
if ($this->gwp_is_valid(false, $license_key)) {
remove_action('admin_notices', array($this->handler_class, 'action_admin_notices'));
if ( $this->gwp_is_valid( false, $license_key ) ) {
remove_action( 'admin_notices', array( $this->handler_class, 'action_admin_notices' ) );
} else {
add_action('admin_notices', array($this->handler_class, 'action_admin_notices'));
add_action( 'admin_notices', array( $this->handler_class, 'action_admin_notices' ) );
}

return $_transient_data;
Expand Down Expand Up @@ -522,7 +551,7 @@ public function show_update_notification( $file, $plugin ) {

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

$version_info = $this->get_cached_version_info(); // || false;
$version_info = $this->get_cached_version_info(); // || false;

if ( false === $version_info ) {
$version_info = $this->api_request(
Expand Down
Loading