PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.7.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.7.1
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.7.1, at vendor/codeinwp/themeisle-sdk/src/Modules/Licenser.php

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