56 if ( is_null( self::$_instance ) ) {
57 self::$_instance =
new self();
60 return self::$_instance;
77 if ( ! wp_doing_ajax() ) {
85 add_filter(
'gk/foundation/ajax/' .
Framework::AJAX_ROUTER .
'/routes', [ $this,
'configure_ajax_routes' ] );
87 add_action(
'after_plugin_row', [ $this,
'display_license_info_on_plugins_page' ], 10, 2 );
106 return array_merge( $routes, [
107 'get_licenses' => [ $this,
'ajax_get_licenses_data' ],
108 'activate_license' => [ $this,
'ajax_activate_license' ],
109 'deactivate_license' => [ $this,
'ajax_deactivate_license' ],
126 throw new Exception( esc_html__(
'You do not have a permission to perform this action.',
'gk-gravityview' ) );
129 $payload = wp_parse_args( $payload, [
130 'skip_cache' =>
false,
143 $licenses_data[ $license[
'key'] ] = $license;
146 return $licenses_data;
157 if ( ! empty( $this->_licenses_data ) ) {
163 if ( ! empty( $licenses_data ) ) {
167 $this->_licenses_data = $licenses_data ?: [];
182 $expiry_dates = array_column( $licenses_data,
'expiry' );
184 array_multisort( $licenses_data, SORT_ASC, $expiry_dates );
186 $this->_licenses_data = $licenses_data;
191 LoggerFramework::get_instance()->error(
'Failed to encrypt licenses data: ' . $e->getMessage() );
212 $product_license_map = [];
214 foreach ( $licenses_data as $license_key => $license_data ) {
215 if ( empty( $license_data[
'products'] ) ) {
219 foreach ( $license_data[
'products'] as $product_id => $product_data ) {
225 $key = $product_data[
'text_domain'];
230 if ( empty( $product_license_map[ $key ] ) ) {
231 $product_license_map[ $key ] = [];
234 $product_license_map[ $key ][] = $license_key;
238 return $product_license_map;
251 $key_by = ! ctype_alpha( $id ) ?
'id' :
'text_domain';
255 return ! empty( $product_license_map[ $id ] ) ? $product_license_map[ $id ] : [];
269 'site_inactive' => esc_html__(
'The license key is valid, but it has not been activated for this site.',
'gk-gravityview' ),
270 'inactive' => esc_html__(
'The license key is valid, but it has not been activated for this site.',
'gk-gravityview' ),
271 'no_activations_left' => esc_html__(
'This license has reached its activation limit.',
'gk-gravityview' ),
272 'deactivated' => esc_html__(
'This license has been deactivated.',
'gk-gravityview' ),
273 'valid' => esc_html__(
'This license key is valid and active.',
'gk-gravityview' ),
274 'invalid' => esc_html__(
'This license key is invalid.',
'gk-gravityview' ),
275 'missing' => esc_html__(
'This license key is invalid.',
'gk-gravityview' ),
276 'revoked' => esc_html__(
'This license key has been revoked.',
'gk-gravityview' ),
277 'expired' => esc_html__(
'This license key has expired.',
'gk-gravityview' ),
280 if ( empty( $statuses[ $status ] ) ) {
281 LoggerFramework::get_instance()->warning(
'Unknown license status: ' . $status );
283 return esc_html__(
'License status could not be determined.',
'gk-gravityview' );
286 return $statuses[ $status ];
302 $multiple_licenses = is_array( $license );
305 'edd_action' => $edd_action,
306 'url' => is_multisite() ? network_home_url() : home_url(),
307 'api_version' => self::EDD_LICENSES_API_VERSION,
308 'license' => $license
311 if (
'check_license' === $edd_action ) {
317 self::EDD_LICENSES_API_ENDPOINT,
325 $response = $multiple_licenses ? $response : [ $response ];
328 if ( $multiple_licenses && 1 === count( $license ) ) {
329 $response = [ $license[0] => $response ];
332 $normalized_response_data = [];
334 $license_keys = $multiple_licenses ? $license : [ $license ];
336 foreach ( (array) $response as $key => $data ) {
337 if ( ! isset( $data[
'success'] ) || ! isset( $data[
'license'] ) || ! isset( $data[
'checksum'] ) ) {
338 throw new Exception( esc_html__(
'License data received from the API is incomplete.',
'gk-gravityview' ) );
341 $license_key = $multiple_licenses ? $key : $license;
343 if ( ! in_array( $license_key, $license_keys,
true ) ) {
344 LoggerFramework::get_instance()->warning(
"EDD API returned unknown license key in response: {$license_key}" );
349 if ( ! $data[
'success'] && empty( $data[
'expires'] ) ) {
352 $expiry = ! empty( $data[
'expires'] ) ? strtotime( $data[
'expires'], current_time(
'timestamp' ) ) : null;
353 $expiry = $expiry ?: $data[
'expires'];
356 $normalized_license_data = [
357 'name' => ! empty( $data[
'customer_name'] ) ? $data[
'customer_name'] : null,
358 'email' => ! empty( $data[
'customer_email'] ) ? $data[
'customer_email'] : null,
359 'license_name' => ! empty( $data[
'license_name'] ) ? $data[
'license_name'] : null,
361 'key' => $license_key,
366 if ( ! empty( $data[
'products'] ) ) {
367 foreach ( $data[
'products'] as $product ) {
368 if ( empty( $product[
'files'][0][
'file'] ) || empty( $product[
'id'] ) || empty( $product[
'textdomain'] ) ) {
372 $normalized_license_data[
'products'][ $product[
'id'] ] = [
373 'id' => $product[
'id'],
374 'text_domain' => $product[
'textdomain'],
375 'download' => $product[
'files'][0][
'file']
380 if ( $multiple_licenses ) {
381 $normalized_response_data[ $license_key ] = $normalized_license_data;
383 $normalized_response_data = $normalized_license_data;
387 return $normalized_response_data;
441 throw new Exception( esc_html__(
'You do not have a permission to perform this action.',
'gk-gravityview' ) );
444 if ( empty( $payload[
'key'] ) ) {
445 throw new Exception( esc_html__(
'Missing license key.',
'gk-gravityview' ) );
464 throw new Exception( esc_html__(
'You do not have a permission to perform this action.',
'gk-gravityview' ) );
469 if ( isset( $licenses_data[ $license_key ] ) ) {
470 throw new Exception( esc_html__(
'This license is already activated.',
'gk-gravityview' ) );
476 if ( ! $response[
'_raw'][
'success'] ) {
480 if ( ! $response[
'_raw'][
'success'] ) {
481 throw new Exception( esc_html__(
'Could not get information on products associated with this license.',
'gk-gravityview' ) );
487 unset( $response[
'_raw'] );
489 $licenses_data[ $license_key ] = $response;
493 if ( CoreHelpers::is_network_admin() ) {
494 delete_site_transient(
'update_plugins ' );
496 delete_transient(
'update_plugins' );
514 $payload = wp_parse_args( $payload, [
516 'force_removal' =>
false,
519 if ( ! $payload[
'key'] ) {
520 throw new Exception( esc_html__(
'Missing license key.',
'gk-gravityview' ) );
527 if ( empty( $licenses_data[ $license_key ] ) ) {
528 throw new Exception( esc_html__(
'The license key is invalid.',
'gk-gravityview' ) );
553 if ( ! $force_removal && !
Arr::get( $response,
'_raw.success' ) ) {
557 throw new Exception( esc_html__(
'Failed to deactivate license.',
'gk-gravityview' ) );
561 if ( ! $force_removal ) {
566 unset( $licenses_data[ $license_key ] );
568 if ( CoreHelpers::is_network_admin() ) {
569 delete_site_transient(
'update_plugins ' );
571 delete_transient(
'update_plugins' );
589 $expiry = ! empty( $license[
'expiry'] ) ? $license[
'expiry'] :
'invalid';
592 if ( ! ctype_alpha( $expiry ) ) {
596 ? human_time_diff( $expiry, current_time(
'timestamp' ) ) .
' ' . esc_html_x(
'ago',
'Indicates "time ago"',
'gk-gravityview' )
597 : date_i18n( get_option(
'date_format' ), $expiry );
604 LoggerFramework::get_instance()->error(
'Failed to encrypt license key: ' . $e->getMessage() );
606 $encrypted_key =
'key_encryption_failed';
609 return array_merge( $license, [
611 'expired' => $expired,
612 'key' => $encrypted_key,
627 $length = strlen( $license_key );
628 $visible_count = (int) round( $length / 8 );
629 $hidden_count = $length - ( $visible_count * 4 );
631 return sprintf(
'%s%s%s',
632 substr( $license_key, 0, $visible_count ),
633 str_repeat(
'✽', $hidden_count ),
634 substr( $license_key, ( $visible_count * -1 ), $visible_count )
646 $hardcoded_license_keys = [];
648 foreach ( self::HARDCODED_LICENSE_CONSTANTS as $constant ) {
649 if ( ! defined( $constant ) ) {
653 if ( is_array( constant( $constant ) ) ) {
654 $hardcoded_license_keys = array_merge( $hardcoded_license_keys, constant( $constant ) );
656 $hardcoded_license_keys[] = constant( $constant );
663 $removed_hardcoded_licenses = 0;
665 foreach ( $licenses_data as $key => $license ) {
666 if ( ! empty( $license[
'hardcoded'] ) && ! in_array( $key, $hardcoded_license_keys,
true ) ) {
667 $removed_hardcoded_licenses++;
669 unset( $licenses_data[ $key ] );
673 if ( $removed_hardcoded_licenses ) {
677 if ( empty( $hardcoded_license_keys ) ) {
682 $license_keys_to_check = array_values( array_diff( $hardcoded_license_keys, array_keys( $licenses_data ) ) );
684 if ( empty( $license_keys_to_check ) ) {
689 $checked_licenses = $this->
check_licenses( $license_keys_to_check );
691 LoggerFramework::get_instance()->error(
"Failed to check hardcoded licenses. {$e->getMessage()}." );
696 foreach ( $checked_licenses as $key => $license ) {
697 if ( ! $license[
'_raw'][
'success'] ) {
698 LoggerFramework::get_instance()->warning(
"Hardcoded license {$key} is invalid." );
703 unset( $license[
'_raw'] );
705 $license[
'hardcoded'] =
true;
707 $licenses_data[ $key ] = $license;
723 $logger = LoggerFramework::get_instance();
725 $migration_status_id =
Framework::ID .
'/legacy-licenses-migrated';
727 $save_migration_status_in_db =
function () use ( $migration_status_id ) {
728 update_site_option( $migration_status_id, current_time(
'timestamp' ) );
731 if ( get_site_option( $migration_status_id ) && ! $force_migration ) {
737 $license_keys_to_migrate = [];
740 'gravityformsaddon_gravityview-importer_settings',
741 'gravityformsaddon_gravityview_app_settings',
742 'gravityformsaddon_gravityview-inline-edit_settings',
743 'gravityformsaddon_gravitycharts_settings',
744 'gravityformsaddon_gk-gravityactions_settings',
745 'gravityformsaddon_gravityview-calendar_settings',
746 'gravityformsaddon_gravityexport_settings',
747 'gravityformsaddon_gravityview-entry-revisions_settings',
750 foreach ( $db_options as $option ) {
751 $license =
Arr::get( get_option( $option, [] ),
'license_key' );
753 $option = str_replace( [
'gravityformsaddon_',
'_settings' ],
'', $option );
756 $license_keys_to_migrate[ $license ] = $option;
758 $logger->warning(
"Legacy license not found for {$option}." );
762 if ( empty( $license_keys_to_migrate ) ) {
763 $save_migration_status_in_db();
765 $logger->info(
'Did not find any legacy licenses to migrate.' );
771 $checked_licenses = $this->
check_licenses( array_keys( $license_keys_to_migrate ) );
773 $logger->error(
"Failed to check legacy licenses. {$e->getMessage()}." );
778 foreach ( $checked_licenses as $key => $license ) {
779 if ( ! $license[
'_raw'][
'success'] ) {
780 $logger->warning(
"Legacy license {$key} is invalid." );
788 $logger->error(
"Failed to activate legacy license {$key}. {$e->getMessage()}." );
793 $logger->info(
"Migrated legacy license for {$license_keys_to_migrate[$key]}." );
795 $licenses_data[ $key ] = $license;
798 $save_migration_status_in_db();
815 $last_validation = get_site_transient( $cache_id );
817 if ( $last_validation && ! $skip_cache ) {
823 $revalidated_licenses = [];
825 if ( empty( $licenses_data ) ) {
830 $license_check_result = $this->
check_licenses( array_keys( $licenses_data ) );
832 foreach ( $license_check_result as $key => $license ) {
833 if ( ! $license[
'_raw'][
'success'] ) {
834 LoggerFramework::get_instance()->warning(
"License {$key} is invalid." );
839 unset( $license[
'_raw'] );
841 if ( ! empty( $licenses_data[ $key ][
'hardcoded'] ) ) {
842 $license[
'hardcoded'] =
true;
845 $revalidated_licenses[ $key ] = $license;
848 LoggerFramework::get_instance()->error(
"Failed to revalidate all licenses. {$e->getMessage()}." );
851 set_site_transient( $cache_id, current_time(
'timestamp' ), DAY_IN_SECONDS );
853 if ( ! empty( $revalidated_licenses ) ) {
869 static $products_data;
871 if ( is_multisite() && ! CoreHelpers::is_network_admin() ) {
875 $is_active = CoreHelpers::is_network_admin() ? is_plugin_active_for_network( $plugin_name ) : is_plugin_active( $plugin_name );
877 if ( ! $is_active ) {
883 if ( ! $products_data ) {
887 LoggerFramework::get_instance()->error(
"Failed to get products on the plugins page. {$e->getMessage()}." );
893 if ( ! isset( $products_data[ $plugin_data[
'TextDomain'] ] ) ) {
897 $this_plugin = $products_data[ $plugin_data[
'TextDomain'] ];
899 $valid_licenses = [];
901 foreach ( $this_plugin[
'licenses'] as $license_key ) {
902 if ( ! isset( $licenses_data[ $license_key ] ) ) {
906 $valid_licenses[] = $license_key;
909 if ( ! empty( $valid_licenses ) ) {
913 add_filter(
"after_plugin_row_{$plugin_name}",
function ( $plugin_name, $plugin_data ) use ( $this_plugin ) {
917 esc_html_x(
'This is an unlicensed product. Please [link]visit the licensing page[/link] to enter a valid license or to purchase a new one.',
'Placeholders inside [] are not to be translated.',
'gk-gravityview' ),
919 '[link]' =>
'<a href="' .
$url .
'">',
924 $screen = get_current_screen();
925 $columns = get_column_headers( $screen );
926 $colspan = ! is_countable( $columns ) ? 3 : count( $columns );
927 $plugin_slug = isset( $plugin_data[
'slug'] ) ? $plugin_data[
'slug'] : sanitize_title( $plugin_data[
'Name'] );
928 $plugin_name = $plugin_data[
'Name'];
931 <tr
class=
"plugin-update-tr active gk-custom-plugin-update-message" data-slug=
"{$plugin_slug}11" data-plugin=
"{$plugin_name}">
932 <td colspan=
"{$colspan}" class=
"plugin-update colspanchange">
933 <div
class=
"update-message notice inline notice-error notice-alt">
938 <style>tr[data-slug=
"{$plugin_slug}"]:not(.gk-custom-plugin-update-message) td, tr[data-slug=
"{$plugin_slug}"]:not(.gk-custom-plugin-update-message) th { box-shadow: none !important; }</style>
955 $theme_data = wp_get_theme();
956 $theme = $theme_data->Name .
' ' . $theme_data->Version;
958 $data[
'php_version'] = PHP_VERSION;
959 $data[
'wp_version'] = get_bloginfo(
'version' );
960 $data[
'mysql_version'] = $wpdb->db_version();
962 if ( defined(
'GV_PLUGIN_VERSION' ) ) {
966 if ( class_exists(
'GFForms' ) ) {
967 $data[
'gf_version'] = GFForms::$version;
970 if ( isset( $_SERVER[
'SERVER_SOFTWARE'] ) ) {
971 $data[
'server'] = $_SERVER[
'SERVER_SOFTWARE'];
974 $data[
'multisite'] = is_multisite();
975 $data[
'theme'] = $theme;
976 $data[
'url'] = is_multisite() ? network_home_url() : home_url();
977 $data[
'beta'] = SettingsFramework::get_instance()->get_plugin_setting(
Core::ID,
'beta' );
980 $gravityview_posts = wp_count_posts(
'gravityview',
'readable' );
982 $data[
'view_count'] = null;
983 $data[
'view_first'] = null;
984 $data[
'view_latest'] = null;
986 if ( ! empty( $gravityview_posts->publish ) ) {
987 $data[
'view_count'] = $gravityview_posts->publish;
989 $first = get_posts(
'numberposts=1&post_type=gravityview&post_status=publish&order=ASC' );
990 $latest = get_posts(
'numberposts=1&post_type=gravityview&post_status=publish&order=DESC' );
992 if ( $first = array_shift( $first ) ) {
993 $data[
'view_first'] = $first->post_date;
995 if ( $latest = array_pop( $latest ) ) {
996 $data[
'view_latest'] = $latest->post_date;
1001 if ( class_exists(
'GFFormsModel' ) ) {
1002 $form_data = GFFormsModel::get_form_count();
1004 $data[
'forms_total'] = $form_data[
'total'];
1005 $data[
'forms_active'] = $form_data[
'active'];
1006 $data[
'forms_inactive'] = $form_data[
'inactive'];
1007 $data[
'forms_trash'] = $form_data[
'trash'];
1010 $plugins = CoreHelpers::get_installed_plugins();
1011 foreach ( $plugins as &$plugin ) {
1012 $plugin =
Arr::only( $plugin, [
'name',
'version',
'active',
'network_activated' ] );
1013 $plugin = array_filter( $plugin );
1016 $data[
'plugins'] = $plugins;
1017 $data[
'locale'] = get_locale();
1037 LoggerFramework::get_instance()->warning(
'Unable to get products when adding a badge count for unlicensed products.' );
1044 foreach ( $products_data as $product ) {
1045 if ( $product[
'active'] && empty( $product[
'licenses'] ) ) {
1069 if (
'lifetime' === $expiry ) {
1073 return $expiry < current_time(
'timestamp' );
is_expired_license( $expiry)
Determines if the license has expired.
const GV_PLUGIN_VERSION(! GravityKit\GravityView\Foundation\meets_min_php_version_requirement(__FILE__, '7.2.0'))
Constants.
ajax_get_licenses_data(array $payload)
AJAX request wrapper for the get_licenses_data() method.
recheck_all_licenses( $skip_cache=false)
Rechecks all licenses and updates the database.
const EDD_LICENSES_API_VERSION
check_license( $license_key)
Checks license key for validity.
static get_instance()
Returns class instance.
ajax_deactivate_license(array $payload)
AJAX request wrapper for the deactivate_license() method.
process_hardcoded_licenses()
Saves new or removes existing hardcoded licenses from the license data.
const EDD_ACTION_CHECK_LICENSE
static get( $array, $key, $default=null)
{}
get_site_data()
Retrieves site data (plugin versions, integrations, etc.) to be sent along with the license check...
ajax_activate_license(array $payload)
AJAX request wrapper for the activate_license() method.
get_license_key_status_message( $status)
Returns license status message based on the EDD status code.
static get_instance( $secret_key='')
Returns class instance.
init()
Initializes the class.
display_license_info_on_plugins_page( $plugin_name, $plugin_data)
Optionally adds notices to installed plugins when license is invalid or expired.
modify_license_data_for_frontend_output( $license)
Adds additional data to the license object for use in the frontend.
save_licenses_data(array $licenses_data)
Saves license data in the database.
const HARDCODED_LICENSE_CONSTANTS
check_licenses(array $license_keys)
Checks multiples license keys for validity.
mask_license_key( $license_key)
Masks part of the license key.
const EDD_LICENSES_API_ENDPOINT
static query_api( $url, array $args=[])
Performs remote call to GravityKit's EDD API.
migrate_legacy_licenses( $force_migration=false)
Migrates licenses for products that do not have Foundation integrated.
const EDD_ACTION_DEACTIVATE_LICENSE
static get_instance()
Returns class instance.
perform_remote_license_call( $license, $edd_action)
Performs remote call to the EDD API.
update_submenu_badge_count()
Optionally updates the Licenses submenu badge count if any of the products are unlicensed.
get_product_licenses( $id)
Returns licenses for a product.
static get_instance()
Returns class instance.
get_product_license_map( $key_by='id')
Returns an object keyed by product ID and associated licenses.
get_licenses_data()
Retrieves license data from the database.
const EDD_ACTION_ACTIVATE_LICENSE
configure_ajax_routes(array $routes)
Configures AJAX routes handled by this class.
activate_license( $license_key)
Activates license.
static only( $array, $keys)
{}
static get_request_unique_string()
Returns a unique value that was generated for this request.
deactivate_license( $license_key, $force_removal=false)
Deactivates license.
Logging framework for GravityKit.