PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.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 3.10.4 All 148 releases
visualizer / vendor / codeinwp / themeisle-sdk / src / Modules / Licenser.php

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

1,004 lines 28.6 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\Loader;
17 use ThemeisleSDK\Product;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 /**
24 * Licenser module for ThemeIsle SDK.
25 */
26 class Licenser extends Abstract_Module {
27
28 /**
29 * Number of max failed checks before showing the license message.
30 *
31 * @var int $max_failed Maximum failed checks allowed before show the notice
32 */
33 private static $max_failed = 5;
34 /**
35 * License key string.
36 *
37 * @var string $license_key The license key string
38 */
39 public $license_key;
40 /**
41 * This ensures that the custom API request only runs on the second time that WP fires the update check.
42 *
43 * @var bool $do_check Flag for request.
44 */
45 private $do_check = false;
46 /**
47 * Number of failed checks to the api endpoint.
48 *
49 * @var bool $failed_checks
50 */
51 private $failed_checks = 0;
52 /**
53 * The product update response key.
54 *
55 * @var string $product_key Product key.
56 */
57 private $product_key;
58
59 /**
60 * Holds local license object.
61 *
62 * @var null Local license object.
63 */
64 private $license_local = null;
65
66 /**
67 * Disable wporg updates for premium products.
68 *
69 * @param string $r Update payload.
70 * @param string $url The api url.
71 *
72 * @return mixed List of themes to check for update.
73 */
74 function disable_wporg_update( $r, $url ) {
75
76 if ( 0 !== strpos( $url, 'https://api.wordpress.org/themes/update-check/' ) ) {
77 return $r;
78 }
79
80 // Decode the JSON response.
81 $themes = json_decode( $r['body']['themes'] );
82
83 unset( $themes->themes->{$this->product->get_slug()} );
84
85 // Encode the updated JSON response.
86 $r['body']['themes'] = json_encode( $themes );
87
88 return $r;
89 }
90
91 /**
92 * Register the setting for the license of the product.
93 *
94 * @return bool
95 */
96 public function register_settings() {
97 if ( ! is_admin() ) {
98 return false;
99 }
100 if ( apply_filters( $this->product->get_key() . '_hide_license_field', false ) ) {
101 return;
102 }
103 add_settings_field(
104 $this->product->get_key() . '_license',
105 $this->product->get_name() . ' license',
106 array( $this, 'license_view' ),
107 'general'
108 );
109 }
110
111 /**
112 * The license view field.
113 */
114 public function license_view() {
115 $status = $this->get_license_status();
116 $value = $this->license_key;
117
118 $activate_string = apply_filters( $this->product->get_key() . '_lc_activate_string', 'Activate' );
119 $deactivate_string = apply_filters( $this->product->get_key() . '_lc_deactivate_string', 'Deactivate' );
120 $valid_string = apply_filters( $this->product->get_key() . '_lc_valid_string', 'Valid' );
121 $invalid_string = apply_filters( $this->product->get_key() . '_lc_invalid_string', 'Invalid' );
122 $license_message = apply_filters( $this->product->get_key() . '_lc_license_message', 'Enter your license from %s purchase history in order to get %s updates' );
123 $error_message = $this->get_error();
124 ?>
125 <style type="text/css">
126 input.themeisle-sdk-text-input-valid {
127 border: 1px solid #7ad03a;
128 }
129
130 input.themeisle-sdk-license-input {
131 width: 300px;
132 padding: 0 8px;
133 line-height: 2;
134 min-height: 30px;
135 }
136
137 .themeisle-sdk-license-deactivate-cta {
138 color: #fff;
139 background: #7ad03a;
140 display: inline-block;
141 text-decoration: none;
142 font-size: 13px;
143 line-height: 30px;
144 height: 26px;
145 margin-left: 5px;
146 padding: 0 10px 3px;
147 -webkit-border-radius: 3px;
148 border-radius: 3px;
149 }
150
151 .themeisle-sdk-license-activate-cta {
152 color: #fff;
153 background: #dd3d36;
154 display: inline-block;
155 text-decoration: none;
156 font-size: 13px;
157 line-height: 30px;
158 height: 26px;
159 margin-left: 5px;
160 padding: 0 10px 3px;
161 -webkit-border-radius: 3px;
162 border-radius: 3px;
163 }
164
165 button.button.themeisle-sdk-licenser-button-cta {
166 line-height: 26px;
167 height: 29px;
168 vertical-align: top;
169 }
170
171 </style>
172 <?php
173 echo sprintf(
174 '<p>%s<input class="themeisle-sdk-license-input %s" type="text" id="%s_license" name="%s_license" value="%s" /><a class="%s">%s</a>&nbsp;&nbsp;&nbsp;<button name="%s_btn_trigger" class="button button-primary themeisle-sdk-licenser-button-cta" value="yes" type="submit" >%s</button></p><p class="description">%s</p>%s',
175 ( ( 'valid' === $status ) ? sprintf( '<input type="hidden" value="%s" name="%s_license" />', $value, $this->product->get_key() ) : '' ),
176 ( ( 'valid' === $status ) ? 'themeisle-sdk-text-input-valid' : '' ),
177 $this->product->get_key(),
178 ( ( 'valid' === $status ) ? $this->product->get_key() . '_mask' : $this->product->get_key() ),
179 ( ( 'valid' === $status ) ? ( str_repeat( '*', 30 ) . substr( $value, - 5 ) ) : $value ),
180 ( 'valid' === $status ? 'themeisle-sdk-license-deactivate-cta' : 'themeisle-sdk-license-activate-cta' ),
181 ( 'valid' === $status ? $valid_string : $invalid_string ),
182 $this->product->get_key(),
183 ( 'valid' === $status ? $deactivate_string : $activate_string ),
184 sprintf( $license_message, '<a href="' . $this->get_api_url() . '">' . $this->get_distributor_name() . '</a> ', $this->product->get_type() ),
185 empty( $error_message ) ? '' : sprintf( '<p style="color:#dd3d36">%s</p>', $error_message )
186 );
187
188 }
189
190 /**
191 * Return the license status.
192 *
193 * @param bool $check_expiration Should check if license is valid, but expired.
194 *
195 * @return string The License status.
196 */
197 public function get_license_status( $check_expiration = false ) {
198
199 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
200
201 if ( '' === $license_data ) {
202 return get_option( $this->product->get_key() . '_license_status', 'not_active' );
203 }
204 $status = isset( $license_data->license ) ? $license_data->license : get_option( $this->product->get_key() . '_license_status', 'not_active' );
205 if ( false === $check_expiration ) {
206 return $status;
207 }
208
209 return ( 'valid' === $status && isset( $license_data->is_expired ) && 'yes' === $license_data->is_expired ) ? 'active_expired' : $status;
210 }
211
212 /**
213 * License price id.
214 *
215 * @return int License plan.
216 */
217 public function get_plan() {
218 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
219 if ( ! isset( $license_data->price_id ) ) {
220 return -1;
221 }
222
223 return (int) $license_data->price_id;
224 }
225
226 /**
227 * Get remote api url.
228 *
229 * @return string Remote api url.
230 */
231 public function get_api_url() {
232 if ( $this->is_from_partner( $this->product ) ) {
233 return 'https://themeisle.com';
234 }
235
236 return $this->product->get_store_url();
237 }
238
239 /**
240 * Get remote api url.
241 *
242 * @return string Remote api url.
243 */
244 public function get_distributor_name() {
245 if ( $this->is_from_partner( $this->product ) ) {
246 return 'ThemeIsle';
247 }
248
249 return $this->product->get_store_name();
250 }
251
252 /**
253 * Show the admin notice regarding the license status.
254 *
255 * @return bool Should we show the notice ?
256 */
257 function show_notice() {
258 if ( ! is_admin() ) {
259 return false;
260 }
261
262 if ( apply_filters( $this->product->get_key() . '_hide_license_notices', false ) ) {
263 return false;
264 }
265
266 $status = $this->get_license_status( true );
267 $no_activations_string = apply_filters( $this->product->get_key() . '_lc_no_activations_string', 'No more activations left for %s. You need to upgrade your plan in order to use %s on more websites. If you need assistance, please get in touch with %s staff.' );
268 $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>. ' );
269 $expired_license_string = apply_filters( $this->product->get_key() . '_lc_expired_string', 'Your %s License Key has expired. In order to continue receiving support and software updates you must <a href="%s" target="_blank">renew</a> your license key.' );
270 // No activations left for this license.
271 if ( 'valid' != $status && $this->check_activation() ) {
272 ?>
273 <div class="error">
274 <p><strong>
275 <?php
276 echo sprintf(
277 $no_activations_string,
278 $this->product->get_name(),
279 $this->product->get_name(),
280 '<a href="' . $this->get_api_url() . '" target="_blank">' . $this->get_distributor_name() . '</a>'
281 );
282 ?>
283 </strong>
284 </p>
285 </div>
286 <?php
287 return false;
288 }
289
290 // Invalid license key.
291 if ( 'active_expired' === $status ) {
292 ?>
293 <div class="error">
294 <p>
295 <strong><?php echo sprintf( $expired_license_string, $this->product->get_name() . ' ' . $this->product->get_type(), $this->get_api_url() . '?license=' . $this->license_key ); ?> </strong>
296 </p>
297 </div>
298 <?php
299
300 return false;
301 }
302 // Invalid license key.
303 if ( 'valid' != $status ) {
304 ?>
305 <div class="error">
306 <p>
307 <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() . '_license' ); ?> </strong>
308 </p>
309 </div>
310 <?php
311
312 return false;
313 }
314
315 return true;
316 }
317
318 /**
319 * Check if the license is active or not.
320 *
321 * @return bool
322 */
323 public function check_activation() {
324 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
325 if ( '' === $license_data ) {
326 return false;
327 }
328
329 return isset( $license_data->license ) ? ( 'no_activations_left' == $license_data->license ) : false;
330
331 }
332
333 /**
334 * Check if the license is about to expire in the next month.
335 *
336 * @return bool
337 */
338 function check_expiration() {
339 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
340 if ( '' === $license_data ) {
341 return false;
342 }
343 if ( ! isset( $license_data->expires ) ) {
344 return false;
345 }
346 if ( strtotime( $license_data->expires ) - time() > 30 * 24 * 3600 ) {
347 return false;
348 }
349
350 return true;
351 }
352
353 /**
354 * Return the renew url from the store used.
355 *
356 * @return string The renew url.
357 */
358 function renew_url() {
359 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
360 if ( '' === $license_data ) {
361 return $this->get_api_url();
362 }
363 if ( ! isset( $license_data->download_id ) || ! isset( $license_data->key ) ) {
364 return $this->get_api_url();
365 }
366
367 return $this->get_api_url() . '/checkout/?edd_license_key=' . $license_data->key . '&download_id=' . $license_data->download_id;
368 }
369
370 /**
371 * Run the license check call.
372 */
373 public function product_valid() {
374 if ( false !== ( $license = get_transient( $this->product->get_key() . '_license_data' ) ) ) {
375 return;
376 }
377 $license = $this->check_license();
378 set_transient( $this->product->get_key() . '_license_data', $license, 12 * HOUR_IN_SECONDS );
379 update_option( $this->product->get_key() . '_license_data', $license );
380 }
381
382 /**
383 * Check the license status.
384 *
385 * @return object The license data.
386 */
387 public function check_license() {
388 $status = $this->get_license_status();
389 if ( 'not_active' === $status ) {
390 $license_data = new \stdClass();
391 $license_data->license = 'not_active';
392
393 return $license_data;
394 }
395 $license = trim( $this->license_key );
396
397 $response = $this->do_license_process( $license, 'check' );
398
399 if ( is_wp_error( $response ) ) {
400 $license_data = new \stdClass();
401 $license_data->license = 'valid';
402 } else {
403 $license_data = $response;
404 }
405
406 $license_old = get_option( $this->product->get_key() . '_license_data', '' );
407
408 if ( 'valid' === $license_old->license && ( $license_data->license !== $license_old->license ) ) {
409 $this->increment_failed_checks();
410 } else {
411 $this->reset_failed_checks();
412 }
413
414 if ( $this->failed_checks <= self::$max_failed ) {
415 return $license_old;
416 }
417
418 if ( ! isset( $license_data->key ) ) {
419 $license_data->key = isset( $license_old->key ) ? $license_old->key : '';
420 }
421
422 return $license_data;
423
424 }
425
426 /**
427 * Increment the failed checks.
428 */
429 private function increment_failed_checks() {
430 $this->failed_checks ++;
431 update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
432 }
433
434 /**
435 * Reset the failed checks
436 */
437 private function reset_failed_checks() {
438 $this->failed_checks = 1;
439 update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
440 }
441
442 /**
443 * Set license validation error message.
444 *
445 * @param string $message Error message.
446 */
447 public function set_error( $message = '' ) {
448 set_transient( $this->product->get_key() . 'act_err', $message, MINUTE_IN_SECONDS );
449
450 return;
451 }
452
453 /**
454 * Return the last error message.
455 *
456 * @return mixed Error message.
457 */
458 public function get_error() {
459 return get_transient( $this->product->get_key() . 'act_err' );
460 }
461
462 /**
463 * Do license activation/deactivation.
464 *
465 * @param string $license License key.
466 * @param string $action What do to.
467 *
468 * @return bool|\WP_Error
469 */
470 public function do_license_process( $license, $action = 'toggle' ) {
471 if ( strlen( $license ) < 10 ) {
472 return new \WP_Error( 'themeisle-license-invalid-format', 'Invalid license.' );
473 }
474 $status = $this->get_license_status();
475
476 if ( 'valid' === $status && 'activate' === $action ) {
477 return new \WP_Error( 'themeisle-license-already-active', 'License is already active.' );
478 }
479 if ( 'valid' !== $status && 'deactivate' === $action ) {
480 return new \WP_Error( 'themeisle-license-already-deactivate', 'License not active.' );
481 }
482
483 if ( 'toggle' === $action ) {
484 $action = ( 'valid' !== $status ? ( 'activate' ) : ( 'deactivate' ) );
485 }
486
487 // Call the custom API.
488 if ( 'check' === $action ) {
489 $response = wp_remote_get( sprintf( '%slicense/check/%s/%s/%s/%s', Product::API_URL, rawurlencode( $this->product->get_name() ), $license, rawurlencode( home_url() ), Loader::get_cache_token() ) );
490 } else {
491 $response = wp_remote_post(
492 sprintf( '%slicense/%s/%s/%s', Product::API_URL, $action, rawurlencode( $this->product->get_name() ), $license ),
493 array(
494 'body' => wp_json_encode(
495 array(
496 'url' => rawurlencode( home_url() ),
497 )
498 ),
499 'headers' => array(
500 'Content-Type' => 'application/json',
501 ),
502 )
503 );
504 }
505
506 // make sure the response came back okay.
507 if ( is_wp_error( $response ) ) {
508 return new \WP_Error( 'themeisle-license-500', sprintf( 'ERROR: Failed to connect to the license service. Please try again later. Reason: %s', $response->get_error_message() ) );
509 }
510
511 $license_data = json_decode( wp_remote_retrieve_body( $response ) );
512
513 if ( ! is_object( $license_data ) ) {
514 return new \WP_Error( 'themeisle-license-404', 'ERROR: Failed to validate license. Please try again in one minute.' );
515 }
516 if ( 'check' === $action ) {
517 return $license_data;
518 }
519
520 Loader::clear_cache_token();
521
522 if ( ! isset( $license_data->license ) ) {
523 $license_data->license = 'invalid';
524 }
525
526 if ( ! isset( $license_data->key ) ) {
527 $license_data->key = $license;
528 }
529 if ( 'valid' === $license_data->license ) {
530 $this->reset_failed_checks();
531 }
532
533 if ( 'deactivate' === $action ) {
534
535 delete_option( $this->product->get_key() . '_license_data' );
536 delete_option( $this->product->get_key() . '_license_plan' );
537 delete_transient( $this->product->get_key() . '_license_data' );
538
539 return true;
540 }
541 if ( isset( $license_data->plan ) ) {
542 update_option( $this->product->get_key() . '_license_plan', $license_data->plan );
543 }
544 update_option( $this->product->get_key() . '_license_data', $license_data );
545 set_transient( $this->product->get_key() . '_license_data', $license_data, 12 * HOUR_IN_SECONDS );
546 if ( 'activate' === $action && 'valid' !== $license_data->license ) {
547 return new \WP_Error( 'themeisle-license-invalid', 'ERROR: Invalid license provided.' );
548 }
549
550 return true;
551 }
552
553 /**
554 * Activate the license remotely.
555 */
556 function process_license() {
557 // listen for our activate button to be clicked.
558 if ( ! isset( $_POST[ $this->product->get_key() . '_btn_trigger' ] ) ) {
559 return;
560 }
561 $license = $_POST[ $this->product->get_key() . '_license' ];
562 $response = $this->do_license_process( $license, 'toggle' );
563 if ( is_wp_error( $response ) ) {
564 $this->set_error( $response->get_error_message() );
565
566 return;
567 }
568 if ( true === $response ) {
569 $this->set_error( '' );
570 }
571
572 return;
573 }
574
575 /**
576 * Load the Themes screen.
577 */
578 function load_themes_screen() {
579 add_thickbox();
580 add_action( 'admin_notices', array( &$this, 'update_nag' ) );
581 }
582
583 /**
584 * Alter the nag for themes update.
585 */
586 function update_nag() {
587 $theme = wp_get_theme( $this->product->get_slug() );
588 $api_response = get_transient( $this->product_key );
589 if ( false === $api_response || ! isset( $api_response->new_version ) ) {
590 return;
591 }
592 $update_url = wp_nonce_url( 'update.php?action=upgrade-theme&amp;theme=' . urlencode( $this->product->get_slug() ), 'upgrade-theme_' . $this->product->get_slug() );
593 $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.' );
594 $update_onclick = ' onclick="if ( confirm(\'' . esc_js( $update_message ) . '\') ) {return true;}return false;"';
595 if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
596 echo '<div id="update-nag">';
597 printf(
598 '<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>.',
599 $theme->get( 'Name' ),
600 $api_response->new_version,
601 sprintf( '%s&TB_iframe=true&amp;width=1024&amp;height=800', $this->product->get_changelog() ),
602 $theme->get( 'Name' ),
603 $update_url,
604 $update_onclick
605 );
606 echo '</div>';
607 echo '<div id="' . $this->product->get_slug() . '_' . 'changelog" style="display:none;">';
608 echo wpautop( $api_response->sections['changelog'] );
609 echo '</div>';
610 }
611 }
612
613 /**
614 * Alter update transient.
615 *
616 * @param mixed $value The transient data.
617 *
618 * @return mixed
619 */
620 function theme_update_transient( $value ) {
621 $update_data = $this->check_for_update();
622 if ( $update_data ) {
623 $value->response[ $this->product->get_slug() ] = $update_data;
624 }
625
626 return $value;
627 }
628
629 /**
630 * Check for updates
631 *
632 * @return array|bool Either the update data or false in case of failure.
633 */
634 function check_for_update() {
635 $update_data = get_transient( $this->product_key );
636
637 if ( false === $update_data ) {
638 $failed = false;
639 $update_data = $this->get_version_data();
640 if ( empty( $update_data ) ) {
641 $failed = true;
642 }
643 // If the response failed, try again in 30 minutes.
644 if ( $failed ) {
645 $data = new \stdClass();
646 $data->new_version = $this->product->get_version();
647 set_transient( $this->product_key, $data, 30 * MINUTE_IN_SECONDS );
648
649 return false;
650 }
651 $update_data->sections = isset( $update_data->sections ) ? maybe_unserialize( $update_data->sections ) : null;
652
653 set_transient( $this->product_key, $update_data, 12 * HOUR_IN_SECONDS );
654 }
655 if ( ! isset( $update_data->new_version ) ) {
656 return false;
657 }
658 if ( version_compare( $this->product->get_version(), $update_data->new_version, '>=' ) ) {
659 return false;
660 }
661
662 return (array) $update_data;
663 }
664
665 /**
666 * Check remote api for latest version.
667 *
668 * @return bool|mixed Update api response.
669 */
670 private function get_version_data() {
671
672 $response = wp_remote_get(
673 sprintf(
674 '%slicense/version/%s/%s/%s/%s',
675 Product::API_URL,
676 rawurlencode( $this->product->get_name() ),
677 ( empty( $this->license_key ) ? 'free' : $this->license_key ),
678 $this->product->get_version(),
679 rawurlencode( home_url() )
680 ),
681 array(
682 'timeout' => 15,
683 'sslverify' => false,
684 )
685 );
686 if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
687 return false;
688 }
689 $update_data = json_decode( wp_remote_retrieve_body( $response ) );
690 if ( ! is_object( $update_data ) ) {
691 return false;
692 }
693 if ( isset( $update_data->slug ) ) {
694 $update_data->slug = $this->product->get_slug();
695 }
696 if ( isset( $update_data->icons ) ) {
697 $update_data->icons = (array) $update_data->icons;
698 }
699 if ( isset( $update_data->banners ) ) {
700 $update_data->banners = (array) $update_data->banners;
701 }
702
703 return $update_data;
704 }
705
706 /**
707 * Delete the update transient
708 */
709 function delete_theme_update_transient() {
710 delete_transient( $this->product_key );
711 }
712
713 /**
714 * Check for Updates at the defined API endpoint and modify the update array.
715 *
716 * @param array $_transient_data Update array build by WordPress.
717 *
718 * @return mixed Modified update array with custom plugin data.
719 */
720 public function pre_set_site_transient_update_plugins_filter( $_transient_data ) {
721 if ( empty( $_transient_data ) || ! $this->do_check ) {
722 $this->do_check = true;
723
724 return $_transient_data;
725 }
726 $api_response = $this->api_request();
727 if ( false !== $api_response && is_object( $api_response ) && isset( $api_response->new_version ) ) {
728 if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
729 $_transient_data->response[ $this->product->get_slug() . '/' . $this->product->get_file() ] = $api_response;
730 }
731 }
732
733 return $_transient_data;
734 }
735
736 /**
737 * Calls the API and, if successfull, returns the object delivered by the API.
738 *
739 * @param string $_action The requested action.
740 * @param array $_data Parameters for the API action.
741 *
742 * @return false||object
743 */
744 private function api_request( $_action = '', $_data = '' ) {
745 $update_data = $this->get_version_data();
746 if ( empty( $update_data ) ) {
747 return false;
748 }
749 if ( $update_data && isset( $update_data->sections ) ) {
750 $update_data->sections = maybe_unserialize( $update_data->sections );
751 }
752
753 return $update_data;
754 }
755
756 /**
757 * Updates information on the "View version x.x details" page with custom data.
758 *
759 * @param mixed $_data Plugin data.
760 * @param string $_action Action to send.
761 * @param object $_args Arguments to use.
762 *
763 * @return object $_data
764 */
765 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
766 if ( ( 'plugin_information' !== $_action ) || ! isset( $_args->slug ) || ( $_args->slug !== $this->product->get_slug() ) ) {
767 return $_data;
768 }
769 $api_response = $this->api_request();
770 if ( false !== $api_response ) {
771 $_data = $api_response;
772 }
773
774 return $_data;
775 }
776
777 /**
778 * Disable SSL verification in order to prevent download update failures.
779 *
780 * @param array $args Http args.
781 * @param string $url Url to check.
782 *
783 * @return array $array
784 */
785 function http_request_args( $args, $url ) {
786 // If it is an https request and we are performing a package download, disable ssl verification.
787 if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
788 $args['sslverify'] = false;
789 }
790
791 return $args;
792 }
793
794 /**
795 * Check if we should load the module for this product.
796 *
797 * @param Product $product Product data.
798 *
799 * @return bool Should we load the module?
800 */
801 public function can_load( $product ) {
802
803 if ( $product->is_wordpress_available() ) {
804 return false;
805 }
806
807 return ( apply_filters( $product->get_key() . '_enable_licenser', true ) === true );
808
809 }
810
811 /**
812 * Load module logic.
813 *
814 * @param Product $product Product to load the module for.
815 *
816 * @return Licenser Module object.
817 */
818 public function load( $product ) {
819 $this->product = $product;
820
821 $this->product_key = $this->product->get_key() . '-update-response';
822
823 $this->license_key = $this->product->get_license();
824 if ( $this->product->requires_license() ) {
825 $this->failed_checks = intval( get_option( $this->product->get_key() . '_failed_checks', 0 ) );
826 $this->register_license_hooks();
827 }
828
829 $namespace = apply_filters( 'themesle_sdk_namespace_' . md5( $product->get_basefile() ), false );
830
831 if ( false !== $namespace ) {
832 add_filter( 'themeisle_sdk_license_process_' . $namespace, [ $this, 'do_license_process' ], 10, 2 );
833 add_filter( 'product_' . $namespace . '_license_status', [ $this, 'get_license_status' ], PHP_INT_MAX );
834 add_filter( 'product_' . $namespace . '_license_key', [ $this->product, 'get_license' ] );
835 add_filter( 'product_' . $namespace . '_license_plan', [ $this, 'get_plan' ], PHP_INT_MAX );
836 if ( defined( 'WP_CLI' ) && WP_CLI ) {
837 \WP_CLI::add_command( $namespace . ' activate', [ $this, 'cli_activate' ] );
838 \WP_CLI::add_command( $namespace . ' deactivate', [ $this, 'cli_deactivate' ] );
839 \WP_CLI::add_command( $namespace . ' is-active', [ $this, 'cli_is_active' ] );
840 }
841 }
842
843 add_action( 'admin_head', [ $this, 'auto_activate' ] );
844 if ( $this->product->is_plugin() ) {
845 add_filter(
846 'pre_set_site_transient_update_plugins',
847 [
848 $this,
849 'pre_set_site_transient_update_plugins_filter',
850 ]
851 );
852 add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
853 add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 );
854
855 return $this;
856 }
857 if ( $this->product->is_theme() ) {
858 add_filter( 'site_transient_update_themes', array( &$this, 'theme_update_transient' ) );
859 add_filter( 'delete_site_transient_update_themes', array( &$this, 'delete_theme_update_transient' ) );
860 add_action( 'load-update-core.php', array( &$this, 'delete_theme_update_transient' ) );
861 add_action( 'load-themes.php', array( &$this, 'delete_theme_update_transient' ) );
862 add_action( 'load-themes.php', array( &$this, 'load_themes_screen' ) );
863 add_filter( 'http_request_args', array( $this, 'disable_wporg_update' ), 5, 2 );
864
865 return $this;
866
867 }
868
869 return $this;
870 }
871
872 /**
873 * Run license activation on plugin activate.
874 */
875 public function auto_activate() {
876 if ( ! current_user_can( 'switch_themes' ) ) {
877 return;
878 }
879 $status = $this->get_license_status();
880 if ( 'not_active' !== $status ) {
881 return;
882 }
883
884 $license_file = dirname( $this->product->get_basefile() ) . '/license.json';
885
886 global $wp_filesystem;
887 if ( ! is_file( $license_file ) ) {
888 return;
889 }
890
891 require_once( ABSPATH . '/wp-admin/includes/file.php' );
892 \WP_Filesystem();
893 $content = json_decode( $wp_filesystem->get_contents( $license_file ) );
894 if ( ! is_object( $content ) ) {
895 return;
896 }
897 if ( ! isset( $content->key ) ) {
898 return;
899 }
900 $this->license_local = $content;
901 $lock_key = $this->product->get_key() . '_autoactivated';
902
903 if ( 'yes' === get_option( $lock_key, '' ) ) {
904 return;
905 }
906 $response = $this->do_license_process( $content->key, 'activate' );
907
908 update_option( $lock_key, 'yes' );
909
910 if ( apply_filters( $this->product->get_key() . '_hide_license_notices', false ) ) {
911 return;
912 }
913
914 if ( true === $response ) {
915 add_action( 'admin_notices', [ $this, 'autoactivate_notice' ] );
916 }
917 }
918
919 /**
920 * Show auto-activate notice.
921 */
922 public function autoactivate_notice() {
923 ?>
924 <div class="notice notice-success is-dismissible">
925 <p><?php echo sprintf( '<strong>%s</strong> has been successfully activated using <strong>%s</strong> license !', $this->product->get_name(), str_repeat( '*', 20 ) . substr( $this->license_local->key, - 10 ) ); ?></p>
926 </div>
927 <?php
928 }
929
930 /**
931 * Activate product license on this site.
932 *
933 * ## OPTIONS
934 *
935 * @param array $args Command args.
936 *
937 * [<license-key>]
938 * : Product license key.
939 */
940 public function cli_activate( $args ) {
941 $license_key = isset( $args[0] ) ? trim( $args[0] ) : '';
942 $response = $this->do_license_process( $license_key, 'activate' );
943 if ( true !== $response ) {
944 \WP_CLI::error( $response->get_error_message() );
945
946 return;
947 }
948
949 \WP_CLI::success( 'Product successfully activated.' );
950 }
951
952 /**
953 * Deactivate product license on this site.
954 *
955 * @param array $args Command args.
956 *
957 * ## OPTIONS
958 *
959 * [<license-key>]
960 * : Product license key.
961 */
962 public function cli_deactivate( $args ) {
963 $license_key = isset( $args[0] ) ? trim( $args[0] ) : '';
964 $response = $this->do_license_process( $license_key, 'deactivate' );
965 if ( true !== $response ) {
966 \WP_CLI::error( $response->get_error_message() );
967
968 return;
969 }
970
971 \WP_CLI::success( 'Product successfully deactivated.' );
972 }
973
974 /**
975 * Checks if product has license activated.
976 *
977 * @param array $args Command args.
978 *
979 * @subcommand is-active
980 */
981 public function cli_is_active( $args ) {
982
983 $status = $this->get_license_status();
984 if ( 'valid' === $status ) {
985 \WP_CLI::halt( 0 );
986
987 return;
988 }
989
990 \WP_CLI::halt( 1 );
991 }
992
993 /**
994 * Register license fields for the products.
995 */
996 public function register_license_hooks() {
997 add_action( 'admin_init', array( $this, 'register_settings' ) );
998 add_action( 'admin_init', array( $this, 'process_license' ) );
999 add_action( 'admin_init', array( $this, 'product_valid' ), 99999999 );
1000 add_action( 'admin_notices', array( $this, 'show_notice' ) );
1001 add_filter( $this->product->get_key() . '_license_status', array( $this, 'get_license_status' ) );
1002 }
1003 }
1004