PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.5.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.5.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
← All changes | vendor/codeinwp/themeisle-sdk/src/Modules/Licenser.php +467 -145 3.1.33.5.1 View file →
@@ -12,8 +12,9 @@
12 12 namespace ThemeisleSDK\Modules;
13 13
14 14 // Exit if accessed directly.
15 15 use ThemeisleSDK\Common\Abstract_Module;
16 +use ThemeisleSDK\Loader;
16 17 use ThemeisleSDK\Product;
17 18
18 19 if ( ! defined( 'ABSPATH' ) ) {
19 20 exit;
@@ -55,8 +56,21 @@
55 56 */
56 57 private $product_key;
57 58
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 + /**
59 73 * Disable wporg updates for premium products.
60 74 *
61 75 * @param string $r Update payload.
62 76 * @param string $url The api url.
@@ -62,9 +76,9 @@
62 76 * @param string $url The api url.
63 77 *
64 78 * @return mixed List of themes to check for update.
65 79 */
66 - function disable_wporg_update( $r, $url ) {
80 + public function disable_wporg_update( $r, $url ) {
67 81
68 82 if ( 0 !== strpos( $url, 'https://api.wordpress.org/themes/update-check/' ) ) {
69 83 return $r;
70 84 }
@@ -74,9 +88,9 @@
74 88
75 89 unset( $themes->themes->{$this->product->get_slug()} );
76 90
77 91 // Encode the updated JSON response.
78 - $r['body']['themes'] = json_encode( $themes );
92 + $r['body']['themes'] = wp_json_encode( $themes );
79 93
80 94 return $r;
81 95 }
82 96
@@ -88,8 +102,11 @@
88 102 public function register_settings() {
89 103 if ( ! is_admin() ) {
90 104 return false;
91 105 }
106 + if ( apply_filters( $this->product->get_key() . '_hide_license_field', false ) ) {
107 + return;
108 + }
92 109 add_settings_field(
93 110 $this->product->get_key() . '_license',
94 111 $this->product->get_name() . ' license',
95 112 array( $this, 'license_view' ),
@@ -108,19 +125,83 @@
108 125 $deactivate_string = apply_filters( $this->product->get_key() . '_lc_deactivate_string', 'Deactivate' );
109 126 $valid_string = apply_filters( $this->product->get_key() . '_lc_valid_string', 'Valid' );
110 127 $invalid_string = apply_filters( $this->product->get_key() . '_lc_invalid_string', 'Invalid' );
111 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 + }
112 135
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>';
136 + input.themeisle-sdk-license-input {
137 + width: 300px;
138 + padding: 0 8px;
139 + line-height: 2;
140 + min-height: 30px;
141 + }
114 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 +
115 194 }
116 195
117 196 /**
118 197 * Return the license status.
119 198 *
199 + * @param bool $check_expiration Should check if license is valid, but expired.
200 + *
120 201 * @return string The License status.
121 202 */
122 - public function get_license_status() {
203 + public function get_license_status( $check_expiration = false ) {
123 204
124 205 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
125 206
126 207 if ( '' === $license_data ) {
@@ -125,11 +206,23 @@
125 206
126 207 if ( '' === $license_data ) {
127 208 return get_option( $this->product->get_key() . '_license_status', 'not_active' );
128 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 + }
129 214
130 - return isset( $license_data->license ) ? $license_data->license : get_option( $this->product->get_key() . '_license_status', 'not_active' );
215 + return ( 'valid' === $status && isset( $license_data->is_expired ) && 'yes' === $license_data->is_expired ) ? 'active_expired' : $status;
216 + }
131 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' );
132 225 }
133 226
134 227 /**
135 228 * Get remote api url.
@@ -157,21 +250,39 @@
157 250 return $this->product->get_store_name();
158 251 }
159 252
160 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 + /**
161 268 * Show the admin notice regarding the license status.
162 269 *
163 270 * @return bool Should we show the notice ?
164 271 */
165 - function show_notice() {
272 + public function show_notice() {
166 273 if ( ! is_admin() ) {
167 274 return false;
168 275 }
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 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 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.' );
174 285 // No activations left for this license.
175 286 if ( 'valid' != $status && $this->check_activation() ) {
176 287 ?>
177 288 <div class="error">
@@ -177,12 +288,12 @@
177 288 <div class="error">
178 289 <p><strong>
179 290 <?php
180 291 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>'
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>'
185 296 );
186 297 ?>
187 298 </strong>
188 299 </p>
@@ -189,14 +300,15 @@
189 300 </div>
190 301 <?php
191 302 return false;
192 303 }
304 +
193 305 // Invalid license key.
194 - if ( 'valid' != $status ) {
306 + if ( 'active_expired' === $status ) {
195 307 ?>
196 308 <div class="error">
197 309 <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>
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>
199 311 </p>
200 312 </div>
201 313 <?php
202 314
@@ -201,26 +313,18 @@
201 313 <?php
202 314
203 315 return false;
204 316 }
205 -
206 - // Expired and soon to expire license.
207 - if ( 'valid' == $status && $this->check_expiration() ) {
317 + // Invalid license key.
318 + if ( 'valid' != $status ) {
208 319 ?>
209 - <div class="update-nag">
320 + <div class="error">
210 321 <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>
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>
220 323 </p>
221 324 </div>
222 325 <?php
326 +
223 327 return false;
224 328 }
225 329
226 330 return true;
@@ -236,9 +340,9 @@
236 340 if ( '' === $license_data ) {
237 341 return false;
238 342 }
239 343
240 - return isset( $license_data->error ) ? ( 'no_activations_left' == $license_data->error ) : false;
344 + return isset( $license_data->license ) ? ( 'no_activations_left' == $license_data->license ) : false;
241 345
242 346 }
243 347
244 348 /**
@@ -245,9 +349,9 @@
245 349 * Check if the license is about to expire in the next month.
246 350 *
247 351 * @return bool
248 352 */
249 - function check_expiration() {
353 + public function check_expiration() {
250 354 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
251 355 if ( '' === $license_data ) {
252 356 return false;
253 357 }
@@ -265,9 +369,9 @@
265 369 * Return the renew url from the store used.
266 370 *
267 371 * @return string The renew url.
268 372 */
269 - function renew_url() {
373 + public function renew_url() {
270 374 $license_data = get_option( $this->product->get_key() . '_license_data', '' );
271 375 if ( '' === $license_data ) {
272 376 return $this->get_api_url();
273 377 }
@@ -281,9 +385,9 @@
281 385 /**
282 386 * Run the license check call.
283 387 */
284 388 public function product_valid() {
285 - if ( false !== ( $license = get_transient( $this->product->get_key() . '_license_data' ) ) ) {
389 + if ( false !== ( $license = get_transient( $this->product->get_key() . '_license_data' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
286 390 return;
287 391 }
288 392 $license = $this->check_license();
289 393 set_transient( $this->product->get_key() . '_license_data', $license, 12 * HOUR_IN_SECONDS );
@@ -296,42 +400,28 @@
296 400 * @return object The license data.
297 401 */
298 402 public function check_license() {
299 403 $status = $this->get_license_status();
300 - if ( 'not_active' == $status ) {
404 + if ( 'not_active' === $status ) {
301 405 $license_data = new \stdClass();
302 406 $license_data->license = 'not_active';
303 407
304 408 return $license_data;
305 409 }
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 - );
410 + $license = trim( $this->license_key );
411 +
412 + $response = $this->do_license_process( $license, 'check' );
413 +
321 414 if ( is_wp_error( $response ) ) {
322 415 $license_data = new \stdClass();
323 416 $license_data->license = 'valid';
324 -
325 417 } 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 - }
418 + $license_data = $response;
331 419 }
420 +
332 421 $license_old = get_option( $this->product->get_key() . '_license_data', '' );
333 - if ( 'valid' == $license_old->license && ( $license_data->license != $license_old->license ) ) {
422 +
423 + if ( 'valid' === $license_old->license && ( $license_data->license !== $license_old->license ) ) {
334 424 $this->increment_failed_checks();
335 425 } else {
336 426 $this->reset_failed_checks();
337 427 }
@@ -339,41 +429,120 @@
339 429 if ( $this->failed_checks <= self::$max_failed ) {
340 430 return $license_old;
341 431 }
342 432
343 - if ( isset( $license_old->hide_valid ) ) {
344 - $license_data->hide_valid = true;
433 + if ( ! isset( $license_data->key ) ) {
434 + $license_data->key = isset( $license_old->key ) ? $license_old->key : '';
345 435 }
346 436
347 - if ( ! isset( $license_data->key ) ) {
348 - $license_data->key = isset( $license_old->key ) ? $license_old->key : '';
437 + return $license_data;
438 +
439 + }
440 +
441 + /**
442 + * Do license activation/deactivation.
443 + *
444 + * @param string $license License key.
445 + * @param string $action What do to.
446 + *
447 + * @return bool|\WP_Error
448 + */
449 + public function do_license_process( $license, $action = 'toggle' ) {
450 + if ( strlen( $license ) < 10 ) {
451 + return new \WP_Error( 'themeisle-license-invalid-format', 'Invalid license.' );
349 452 }
453 + $status = $this->get_license_status();
350 454
351 - if ( isset( $license_old->hide_expiration ) ) {
352 - $license_data->hide_expiration = true;
455 + if ( 'valid' === $status && 'activate' === $action ) {
456 + return new \WP_Error( 'themeisle-license-already-active', 'License is already active.' );
353 457 }
458 + if ( 'valid' !== $status && 'deactivate' === $action ) {
459 + return new \WP_Error( 'themeisle-license-already-deactivate', 'License not active.' );
460 + }
354 461
355 - if ( isset( $license_old->hide_activation ) ) {
356 - $license_data->hide_activation = true;
462 + if ( 'toggle' === $action ) {
463 + $action = ( 'valid' !== $status ? ( 'activate' ) : ( 'deactivate' ) );
357 464 }
358 465
359 - return $license_data;
466 + // Call the custom API.
467 + if ( 'check' === $action ) {
468 + $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() ) );
469 + } else {
470 + $response = wp_remote_post(
471 + sprintf( '%slicense/%s/%s/%s', Product::API_URL, $action, rawurlencode( $this->product->get_name() ), $license ),
472 + array(
473 + 'body' => wp_json_encode(
474 + array(
475 + 'url' => rawurlencode( home_url() ),
476 + )
477 + ),
478 + 'headers' => array(
479 + 'Content-Type' => 'application/json',
480 + ),
481 + )
482 + );
483 + }
360 484
485 + // make sure the response came back okay.
486 + if ( is_wp_error( $response ) ) {
487 + 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() ) );
488 + }
489 +
490 + $license_data = json_decode( wp_remote_retrieve_body( $response ) );
491 +
492 + if ( ! is_object( $license_data ) ) {
493 + return new \WP_Error( 'themeisle-license-404', 'ERROR: Failed to validate license. Please try again in one minute.' );
494 + }
495 + if ( 'check' === $action ) {
496 + return $license_data;
497 + }
498 +
499 + Loader::clear_cache_token();
500 +
501 + if ( ! isset( $license_data->license ) ) {
502 + $license_data->license = 'invalid';
503 + }
504 +
505 + if ( ! isset( $license_data->key ) ) {
506 + $license_data->key = $license;
507 + }
508 + if ( 'valid' === $license_data->license ) {
509 + $this->reset_failed_checks();
510 + }
511 +
512 + if ( 'deactivate' === $action ) {
513 +
514 + delete_option( $this->product->get_key() . '_license_data' );
515 + delete_option( $this->product->get_key() . '_license_plan' );
516 + delete_transient( $this->product->get_key() . '_license_data' );
517 +
518 + return true;
519 + }
520 + if ( isset( $license_data->plan ) ) {
521 + update_option( $this->product->get_key() . '_license_plan', $license_data->plan );
522 + }
523 + update_option( $this->product->get_key() . '_license_data', $license_data );
524 + set_transient( $this->product->get_key() . '_license_data', $license_data, 12 * HOUR_IN_SECONDS );
525 + if ( 'activate' === $action && 'valid' !== $license_data->license ) {
526 + return new \WP_Error( 'themeisle-license-invalid', 'ERROR: Invalid license provided.' );
527 + }
528 +
529 + return true;
361 530 }
362 531
363 532 /**
364 - * Increment the failed checks.
533 + * Reset the failed checks
365 534 */
366 - private function increment_failed_checks() {
367 - $this->failed_checks ++;
535 + private function reset_failed_checks() {
536 + $this->failed_checks = 1;
368 537 update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
369 538 }
370 539
371 540 /**
372 - * Reset the failed checks
541 + * Increment the failed checks.
373 542 */
374 - private function reset_failed_checks() {
375 - $this->failed_checks = 1;
543 + private function increment_failed_checks() {
544 + $this->failed_checks ++;
376 545 update_option( $this->product->get_key() . '_failed_checks', $this->failed_checks );
377 546 }
378 547
379 548 /**
@@ -378,64 +547,50 @@
378 547
379 548 /**
380 549 * Activate the license remotely.
381 550 */
382 - function activate_license() {
551 + public function process_license() {
383 552 // listen for our activate button to be clicked.
384 553 if ( ! isset( $_POST[ $this->product->get_key() . '_btn_trigger' ] ) ) {
385 554 return;
386 555 }
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';
556 + if ( ! isset( $_POST[ $this->product->get_key() . 'nonce_field' ] )
557 + || ! wp_verify_nonce( $_POST[ $this->product->get_key() . 'nonce_field' ], $this->product->get_key() . 'nonce' ) //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
558 + ) {
559 + return;
400 560 }
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.
561 + if ( ! current_user_can( 'manage_options' ) ) {
562 + return;
563 + }
564 + $license = isset( $_POST[ $this->product->get_key() . '_license' ] )
565 + ? sanitize_text_field( $_POST[ $this->product->get_key() . '_license' ] )
566 + : '';
567 +
568 + $response = $this->do_license_process( $license, 'toggle' );
404 569 if ( is_wp_error( $response ) ) {
405 - $license_data = new \stdClass();
406 - $license_data->license = ( 'valid' != $status ) ? 'valid' : 'invalid';
570 + $this->set_error( $response->get_error_message() );
407 571
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 - }
572 + return;
417 573 }
418 - if ( ! isset( $license_data->key ) ) {
419 - $license_data->key = $license;
574 + if ( true === $response ) {
575 + $this->set_error( '' );
420 576 }
421 - if ( 'valid' == $license_data->license ) {
422 - $this->reset_failed_checks();
423 - }
577 + }
424 578
425 - if ( isset( $license_data->plan ) ) {
426 - update_option( $this->product->get_key() . '_license_plan', $license_data->plan );
427 - }
579 + /**
580 + * Set license validation error message.
581 + *
582 + * @param string $message Error message.
583 + */
584 + public function set_error( $message = '' ) {
585 + set_transient( $this->product->get_key() . 'act_err', $message, MINUTE_IN_SECONDS );
428 586
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 587 }
433 588
434 589 /**
435 590 * Load the Themes screen.
436 591 */
437 - function load_themes_screen() {
592 + public function load_themes_screen() {
438 593 add_thickbox();
439 594 add_action( 'admin_notices', array( &$this, 'update_nag' ) );
440 595 }
441 596
@@ -441,12 +596,12 @@
441 596
442 597 /**
443 598 * Alter the nag for themes update.
444 599 */
445 - function update_nag() {
600 + public function update_nag() {
446 601 $theme = wp_get_theme( $this->product->get_slug() );
447 602 $api_response = get_transient( $this->product_key );
448 - if ( false === $api_response ) {
603 + if ( false === $api_response || ! isset( $api_response->new_version ) ) {
449 604 return;
450 605 }
451 606 $update_url = wp_nonce_url( 'update.php?action=upgrade-theme&amp;theme=' . urlencode( $this->product->get_slug() ), 'upgrade-theme_' . $this->product->get_slug() );
452 607 $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.' );
@@ -454,18 +609,18 @@
454 609 if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
455 610 echo '<div id="update-nag">';
456 611 printf(
457 612 '<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
613 + esc_attr( $theme->get( 'Name' ) ),
614 + esc_attr( $api_response->new_version ),
615 + esc_url( sprintf( '%s&TB_iframe=true&amp;width=1024&amp;height=800', $this->product->get_changelog() ) ),
616 + esc_attr( $theme->get( 'Name' ) ),
617 + esc_url( $update_url ),
618 + $update_onclick // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, Already escaped.
464 619 );
465 620 echo '</div>';
466 - echo '<div id="' . $this->product->get_slug() . '_' . 'changelog" style="display:none;">';
467 - echo wpautop( $api_response->sections['changelog'] );
621 + echo '<div id="' . esc_attr( $this->product->get_slug() ) . '_changelog" style="display:none;">';
622 + echo wp_kses_data( wpautop( $api_response->sections['changelog'] ) );
468 623 echo '</div>';
469 624 }
470 625 }
471 626
@@ -475,9 +630,9 @@
475 630 * @param mixed $value The transient data.
476 631 *
477 632 * @return mixed
478 633 */
479 - function theme_update_transient( $value ) {
634 + public function theme_update_transient( $value ) {
480 635 $update_data = $this->check_for_update();
481 636 if ( $update_data ) {
482 637 $value->response[ $this->product->get_slug() ] = $update_data;
483 638 }
@@ -489,9 +644,9 @@
489 644 * Check for updates
490 645 *
491 646 * @return array|bool Either the update data or false in case of failure.
492 647 */
493 - function check_for_update() {
648 + public function check_for_update() {
494 649 $update_data = get_transient( $this->product_key );
495 650
496 651 if ( false === $update_data ) {
497 652 $failed = false;
@@ -506,9 +661,9 @@
506 661 set_transient( $this->product_key, $data, 30 * MINUTE_IN_SECONDS );
507 662
508 663 return false;
509 664 }
510 - $update_data->sections = maybe_unserialize( $update_data->sections );
665 + $update_data->sections = isset( $update_data->sections ) ? maybe_unserialize( $update_data->sections ) : null;
511 666
512 667 set_transient( $this->product_key, $update_data, 12 * HOUR_IN_SECONDS );
513 668 }
514 669 if ( ! isset( $update_data->new_version ) ) {
@@ -526,23 +681,21 @@
526 681 *
527 682 * @return bool|mixed Update api response.
528 683 */
529 684 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(),
685 +
686 + $response = $this->safe_get(
687 + sprintf(
688 + '%slicense/version/%s/%s/%s/%s',
689 + Product::API_URL,
690 + rawurlencode( $this->product->get_name() ),
691 + ( empty( $this->license_key ) ? 'free' : $this->license_key ),
692 + $this->product->get_version(),
693 + rawurlencode( home_url() )
694 + ),
541 695 array(
542 - 'timeout' => 15,
696 + 'timeout' => 15, //phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout, Inherited by wp_remote_get only, for vip environment we use defaults.
543 697 'sslverify' => false,
544 - 'body' => $api_params,
545 698 )
546 699 );
547 700 if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
548 701 return false;
@@ -550,8 +703,17 @@
550 703 $update_data = json_decode( wp_remote_retrieve_body( $response ) );
551 704 if ( ! is_object( $update_data ) ) {
552 705 return false;
553 706 }
707 + if ( isset( $update_data->slug ) ) {
708 + $update_data->slug = $this->product->get_slug();
709 + }
710 + if ( isset( $update_data->icons ) ) {
711 + $update_data->icons = (array) $update_data->icons;
712 + }
713 + if ( isset( $update_data->banners ) ) {
714 + $update_data->banners = (array) $update_data->banners;
715 + }
554 716
555 717 return $update_data;
556 718 }
557 719
@@ -557,10 +719,10 @@
557 719
558 720 /**
559 721 * Delete the update transient
560 722 */
561 - function delete_theme_update_transient() {
562 - delete_transient( $this->product_key );
723 + public function delete_theme_update_transient() {
724 + return delete_transient( $this->product_key );
563 725 }
564 726
565 727 /**
566 728 * Check for Updates at the defined API endpoint and modify the update array.
@@ -578,8 +740,10 @@
578 740 $api_response = $this->api_request();
579 741 if ( false !== $api_response && is_object( $api_response ) && isset( $api_response->new_version ) ) {
580 742 if ( version_compare( $this->product->get_version(), $api_response->new_version, '<' ) ) {
581 743 $_transient_data->response[ $this->product->get_slug() . '/' . $this->product->get_file() ] = $api_response;
744 + } else {
745 + $_transient_data->no_update[ $this->product->get_slug() . '/' . $this->product->get_file() ] = $api_response;
582 746 }
583 747 }
584 748
585 749 return $_transient_data;
@@ -614,9 +778,9 @@
614 778 *
615 779 * @return object $_data
616 780 */
617 781 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
618 - if ( ( 'plugin_information' != $_action ) || ! isset( $_args->slug ) || ( $_args->slug != $this->product->get_slug() ) ) {
782 + if ( ( 'plugin_information' !== $_action ) || ! isset( $_args->slug ) || ( $_args->slug !== $this->product->get_slug() ) ) {
619 783 return $_data;
620 784 }
621 785 $api_response = $this->api_request();
622 786 if ( false !== $api_response ) {
@@ -633,9 +797,9 @@
633 797 * @param string $url Url to check.
634 798 *
635 799 * @return array $array
636 800 */
637 - function http_request_args( $args, $url ) {
801 + public function http_request_args( $args, $url ) {
638 802 // If it is an https request and we are performing a package download, disable ssl verification.
639 803 if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
640 804 $args['sslverify'] = false;
641 805 }
@@ -677,8 +841,24 @@
677 841 $this->failed_checks = intval( get_option( $this->product->get_key() . '_failed_checks', 0 ) );
678 842 $this->register_license_hooks();
679 843 }
680 844
845 + $namespace = apply_filters( 'themesle_sdk_namespace_' . md5( $product->get_basefile() ), false );
846 +
847 + if ( false !== $namespace ) {
848 + $this->namespace = $namespace;
849 + add_filter( 'themeisle_sdk_license_process_' . $namespace, [ $this, 'do_license_process' ], 10, 2 );
850 + add_filter( 'product_' . $namespace . '_license_status', [ $this, 'get_license_status' ], PHP_INT_MAX );
851 + add_filter( 'product_' . $namespace . '_license_key', [ $this->product, 'get_license' ] );
852 + add_filter( 'product_' . $namespace . '_license_plan', [ $this, 'get_plan' ], PHP_INT_MAX );
853 + if ( defined( 'WP_CLI' ) && WP_CLI ) {
854 + \WP_CLI::add_command( $namespace . ' activate', [ $this, 'cli_activate' ] );
855 + \WP_CLI::add_command( $namespace . ' deactivate', [ $this, 'cli_deactivate' ] );
856 + \WP_CLI::add_command( $namespace . ' is-active', [ $this, 'cli_is_active' ] );
857 + }
858 + }
859 +
860 + add_action( 'admin_head', [ $this, 'auto_activate' ] );
681 861 if ( $this->product->is_plugin() ) {
682 862 add_filter(
683 863 'pre_set_site_transient_update_plugins',
684 864 [
@@ -686,19 +866,19 @@
686 866 'pre_set_site_transient_update_plugins_filter',
687 867 ]
688 868 );
689 869 add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
690 - add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 );
870 + add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 ); //phpcs:ignore WordPressVIPMinimum.Hooks.RestrictedHooks.http_request_args
691 871
692 872 return $this;
693 873 }
694 874 if ( $this->product->is_theme() ) {
695 875 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' ) );
876 + add_action( 'delete_site_transient_update_themes', array( &$this, 'delete_theme_update_transient' ) );
697 877 add_action( 'load-update-core.php', array( &$this, 'delete_theme_update_transient' ) );
698 878 add_action( 'load-themes.php', array( &$this, 'delete_theme_update_transient' ) );
699 879 add_action( 'load-themes.php', array( &$this, 'load_themes_screen' ) );
700 - add_filter( 'http_request_args', array( $this, 'disable_wporg_update' ), 5, 2 );
880 + add_filter( 'http_request_args', array( $this, 'disable_wporg_update' ), 5, 2 ); //phpcs:ignore WordPressVIPMinimum.Hooks.RestrictedHooks.http_request_args
701 881
702 882 return $this;
703 883
704 884 }
@@ -710,10 +890,152 @@
710 890 * Register license fields for the products.
711 891 */
712 892 public function register_license_hooks() {
713 893 add_action( 'admin_init', array( $this, 'register_settings' ) );
714 - add_action( 'admin_init', array( $this, 'activate_license' ) );
894 + add_action( 'admin_init', array( $this, 'process_license' ) );
715 895 add_action( 'admin_init', array( $this, 'product_valid' ), 99999999 );
716 896 add_action( 'admin_notices', array( $this, 'show_notice' ) );
717 897 add_filter( $this->product->get_key() . '_license_status', array( $this, 'get_license_status' ) );
898 + }
899 +
900 + /**
901 + * Check license on filesystem.
902 + *
903 + * @return mixed License key.
904 + */
905 + public function get_file_license() {
906 +
907 + $license_file = dirname( $this->product->get_basefile() ) . '/license.json';
908 +
909 + global $wp_filesystem;
910 + if ( ! is_file( $license_file ) ) {
911 + return false;
912 + }
913 +
914 + require_once ABSPATH . '/wp-admin/includes/file.php';
915 + \WP_Filesystem();
916 + $content = json_decode( $wp_filesystem->get_contents( $license_file ) );
917 + if ( ! is_object( $content ) ) {
918 + return false;
919 + }
920 + if ( ! isset( $content->key ) ) {
921 + return false;
922 + }
923 + return $content->key;
924 + }
925 + /**
926 + * Run license activation on plugin activate.
927 + */
928 + public function auto_activate() {
929 + $status = $this->get_license_status();
930 + if ( 'not_active' !== $status ) {
931 + return false;
932 + }
933 +
934 + if ( ! empty( $this->namespace ) ) {
935 + $license_key = apply_filters( 'product_' . $this->namespace . '_license_key_constant', '' );
936 + }
937 +
938 + if ( empty( $license_key ) ) {
939 + $license_key = $this->get_file_license();
940 + }
941 + if ( empty( $license_key ) ) {
942 + return;
943 + }
944 +
945 +
946 + $this->license_local = $license_key;
947 + $lock_key = $this->product->get_key() . '_autoactivated';
948 +
949 + if ( 'yes' === get_option( $lock_key, '' ) ) {
950 + return;
951 + }
952 + if ( 'yes' === get_transient( $lock_key ) ) {
953 + return;
954 + }
955 + $response = $this->do_license_process( $license_key, 'activate' );
956 +
957 + set_transient( $lock_key, 'yes', 6 * HOUR_IN_SECONDS );
958 +
959 + if ( apply_filters( $this->product->get_key() . '_hide_license_notices', false ) ) {
960 + return;
961 + }
962 +
963 + if ( true === $response ) {
964 + add_action( 'admin_notices', [ $this, 'autoactivate_notice' ] );
965 + }
966 + }
967 +
968 + /**
969 + * Show auto-activate notice.
970 + */
971 + public function autoactivate_notice() {
972 + ?>
973 + <div class="notice notice-success is-dismissible">
974 + <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>
975 + </div>
976 + <?php
977 + }
978 +
979 + /**
980 + * Activate product license on this site.
981 + *
982 + * ## OPTIONS
983 + *
984 + * @param array $args Command args.
985 + *
986 + * [<license-key>]
987 + * : Product license key.
988 + */
989 + public function cli_activate( $args ) {
990 + $license_key = isset( $args[0] ) ? trim( $args[0] ) : '';
991 + $response = $this->do_license_process( $license_key, 'activate' );
992 + if ( true !== $response ) {
993 + \WP_CLI::error( $response->get_error_message() );
994 +
995 + return;
996 + }
997 +
998 + \WP_CLI::success( 'Product successfully activated.' );
999 + }
1000 +
1001 + /**
1002 + * Deactivate product license on this site.
1003 + *
1004 + * @param array $args Command args.
1005 + *
1006 + * ## OPTIONS
1007 + *
1008 + * [<license-key>]
1009 + * : Product license key.
1010 + */
1011 + public function cli_deactivate( $args ) {
1012 + $license_key = isset( $args[0] ) ? trim( $args[0] ) : '';
1013 + $response = $this->do_license_process( $license_key, 'deactivate' );
1014 + if ( true !== $response ) {
1015 + \WP_CLI::error( $response->get_error_message() );
1016 +
1017 + return;
1018 + }
1019 +
1020 + \WP_CLI::success( 'Product successfully deactivated.' );
1021 + }
1022 +
1023 + /**
1024 + * Checks if product has license activated.
1025 + *
1026 + * @param array $args Command args.
1027 + *
1028 + * @subcommand is-active
1029 + */
1030 + public function cli_is_active( $args ) {
1031 +
1032 + $status = $this->get_license_status();
1033 + if ( 'valid' === $status ) {
1034 + \WP_CLI::halt( 0 );
1035 +
1036 + return;
1037 + }
1038 +
1039 + \WP_CLI::halt( 1 );
718 1040 }
719 1041 }