PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.2.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.2.0
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / codeinwp / themeisle-sdk / src / Modules / Licenser.php

Licenser.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.2.0, at vendor/codeinwp/themeisle-sdk/src/Modules/Licenser.php

720 lines 21.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The main loader class for license handling.
4 *
5 * @package ThemeIsleSDK
6 * @subpackage Modules
7 * @copyright Copyright (c) 2017, Marius Cristea
8 * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9 * @since 1.0.0
10 */
11
12 namespace ThemeisleSDK\Modules;
13
14 // Exit if accessed directly.
15 use ThemeisleSDK\Common\Abstract_Module;
16 use ThemeisleSDK\Product;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Licenser module for ThemeIsle SDK.
24 */
25 class Licenser extends Abstract_Module {
26
27 /**
28 * Number of max failed checks before showing the license message.
29 *
30 * @var int $max_failed Maximum failed checks allowed before show the notice
31 */
32 private static $max_failed = 5;
33 /**
34 * License key string.
35 *
36 * @var string $license_key The license key string
37 */
38 public $license_key;
39 /**
40 * This ensures that the custom API request only runs on the second time that WP fires the update check.
41 *
42 * @var bool $do_check Flag for request.
43 */
44 private $do_check = false;
45 /**
46 * Number of failed checks to the api endpoint.
47 *
48 * @var bool $failed_checks
49 */
50 private $failed_checks = 0;
51 /**
52 * The product update response key.
53 *
54 * @var string $product_key Product key.
55 */
56 private $product_key;
57
58 /**
59 * Disable wporg updates for premium products.
60 *
61 * @param string $r Update payload.
62 * @param string $url The api url.
63 *
64 * @return mixed List of themes to check for update.
65 */
66 function disable_wporg_update( $r, $url ) {
67
68 if ( 0 !== strpos( $url, 'https://api.wordpress.org/themes/update-check/' ) ) {
69 return $r;
70 }
71
72 // Decode the JSON response.
73 $themes = json_decode( $r['body']['themes'] );
74
75 unset( $themes->themes->{$this->product->get_slug()} );
76
77 // Encode the updated JSON response.
78 $r['body']['themes'] = json_encode( $themes );
79
80 return $r;
81 }
82
83 /**
84 * Register the setting for the license of the product.
85 *
86 * @return bool
87 */
88 public function register_settings() {
89 if ( ! is_admin() ) {
90 return false;
91 }
92 add_settings_field(
93 $this->product->get_key() . '_license',
94 $this->product->get_name() . ' license',
95 array( $this, 'license_view' ),
96 'general'
97 );
98 }
99
100 /**
101 * The license view field.
102 */
103 public function license_view() {
104 $status = $this->get_license_status();
105 $value = $this->license_key;
106
107 $activate_string = apply_filters( $this->product->get_key() . '_lc_activate_string', 'Activate' );
108 $deactivate_string = apply_filters( $this->product->get_key() . '_lc_deactivate_string', 'Deactivate' );
109 $valid_string = apply_filters( $this->product->get_key() . '_lc_valid_string', 'Valid' );
110 $invalid_string = apply_filters( $this->product->get_key() . '_lc_invalid_string', 'Invalid' );
111 $license_message = apply_filters( $this->product->get_key() . '_lc_license_message', 'Enter your license from %s purchase history in order to get %s updates' );
112
113 echo '<p ><input ' . ( ( 'valid' === $status ) ? ( 'style="border:1px solid #7ad03a; "' ) : '' ) . ' type="text" id="' . $this->product->get_key() . '_license" name="' . $this->product->get_key() . '_license" value="' . $value . '" /><a ' . ( ( 'valid' === $status ) ? ( 'style="color:#fff;background: #7ad03a; display: inline-block;text-decoration: none;font-size: 13px;line-height: 26px;height: 26px; margin-left:5px; padding: 0 10px 1px; -webkit-border-radius: 3px;border-radius: 3px; ">' . $valid_string ) : ( 'style="color:#fff;background: #dd3d36; display: inline-block;text-decoration: none;font-size: 13px;line-height: 26px;height: 26px; margin-left:5px; padding: 0 10px 1px; -webkit-border-radius: 3px;border-radius: 3px; ">' . $invalid_string ) ) . ' </a>&nbsp;&nbsp;&nbsp;<button name="' . $this->product->get_key() . '_btn_trigger" ' . ( ( 'valid' === $status ) ? ( ' class="button button-primary">' . $deactivate_string ) : ( ' class="button button-primary" value="yes" type="submit" >' . $activate_string ) ) . ' </button></p><p class="description">' . sprintf( $license_message, '<a href="' . $this->get_api_url() . '">' . $this->get_distributor_name() . '</a> ', $this->product->get_type() ) . '</p>';
114
115 }
116
117 /**
118 * Return the license status.
119 *
120 * @return string The License status.
121 */
122 public function get_license_status() {
123
124 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
125
126 if ( '' === $license_data ) {
127 return get_option( $this->product->get_key() . '_license_status', 'not_active' );
128 }
129
130 return isset( $license_data->license ) ? $license_data->license : get_option( $this->product->get_key() . '_license_status', 'not_active' );
131
132 }
133
134 /**
135 * Get remote api url.
136 *
137 * @return string Remote api url.
138 */
139 public function get_api_url() {
140 if ( $this->is_from_partner( $this->product ) ) {
141 return 'https://themeisle.com';
142 }
143
144 return $this->product->get_store_url();
145 }
146
147 /**
148 * Get remote api url.
149 *
150 * @return string Remote api url.
151 */
152 public function get_distributor_name() {
153 if ( $this->is_from_partner( $this->product ) ) {
154 return 'ThemeIsle';
155 }
156
157 return $this->product->get_store_name();
158 }
159
160 /**
161 * Show the admin notice regarding the license status.
162 *
163 * @return bool Should we show the notice ?
164 */
165 function show_notice() {
166 if ( ! is_admin() ) {
167 return false;
168 }
169 $status = $this->get_license_status();
170 $no_activations_string = apply_filters( $this->product->get_key() . '_lc_no_activations_string', 'No activations left for %s !!!. You need to upgrade your plan in order to use %s on more websites. Please ask the %s Staff for more details.' );
171 $no_valid_string = apply_filters( $this->product->get_key() . '_lc_no_valid_string', 'In order to benefit from updates and support for %s, please add your license code from your <a href="%s" target="_blank">purchase history</a> and validate it <a href="%s">here</a>. ' );
172 $expiration_string = apply_filters( $this->product->get_key() . '_lc_expiration_string', 'Your license is about to expire for %s. You can go to %s and renew it ' );
173
174 // No activations left for this license.
175 if ( 'valid' != $status && $this->check_activation() ) {
176 ?>
177 <div class="error">
178 <p><strong>
179 <?php
180 echo sprintf(
181 $no_activations_string,
182 $this->product->get_name(),
183 $this->product->get_name(),
184 '<a href="' . $this->get_api_url() . '" target="_blank">' . $this->get_distributor_name() . '</a>'
185 );
186 ?>
187 </strong>
188 </p>
189 </div>
190 <?php
191 return false;
192 }
193 // Invalid license key.
194 if ( 'valid' != $status ) {
195 ?>
196 <div class="error">
197 <p>
198 <strong><?php echo sprintf( $no_valid_string, $this->product->get_name() . ' ' . $this->product->get_type(), $this->get_api_url(), admin_url( 'options-general.php' ) . '#' . $this->product->get_key() ); ?> </strong>
199 </p>
200 </div>
201 <?php
202
203 return false;
204 }
205
206 // Expired and soon to expire license.
207 if ( 'valid' == $status && $this->check_expiration() ) {
208 ?>
209 <div class="update-nag">
210 <p>
211 <strong>
212 <?php
213 echo sprintf(
214 $expiration_string,
215 $this->product->get_name() . ' ' . $this->product->get_type(),
216 '<a href="' . $this->renew_url() . '" target="_blank">' . $this->get_distributor_name() . '</a>'
217 );
218 ?>
219 </strong>
220 </p>
221 </div>
222 <?php
223 return false;
224 }
225
226 return true;
227 }
228
229 /**
230 * Check if the license is active or not.
231 *
232 * @return bool
233 */
234 public function check_activation() {
235 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
236 if ( '' === $license_data ) {
237 return false;
238 }
239
240 return isset( $license_data->error ) ? ( 'no_activations_left' == $license_data->error ) : false;
241
242 }
243
244 /**
245 * Check if the license is about to expire in the next month.
246 *
247 * @return bool
248 */
249 function check_expiration() {
250 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
251 if ( '' === $license_data ) {
252 return false;
253 }
254 if ( ! isset( $license_data->expires ) ) {
255 return false;
256 }
257 if ( strtotime( $license_data->expires ) - time() > 30 * 24 * 3600 ) {
258 return false;
259 }
260
261 return true;
262 }
263
264 /**
265 * Return the renew url from the store used.
266 *
267 * @return string The renew url.
268 */
269 function renew_url() {
270 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
271 if ( '' === $license_data ) {
272 return $this->get_api_url();
273 }
274 if ( ! isset( $license_data->download_id ) || ! isset( $license_data->key ) ) {
275 return $this->get_api_url();
276 }
277
278 return $this->get_api_url() . '/checkout/?edd_license_key=' . $license_data->key . '&download_id=' . $license_data->download_id;
279 }
280
281 /**
282 * Run the license check call.
283 */
284 public function product_valid() {
285 if ( false !== ( $license = get_transient( $this->product->get_key() . '_license_data' ) ) ) {
286 return;
287 }
288 $license = $this->check_license();
289 set_transient( $this->product->get_key() . '_license_data', $license, 12 * HOUR_IN_SECONDS );
290 update_option( $this->product->get_key() . '_license_data', $license );
291 }
292
293 /**
294 * Check the license status.
295 *
296 * @return object The license data.
297 */
298 public function check_license() {
299 $status = $this->get_license_status();
300 if ( 'not_active' == $status ) {
301 $license_data = new \stdClass();
302 $license_data->license = 'not_active';
303
304 return $license_data;
305 }
306 $license = trim( $this->license_key );
307 $api_params = array(
308 'edd_action' => 'check_license',
309 'license' => $license,
310 'item_name' => rawurlencode( $this->product->get_name() ),
311 'url' => rawurlencode( home_url() ),
312 );
313 // Call the custom API.
314 $response = wp_remote_get(
315 add_query_arg( $api_params, $this->get_api_url() ),
316 array(
317 'timeout' => 15,
318 'sslverify' => false,
319 )
320 );
321 if ( is_wp_error( $response ) ) {
322 $license_data = new \stdClass();
323 $license_data->license = 'valid';
324
325 } else {
326 $license_data = json_decode( wp_remote_retrieve_body( $response ) );
327 if ( ! is_object( $license_data ) ) {
328 $license_data = new \stdClass();
329 $license_data->license = 'valid';
330 }
331 }
332 $license_old = get_option( $this->product->get_key() . '_license_data', '' );
333 if ( 'valid' == $license_old->license && ( $license_data->license != $license_old->license ) ) {
334 $this->increment_failed_checks();
335 } else {
336 $this->reset_failed_checks();
337 }
338
339 if ( $this->failed_checks <= self::$max_failed ) {
340 return $license_old;
341 }
342
343 if ( isset( $license_old->hide_valid ) ) {
344 $license_data->hide_valid = true;
345 }
346
347 if ( ! isset( $license_data->key ) ) {
348 $license_data->key = isset( $license_old->key ) ? $license_old->key : '';
349 }
350
351 if ( isset( $license_old->hide_expiration ) ) {
352 $license_data->hide_expiration = true;
353 }
354
355 if ( isset( $license_old->hide_activation ) ) {
356 $license_data->hide_activation = true;
357 }
358
359 return $license_data;
360
361 }
362
363 /**
364 * Increment the failed checks.
365 */
366 private function increment_failed_checks() {
367 $this->failed_checks ++;
368 update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
369 }
370
371 /**
372 * Reset the failed checks
373 */
374 private function reset_failed_checks() {
375 $this->failed_checks = 1;
376 update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
377 }
378
379 /**
380 * Activate the license remotely.
381 */
382 function activate_license() {
383 // listen for our activate button to be clicked.
384 if ( ! isset( $_POST[ $this->product->get_key() . '_btn_trigger' ] ) ) {
385 return;
386 }
387 $status = $this->get_license_status();
388 // retrieve the license from the database.
389 $license = $_POST[ $this->product->get_key() . '_license' ];
390 $api_params = array(
391 'license' => $license,
392 'item_name' => rawurlencode( $this->product->get_name() ),
393 'url' => rawurlencode( home_url() ),
394 );
395 if ( 'valid' != $status ) {
396 // data to send in our API request.
397 $api_params['edd_action'] = 'activate_license';
398 } else {
399 $api_params['edd_action'] = 'deactivate_license';
400 }
401 // Call the custom API.
402 $response = wp_remote_get( add_query_arg( $api_params, $this->get_api_url() ) );
403 // make sure the response came back okay.
404 if ( is_wp_error( $response ) ) {
405 $license_data = new \stdClass();
406 $license_data->license = ( 'valid' != $status ) ? 'valid' : 'invalid';
407
408 } else {
409 $license_data = json_decode( wp_remote_retrieve_body( $response ) );
410 if ( ! is_object( $license_data ) ) {
411 $license_data = new \stdClass();
412 $license_data->license = ( 'valid' != $status ) ? 'valid' : 'invalid';
413 }
414 if ( ! isset( $license_data->license ) ) {
415 $license_data->license = 'invalid';
416 }
417 }
418 if ( ! isset( $license_data->key ) ) {
419 $license_data->key = $license;
420 }
421 if ( 'valid' == $license_data->license ) {
422 $this->reset_failed_checks();
423 }
424
425 if ( isset( $license_data->plan ) ) {
426 update_option( $this->product->get_key() . '_license_plan', $license_data->plan );
427 }
428
429 update_option( $this->product->get_key() . '_license_data', $license_data );
430 set_transient( $this->product->get_key() . '_license_data', $license_data, 12 * HOUR_IN_SECONDS );
431
432 }
433
434 /**
435 * Load the Themes screen.
436 */
437 function load_themes_screen() {
438 add_thickbox();
439 add_action( 'admin_notices', array( &$this, 'update_nag' ) );
440 }
441
442 /**
443 * Alter the nag for themes update.
444 */
445 function update_nag() {
446 $theme = wp_get_theme( $this->product->get_slug() );
447 $api_response = get_transient( $this->product_key );
448 if ( false === $api_response ) {
449 return;
450 }
451 $update_url = wp_nonce_url( 'update.php?action=upgrade-theme&amp;theme=' . urlencode( $this->product->get_slug() ), 'upgrade-theme_' . $this->product->get_slug() );
452 $update_message = apply_filters( 'themeisle_sdk_license_update_message', 'Updating this theme will lose any customizations you have made. Cancel to stop, OK to update.' );
453 $update_onclick = ' onclick="if ( confirm(\'' . esc_js( $update_message ) . '\') ) {return true;}return false;"';
454 if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
455 echo '<div id="update-nag">';
456 printf(
457 '<strong>%1$s %2$s</strong> is available. <a href="%3$s" class="thickbox" title="%4s">Check out what\'s new</a> or <a href="%5$s"%6$s>update now</a>.',
458 $theme->get( 'Name' ),
459 $api_response->new_version,
460 '#TB_inline?width=640&amp;inlineId=' . $this->product->get_version() . '_changelog',
461 $theme->get( 'Name' ),
462 $update_url,
463 $update_onclick
464 );
465 echo '</div>';
466 echo '<div id="' . $this->product->get_slug() . '_' . 'changelog" style="display:none;">';
467 echo wpautop( $api_response->sections['changelog'] );
468 echo '</div>';
469 }
470 }
471
472 /**
473 * Alter update transient.
474 *
475 * @param mixed $value The transient data.
476 *
477 * @return mixed
478 */
479 function theme_update_transient( $value ) {
480 $update_data = $this->check_for_update();
481 if ( $update_data ) {
482 $value->response[ $this->product->get_slug() ] = $update_data;
483 }
484
485 return $value;
486 }
487
488 /**
489 * Check for updates
490 *
491 * @return array|bool Either the update data or false in case of failure.
492 */
493 function check_for_update() {
494 $update_data = get_transient( $this->product_key );
495
496 if ( false === $update_data ) {
497 $failed = false;
498 $update_data = $this->get_version_data();
499 if ( empty( $update_data ) ) {
500 $failed = true;
501 }
502 // If the response failed, try again in 30 minutes.
503 if ( $failed ) {
504 $data = new \stdClass();
505 $data->new_version = $this->product->get_version();
506 set_transient( $this->product_key, $data, 30 * MINUTE_IN_SECONDS );
507
508 return false;
509 }
510 $update_data->sections = maybe_unserialize( $update_data->sections );
511
512 set_transient( $this->product_key, $update_data, 12 * HOUR_IN_SECONDS );
513 }
514 if ( ! isset( $update_data->new_version ) ) {
515 return false;
516 }
517 if ( version_compare( $this->product->get_version(), $update_data->new_version, '>=' ) ) {
518 return false;
519 }
520
521 return (array) $update_data;
522 }
523
524 /**
525 * Check remote api for latest version.
526 *
527 * @return bool|mixed Update api response.
528 */
529 private function get_version_data() {
530 $api_params = array(
531 'edd_action' => 'get_version',
532 'version' => $this->product->get_version(),
533 'license' => $this->license_key,
534 'name' => $this->product->get_name(),
535 'slug' => $this->product->get_slug(),
536 'author' => $this->get_distributor_name(),
537 'url' => rawurlencode( home_url() ),
538 );
539 $response = wp_remote_get(
540 $this->get_api_url(),
541 array(
542 'timeout' => 15,
543 'sslverify' => false,
544 'body' => $api_params,
545 )
546 );
547 if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
548 return false;
549 }
550 $update_data = json_decode( wp_remote_retrieve_body( $response ) );
551 if ( ! is_object( $update_data ) ) {
552 return false;
553 }
554
555 return $update_data;
556 }
557
558 /**
559 * Delete the update transient
560 */
561 function delete_theme_update_transient() {
562 delete_transient( $this->product_key );
563 }
564
565 /**
566 * Check for Updates at the defined API endpoint and modify the update array.
567 *
568 * @param array $_transient_data Update array build by WordPress.
569 *
570 * @return mixed Modified update array with custom plugin data.
571 */
572 public function pre_set_site_transient_update_plugins_filter( $_transient_data ) {
573 if ( empty( $_transient_data ) || ! $this->do_check ) {
574 $this->do_check = true;
575
576 return $_transient_data;
577 }
578 $api_response = $this->api_request();
579 if ( false !== $api_response && is_object( $api_response ) && isset( $api_response->new_version ) ) {
580 if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
581 $_transient_data->response[ $this->product->get_slug() . '/' . $this->product->get_file() ] = $api_response;
582 }
583 }
584
585 return $_transient_data;
586 }
587
588 /**
589 * Calls the API and, if successfull, returns the object delivered by the API.
590 *
591 * @param string $_action The requested action.
592 * @param array $_data Parameters for the API action.
593 *
594 * @return false||object
595 */
596 private function api_request( $_action = '', $_data = '' ) {
597 $update_data = $this->get_version_data();
598 if ( empty( $update_data ) ) {
599 return false;
600 }
601 if ( $update_data && isset( $update_data->sections ) ) {
602 $update_data->sections = maybe_unserialize( $update_data->sections );
603 }
604
605 return $update_data;
606 }
607
608 /**
609 * Updates information on the "View version x.x details" page with custom data.
610 *
611 * @param mixed $_data Plugin data.
612 * @param string $_action Action to send.
613 * @param object $_args Arguments to use.
614 *
615 * @return object $_data
616 */
617 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
618 if ( ( 'plugin_information' != $_action ) || ! isset( $_args->slug ) || ( $_args->slug != $this->product->get_slug() ) ) {
619 return $_data;
620 }
621 $api_response = $this->api_request();
622 if ( false !== $api_response ) {
623 $_data = $api_response;
624 }
625
626 return $_data;
627 }
628
629 /**
630 * Disable SSL verification in order to prevent download update failures.
631 *
632 * @param array $args Http args.
633 * @param string $url Url to check.
634 *
635 * @return array $array
636 */
637 function http_request_args( $args, $url ) {
638 // If it is an https request and we are performing a package download, disable ssl verification.
639 if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
640 $args['sslverify'] = false;
641 }
642
643 return $args;
644 }
645
646 /**
647 * Check if we should load the module for this product.
648 *
649 * @param Product $product Product data.
650 *
651 * @return bool Should we load the module?
652 */
653 public function can_load( $product ) {
654
655 if ( $product->is_wordpress_available() ) {
656 return false;
657 }
658
659 return ( apply_filters( $product->get_key() . '_enable_licenser', true ) === true );
660
661 }
662
663 /**
664 * Load module logic.
665 *
666 * @param Product $product Product to load the module for.
667 *
668 * @return Licenser Module object.
669 */
670 public function load( $product ) {
671 $this->product = $product;
672
673 $this->product_key = $this->product->get_key() . '-update-response';
674
675 $this->license_key = $this->product->get_license();
676 if ( $this->product->requires_license() ) {
677 $this->failed_checks = intval( get_option( $this->product->get_key() . '_failed_checks', 0 ) );
678 $this->register_license_hooks();
679 }
680
681 if ( $this->product->is_plugin() ) {
682 add_filter(
683 'pre_set_site_transient_update_plugins',
684 [
685 $this,
686 'pre_set_site_transient_update_plugins_filter',
687 ]
688 );
689 add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
690 add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 );
691
692 return $this;
693 }
694 if ( $this->product->is_theme() ) {
695 add_filter( 'site_transient_update_themes', array( &$this, 'theme_update_transient' ) );
696 add_filter( 'delete_site_transient_update_themes', array( &$this, 'delete_theme_update_transient' ) );
697 add_action( 'load-update-core.php', array( &$this, 'delete_theme_update_transient' ) );
698 add_action( 'load-themes.php', array( &$this, 'delete_theme_update_transient' ) );
699 add_action( 'load-themes.php', array( &$this, 'load_themes_screen' ) );
700 add_filter( 'http_request_args', array( $this, 'disable_wporg_update' ), 5, 2 );
701
702 return $this;
703
704 }
705
706 return $this;
707 }
708
709 /**
710 * Register license fields for the products.
711 */
712 public function register_license_hooks() {
713 add_action( 'admin_init', array( $this, 'register_settings' ) );
714 add_action( 'admin_init', array( $this, 'activate_license' ) );
715 add_action( 'admin_init', array( $this, 'product_valid' ), 99999999 );
716 add_action( 'admin_notices', array( $this, 'show_notice' ) );
717 add_filter( $this->product->get_key() . '_license_status', array( $this, 'get_license_status' ) );
718 }
719 }
720