PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.0.10
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.0.10
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 / class-themeisle-sdk-licenser.php

class-themeisle-sdk-licenser.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.0.10, at vendor/codeinwp/themeisle-sdk/class-themeisle-sdk-licenser.php

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