PluginProbe
Borderless – Addons and Templates for Elementor / 1.4.9
Borderless – Addons and Templates for Elementor v1.4.9
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 All 78 releases
borderless / includes / license / client.php

client.php in Borderless – Addons and Templates for Elementor 1.4.9, at includes/license/client.php

1,065 lines 38.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined( 'ABSPATH' ) || exit;
4
5 if ( ! class_exists( 'BORDERLESS__LICENSE' ) ) {
6 class BORDERLESS__LICENSE {
7
8 /**
9 * Class args
10 *
11 * @var string
12 */
13 private $api_url = '';
14 private $data_key = '';
15 private $file = '';
16 private $plugin_name = '';
17 private $plugin_or_theme = '';
18 private $product_id = '';
19 private $slug = '';
20 private $software_title = '';
21 private $software_version = '';
22 private $text_domain = ''; // For language translation.
23
24 /**
25 * Class properties.
26 *
27 * @var string
28 */
29 private $data = array();
30 private $identifier = '';
31 private $no_product_id = false;
32 private $product_id_chosen = 0;
33 private $wc_am_activated_key = '';
34 private $wc_am_activation_tab_key = '';
35 private $wc_am_api_key_key = '';
36 private $wc_am_deactivate_checkbox_key = '';
37 private $wc_am_deactivation_tab_key = '';
38 private $wc_am_auto_update_key = '';
39 private $wc_am_domain = '';
40 private $wc_am_instance_id = '';
41 private $wc_am_instance_key = '';
42 private $wc_am_menu_tab_activation_title = '';
43 private $wc_am_menu_tab_deactivation_title = '';
44 private $wc_am_plugin_name = '';
45 private $wc_am_product_id = '';
46 private $wc_am_renew_license_url = '';
47 private $wc_am_settings_menu_title = '';
48 private $wc_am_settings_title = '';
49 private $wc_am_software_version = '';
50
51 public function __construct( $file, $product_id, $software_version, $plugin_or_theme, $api_url, $software_title = '', $text_domain = '' ) {
52 $this->no_product_id = empty( $product_id );
53 $this->plugin_or_theme = esc_attr( strtolower( $plugin_or_theme ) );
54
55 if ( $this->no_product_id ) {
56 $this->identifier = $this->plugin_or_theme == 'plugin' ? dirname( untrailingslashit( plugin_basename( $file ) ) ) : basename( dirname( plugin_basename( $file ) ) );
57 $product_id = strtolower( str_ireplace( array( ' ', '_', '&', '?', '-' ), '_', $this->identifier ) );
58 $this->wc_am_product_id = 'wc_am_product_id_' . $product_id;
59 $this->product_id_chosen = get_option( $this->wc_am_product_id );
60 } else {
61 /**
62 * Preserve the value of $product_id to use for API requests. Pre 2.0 product_id is a string, and >= 2.0 is an integer.
63 */
64 if ( is_int( $product_id ) ) {
65 $this->product_id = absint( $product_id );
66 } else {
67 $this->product_id = esc_attr( $product_id );
68 }
69 }
70
71 // If the product_id was not provided, but was saved by the customer, used the saved product_id.
72 if ( empty( $this->product_id ) && ! empty( $this->product_id_chosen ) ) {
73 $this->product_id = $this->product_id_chosen;
74 }
75
76 $this->file = $file;
77 $this->software_title = esc_attr( $software_title );
78 $this->software_version = esc_attr( $software_version );
79 $this->api_url = esc_url( $api_url );
80 $this->text_domain = esc_attr( $text_domain );
81 /**
82 * If the product_id is a pre 2.0 string, format it to be used as an option key, otherwise it will be an integer if >= 2.0.
83 */
84 $this->data_key = 'borderless_client_' . strtolower( str_ireplace( array( ' ', '_', '&', '?', '-' ), '_', $product_id ) );
85 $this->wc_am_activated_key = $this->data_key . '_activated';
86
87 if ( is_admin() ) {
88 if ( ! empty( $this->plugin_or_theme ) && $this->plugin_or_theme == 'theme' ) {
89 add_action( 'admin_init', array( $this, 'activation' ) );
90 }
91
92 if ( ! empty( $this->plugin_or_theme ) && $this->plugin_or_theme == 'plugin' ) {
93 register_activation_hook( $this->file, array( $this, 'activation' ) );
94 }
95
96 add_action( 'admin_menu', array( $this, 'register_menu' ) );
97 add_action( 'admin_init', array( $this, 'load_settings' ) );
98 // Check for external connection blocking
99 add_action( 'admin_notices', array( $this, 'check_external_blocking' ) );
100
101 /**
102 * Set all data defaults here
103 */
104 $this->wc_am_api_key_key = $this->data_key . '_api_key';
105 $this->wc_am_instance_key = $this->data_key . '_instance';
106
107 /**
108 * Set all admin menu data
109 */
110 $this->wc_am_deactivate_checkbox_key = $this->data_key . '_deactivate_checkbox';
111 $this->wc_am_activation_tab_key = $this->data_key . '_dashboard';
112 $this->wc_am_deactivation_tab_key = $this->data_key . '_deactivation';
113 $this->wc_am_auto_update_key = $this->data_key . '_auto_update';
114 $this->wc_am_settings_menu_title = esc_html__( ' License', $this->text_domain );
115 $this->wc_am_settings_title = $this->software_title . esc_html__( ' Key Activation', $this->text_domain );
116 $this->wc_am_menu_tab_activation_title = esc_html__( 'Activation', $this->text_domain );
117 $this->wc_am_menu_tab_deactivation_title = esc_html__( 'Deactivation', $this->text_domain );
118
119 /**
120 * Set all software update data here
121 */
122 $this->data = get_option( $this->data_key );
123 $this->wc_am_plugin_name = $this->plugin_or_theme == 'plugin' ? untrailingslashit( plugin_basename( $this->file ) ) : basename( dirname( plugin_basename( $file ) ) ); // same as plugin slug. if a theme use a theme name like 'twentyeleven'
124 $this->wc_am_renew_license_url = $this->api_url . 'my-account'; // URL to renew an API Key. Trailing slash in the upgrade_url is required.
125 $this->wc_am_instance_id = get_option( $this->wc_am_instance_key ); // Instance ID (unique to each blog activation)
126 /**
127 * Some web hosts have security policies that block the : (colon) and // (slashes) in http://,
128 * so only the host portion of the URL can be sent. For example the host portion might be
129 * www.example.com or example.com. http://www.example.com includes the scheme http,
130 * and the host www.example.com.
131 * Sending only the host also eliminates issues when a client site changes from http to https,
132 * but their activation still uses the original scheme.
133 * To send only the host, use a line like the one below:
134 *
135 * $this->wc_am_domain = str_ireplace( array( 'http://', 'https://' ), '', home_url() ); // blog domain name
136 */
137 $this->wc_am_domain = str_ireplace( array( 'http://', 'https://' ), '', home_url() ); // blog domain name
138 $this->wc_am_software_version = $this->software_version; // The software version
139
140 /**
141 * Check for software updates
142 */
143 $this->check_for_update();
144
145 /**
146 * Makes auto updates available if WP >= 5.5.
147 *
148 * @since 2.8
149 */
150 $this->try_automatic_updates();
151
152 if ( $this->plugin_or_theme == 'plugin' ) {
153 //add_action( 'wp_ajax_update_auto_update_setting', array( $this, 'update_auto_update_setting' ) );
154 add_filter( 'plugin_auto_update_setting_html', array( $this, 'auto_update_message' ), 10, 3 );
155 }
156 }
157
158 /**
159 * Deletes all data if plugin deactivated
160 */ //if ( $this->plugin_or_theme == 'plugin' ) {
161 // register_deactivation_hook( $this->file, array( $this, 'uninstall' ) );
162 //}
163 //
164 //if ( $this->plugin_or_theme == 'theme' ) {
165 // add_action( 'switch_theme', array( $this, 'uninstall' ) );
166 //}
167 }
168
169 /**
170 * license_key_deactivation
171 * Register submenu specific to this product.
172 */
173 public function register_menu() {
174 add_submenu_page(
175 'borderless.php',
176 sprintf( __( '%s', 'borderless' ), $this->wc_am_settings_menu_title ),
177 sprintf( __( '%s', 'borderless' ), $this->wc_am_settings_menu_title ),
178 'manage_options',
179 $this->wc_am_activation_tab_key, array(
180 $this,
181 'config_page'
182 )
183 );
184 }
185
186 /**
187 * Tries auto updates.
188 *
189 * @since 2.8
190 */
191 public function try_automatic_updates() {
192 global $wp_version;
193
194 if ( version_compare( $wp_version, '5.5', '>=' ) ) {
195 //if ( empty( get_option( $this->wc_am_auto_update_key ) ) ) {
196 // update_option( $this->wc_am_auto_update_key, 'on' );
197 //}
198
199 if ( $this->plugin_or_theme == 'plugin' ) {
200 add_filter( 'auto_update_plugin', array( $this, 'maybe_auto_update' ), 10, 2 );
201 } elseif ( $this->plugin_or_theme == 'theme' ) {
202 add_filter( 'auto_update_theme', array( $this, 'maybe_auto_update' ), 10, 2 );
203 }
204 }
205 }
206
207 /**
208 * Tries to set auto updates.
209 *
210 * @since 2.8
211 *
212 * @param bool|null $update
213 * @param object $item
214 *
215 * @return bool
216 */
217 public function maybe_auto_update( $update, $item ) {
218 if ( strpos( $this->wc_am_plugin_name, '.php' ) !== 0 ) {
219 $slug = dirname( $this->wc_am_plugin_name );
220 } else {
221 $slug = $this->wc_am_plugin_name;
222 }
223
224 if ( isset( $item->slug ) && $item->slug == $slug ) {
225 if ( $this->is_auto_update_disabled() ) {
226 return false;
227 }
228
229 if ( ! $this->get_api_key_status() || ! $this->get_api_key_status( true ) ) {
230 return false;
231 }
232
233 return true;
234 }
235
236 return $update;
237 }
238
239 /**
240 * Checks if auto updates are disabled.
241 *
242 * @since 2.8
243 *
244 * @return bool
245 */
246 public function is_auto_update_disabled() {
247 /*
248 * WordPress will not offer to update if background updates are disabled.
249 * WordPress background updates are disabled if file changes are not allowed.
250 */
251 if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
252 return true;
253 }
254
255 if ( defined( 'WP_INSTALLING' ) ) {
256 return true;
257 }
258
259 $wp_updates_disabled = defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED;
260
261 /**
262 * Overrides the WordPress AUTOMATIC_UPDATER_DISABLED constant.
263 *
264 * @param bool $wp_updates_disabled true if disables. false otherwise.
265 */
266 $wp_updates_disabled = apply_filters( 'automatic_updater_disabled', $wp_updates_disabled );
267
268 if ( $wp_updates_disabled ) {
269 return true;
270 }
271
272 // Return true if this plugin or theme background update is disabled.
273 // return get_option( $this->wc_am_auto_update_key ) !== 'on';
274
275 return false;
276 }
277
278 /**
279 * Filter the auto-update message on the plugins page.
280 *
281 * Plugin updates stored in 'auto_update_plugins' array.
282 *
283 * @see 'wp-admin/includes/class-wp-plugins-list-table.php'
284 *
285 * @since 2.8
286 *
287 * @param string $html HTML of the auto-update message.
288 * @param string $plugin_file Plugin file.
289 * @param array $plugin_data Plugin details.
290 *
291 * @return mixed|string
292 */
293 public function auto_update_message( $html, $plugin_file, $plugin_data ) {
294 if ( $this->wc_am_plugin_name == $plugin_file ) {
295 global $status, $page;
296
297 // if ( ! $this->get_api_key_status( true ) || get_option( $this->wc_am_auto_update_key ) !== 'on' ) {
298 if ( ! $this->get_api_key_status() || ! $this->get_api_key_status( true ) ) {
299 return esc_html__( 'Auto-updates unavailable.', $this->text_domain );
300 }
301
302 $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
303 $html = array();
304
305 if ( ! empty( $plugin_data[ 'auto-update-forced' ] ) ) {
306 if ( $plugin_data[ 'auto-update-forced' ] ) {
307 // Forced on.
308 $text = __( 'Auto-updates enabled' );
309 } else {
310 $text = __( 'Auto-updates disabled' );
311 }
312
313 $action = 'unavailable';
314 $time_class = ' hidden';
315 } elseif ( in_array( $plugin_file, $auto_updates, true ) ) {
316 $text = __( 'Disable auto-updates' );
317 $action = 'disable';
318 $time_class = '';
319 } else {
320 $text = __( 'Enable auto-updates' );
321 $action = 'enable';
322 $time_class = ' hidden';
323 }
324
325 $query_args = array(
326 'action' => "{$action}-auto-update",
327 'plugin' => $plugin_file,
328 'paged' => $page,
329 'plugin_status' => $status,
330 );
331
332 $url = add_query_arg( $query_args, 'plugins.php' );
333
334 if ( 'unavailable' === $action ) {
335 $html[] = '<span class="label">' . $text . '</span>';
336 } else {
337 $html[] = sprintf( '<a href="%s" class="toggle-auto-update aria-button-if-js" data-wp-action="%s">', wp_nonce_url( $url, 'updates' ), $action );
338
339 $html[] = '<span class="dashicons dashicons-update spin hidden" aria-hidden="true"></span>';
340 $html[] = '<span class="label">' . $text . '</span>';
341 $html[] = '</a>';
342 }
343
344 if ( ! empty( $plugin_data[ 'update' ] ) ) {
345 $html[] = sprintf( '<div class="auto-update-time%s">%s</div>', $time_class, wp_get_auto_update_message() );
346 }
347
348 $html = implode( '', $html );
349 }
350
351 return $html;
352 }
353
354 /**
355 * Generate the default data.
356 */
357 public function activation() {
358 $instance_exists = get_option( $this->wc_am_instance_key );
359
360 if ( get_option( $this->data_key ) === false || $instance_exists === false ) {
361 if ( $instance_exists === false ) {
362 update_option( $this->wc_am_instance_key, wp_generate_password( 12, false ) );
363 }
364
365 update_option( $this->wc_am_deactivate_checkbox_key, 'on' );
366 update_option( $this->wc_am_activated_key, 'Deactivated' );
367 }
368 }
369
370 /**
371 * Deletes all data if plugin deactivated
372 */
373 public function uninstall() {
374 /**
375 * @since 2.5.1
376 *
377 * Filter borderless_client_uninstall_disable
378 * If set to false uninstall() method will be disabled.
379 */
380 if ( apply_filters( 'borderless_client_uninstall_disable', true ) ) {
381 global $blog_id;
382
383 $this->license_key_deactivation();
384
385 // Remove options pre API Manager 2.0
386 if ( is_multisite() ) {
387 switch_to_blog( $blog_id );
388
389 foreach (
390 array(
391 $this->wc_am_instance_key,
392 $this->wc_am_deactivate_checkbox_key,
393 $this->wc_am_activated_key,
394 ) as $option
395 ) {
396
397 delete_option( $option );
398 }
399
400 restore_current_blog();
401 } else {
402 foreach (
403 array(
404 $this->wc_am_instance_key,
405 $this->wc_am_deactivate_checkbox_key,
406 $this->wc_am_activated_key
407 ) as $option
408 ) {
409
410 delete_option( $option );
411 }
412 }
413 }
414 }
415
416 /**
417 * Deactivates the license on the API server
418 */
419 public function license_key_deactivation() {
420 $activation_status = get_option( $this->wc_am_activated_key );
421 $api_key = ! empty( $this->data[ $this->wc_am_api_key_key ] ) ? $this->data[ $this->wc_am_api_key_key ] : '';
422
423 $args = array(
424 'api_key' => $api_key,
425 );
426
427 if ( ! empty( $api_key ) && $activation_status == 'Activated' ) {
428 if ( empty( $this->deactivate( $args ) ) ) {
429 add_settings_error( 'not_deactivated_text', 'not_deactivated_error', esc_html__( 'The License Key could not be deactivated. Use the License Key Deactivation tab to manually deactivate the License Key before activating a new License Key. If all else fails, go to Plugins, then deactivate and reactivate this plugin, or if a theme change themes, then change back to this theme, then go to the Settings for this plugin/theme and enter the License Key information again to activate it. Also check the My Account dashboard to see if the License Key for this site was still active before the error message was displayed.', $this->text_domain ), 'updated' );
430 }
431 }
432 }
433
434 /**
435 * Check for external blocking contstant.
436 */
437 public function check_external_blocking() {
438 // show notice if external requests are blocked through the WP_HTTP_BLOCK_EXTERNAL constant
439 if ( defined( 'WP_HTTP_BLOCK_EXTERNAL' ) && WP_HTTP_BLOCK_EXTERNAL === true ) {
440 // check if our API endpoint is in the allowed hosts
441 $host = parse_url( $this->api_url, PHP_URL_HOST );
442
443 if ( ! defined( 'WP_ACCESSIBLE_HOSTS' ) || stristr( WP_ACCESSIBLE_HOSTS, $host ) === false ) {
444 ?>
445 <div class="notice notice-error">
446 <p><?php printf( __( '<b>Warning!</b> You\'re blocking external requests which means you won\'t be able to get %s updates. Please add %s to %s.', $this->text_domain ), $this->software_title, '<strong>' . $host . '</strong>', '<code>WP_ACCESSIBLE_HOSTS</code>' ); ?></p>
447 </div>
448 <?php
449 }
450 }
451 }
452
453 // Draw option page
454 public function config_page() {
455 $settings_tabs = array(
456 $this->wc_am_activation_tab_key => esc_html__( $this->wc_am_menu_tab_activation_title, $this->text_domain ),
457 $this->wc_am_deactivation_tab_key => esc_html__( $this->wc_am_menu_tab_deactivation_title, $this->text_domain )
458 );
459 $current_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : $this->wc_am_activation_tab_key;
460 $tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : $this->wc_am_activation_tab_key;
461 ?>
462 <div class='wrap'>
463 <h2 class="nav-tab-wrapper">
464 <?php
465 foreach ( $settings_tabs as $tab_page => $tab_name ) {
466 $active_tab = $current_tab == $tab_page ? 'nav-tab-active' : '';
467 echo '<a class="nav-tab ' . esc_attr( $active_tab ) . '" href="?page=' . esc_attr( $this->wc_am_activation_tab_key ) . '&tab=' . esc_attr( $tab_page ) . '">' . esc_attr( $tab_name ) . '</a>';
468 }
469 ?>
470 </h2>
471 <form action='options.php' method='post'>
472 <div class="main">
473 <?php
474 if ( $tab == $this->wc_am_activation_tab_key ) {
475 settings_fields( $this->data_key );
476 do_settings_sections( $this->wc_am_activation_tab_key );
477 submit_button( esc_html__( 'Save Changes', $this->text_domain ) );
478 } else {
479 settings_fields( $this->wc_am_deactivate_checkbox_key );
480 do_settings_sections( $this->wc_am_deactivation_tab_key );
481 submit_button( esc_html__( 'Save Changes', $this->text_domain ) );
482 }
483 ?>
484 </div>
485 </form>
486 </div>
487 <?php
488 }
489
490 // Register settings
491 public function load_settings() {
492 global $wp_version;
493
494 register_setting( $this->data_key, $this->data_key, array( $this, 'validate_options' ) );
495 // API Key
496 add_settings_section( $this->wc_am_api_key_key, esc_html__( 'Key Activation', $this->text_domain ), array(
497 $this,
498 'wc_am_api_key_text'
499 ), $this->wc_am_activation_tab_key );
500 add_settings_field( $this->wc_am_api_key_key, esc_html__( 'License Key', $this->text_domain ), array(
501 $this,
502 'wc_am_api_key_field'
503 ), $this->wc_am_activation_tab_key, $this->wc_am_api_key_key );
504
505 /**
506 * @since 2.3
507 */
508 if ( $this->no_product_id ) {
509 add_settings_field( 'product_id', esc_html__( 'Product ID', $this->text_domain ), array(
510 $this,
511 'wc_am_product_id_field'
512 ), $this->wc_am_activation_tab_key, $this->wc_am_api_key_key );
513 }
514
515 /**
516 * @since 2.8
517 */ //if ( version_compare( $wp_version, '5.5', '>=' ) ) {
518 // add_settings_field( $this->wc_am_auto_update_key, esc_html__( 'Auto Plugin Updates', $this->text_domain ), array(
519 // $this,
520 // 'wc_am_auto_update_radio'
521 // ), $this->wc_am_activation_tab_key, $this->wc_am_api_key_key );
522 //}
523
524 add_settings_field( 'status', esc_html__( 'Key Status', $this->text_domain ), array(
525 $this,
526 'wc_am_api_key_status'
527 ), $this->wc_am_activation_tab_key, $this->wc_am_api_key_key );
528 // Activation settings
529 register_setting( $this->wc_am_deactivate_checkbox_key, $this->wc_am_deactivate_checkbox_key, array(
530 $this,
531 'wc_am_license_key_deactivation'
532 ) );
533 add_settings_section( 'deactivate_button', esc_html__( 'Deactivation', $this->text_domain ), array(
534 $this,
535 'wc_am_deactivate_text'
536 ), $this->wc_am_deactivation_tab_key );
537 add_settings_field( 'deactivate_button', esc_html__( 'Deactivate Key', $this->text_domain ), array(
538 $this,
539 'wc_am_deactivate_textarea'
540 ), $this->wc_am_deactivation_tab_key, 'deactivate_button' );
541 }
542
543 // Provides text for api key section
544 public function wc_am_api_key_text() { }
545
546 // Returns the API Key status from the WooCommerce API Manager on the server
547 public function wc_am_api_key_status() {
548 if ( $this->get_api_key_status( true ) ) {
549 $license_status_check = esc_html__( 'Activated', $this->text_domain );
550 update_option( $this->wc_am_activated_key, 'Activated' );
551 update_option( $this->wc_am_deactivate_checkbox_key, 'off' );
552 } else {
553 $license_status_check = esc_html__( 'Deactivated', $this->text_domain );
554 }
555
556 echo esc_attr( $license_status_check );
557 }
558
559 /**
560 * Returns the API Key status by querying the Status API function from the WooCommerce API Manager on the server.
561 *
562 * @return array|mixed|object
563 */
564 public function license_key_status() {
565 $status = $this->status();
566
567 return ! empty( $status ) ? json_decode( $this->status(), true ) : $status;
568 }
569
570 /**
571 * Returns true if the API Key status is Activated.
572 *
573 * @since 2.1
574 *
575 * @param bool $live Do not set to true if using to activate software. True is for live status checks after activation.
576 *
577 * @return bool
578 */
579 public function get_api_key_status( $live = false ) {
580 /**
581 * Real-time result.
582 *
583 * @since 2.5.1
584 */
585 if ( $live ) {
586 $license_status = $this->license_key_status();
587
588 return ! empty( $license_status ) && ! empty( $license_status[ 'data' ][ 'activated' ] ) && $license_status[ 'data' ][ 'activated' ];
589 }
590
591 /**
592 * If $live === false.
593 *
594 * Stored result when first activating software.
595 */
596 return get_option( $this->wc_am_activated_key ) == 'Activated';
597 }
598
599 // Returns API Key text field
600 public function wc_am_api_key_field() {
601 if ( ! empty( $this->data[ $this->wc_am_api_key_key ] ) ) {
602 echo "<input id='api_key' name='" . esc_attr( $this->data_key ) . "[" . esc_attr( $this->wc_am_api_key_key ) . "]' size='25' type='text' value='" . esc_attr( $this->data[ $this->wc_am_api_key_key ] ) . "' />";
603 } else {
604 echo "<input id='api_key' name='" . esc_attr( $this->data_key ) . "[" . esc_attr( $this->wc_am_api_key_key ) . "]' size='25' type='text' value='' />";
605 }
606 }
607
608 /**
609 * @since 2.3
610 */
611 public function wc_am_product_id_field() {
612 $product_id = get_option( $this->wc_am_product_id );
613
614 if ( ! empty( $product_id ) ) {
615 $this->product_id = $product_id;
616 }
617
618 if ( ! empty( $product_id ) ) {
619 echo "<input id='product_id' name='" . esc_attr( $this->wc_am_product_id ) . "' size='25' type='text' value='" . absint( $this->product_id ) . "' />";
620 } else {
621 echo "<input id='product_id' name='" . esc_attr( $this->wc_am_product_id ) . "' size='25' type='text' value='' />";
622 }
623 }
624
625 /**
626 * Radio buttons to toggle auto-updates on or off.
627 *
628 * @since 2.8
629 */
630 //public function wc_am_auto_update_radio() {
631 // echo '<input type="radio" name="' . esc_attr( $this->wc_am_auto_update_key ) . '" value="on"' . checked( get_option( $this->wc_am_auto_update_key ), 'on', false ) . '>' . esc_html__( 'On', $this->text_domain ) . '<br /><br />';
632 // echo '<input type="radio" name="' . esc_attr( $this->wc_am_auto_update_key ) . '" value="off"' . checked( get_option( $this->wc_am_auto_update_key ), 'off', false ) . '>' . esc_html__( 'Off', $this->text_domain );
633 //}
634
635 /**
636 * Sanitizes and validates all input and output for Dashboard
637 *
638 * @since 2.0
639 *
640 * @param $input
641 *
642 * @return mixed|string
643 */
644 public function validate_options( $input ) {
645 // Load existing options, validate, and update with changes from input before returning
646 $options = $this->data;
647 $options[ $this->wc_am_api_key_key ] = trim( $input[ $this->wc_am_api_key_key ] );
648 $api_key = trim( $input[ $this->wc_am_api_key_key ] );
649 $activation_status = get_option( $this->wc_am_activated_key );
650 $checkbox_status = get_option( $this->wc_am_deactivate_checkbox_key );
651 $current_api_key = ! empty( $this->data[ $this->wc_am_api_key_key ] ) ? $this->data[ $this->wc_am_api_key_key ] : '';
652
653 /**
654 * @since 2.3
655 */
656 if ( $this->no_product_id ) {
657 $new_product_id = absint( $_REQUEST[ $this->wc_am_product_id ] );
658
659 if ( ! empty( $new_product_id ) ) {
660 update_option( $this->wc_am_product_id, $new_product_id );
661 $this->product_id = $new_product_id;
662 }
663 }
664
665 /**
666 * Toggle auto-updates.
667 *
668 * @since 2.8
669 */ //if ( ! empty( $_REQUEST[ $this->wc_am_auto_update_key ] ) && $_REQUEST[ $this->wc_am_auto_update_key ] == 'on' ) {
670 // update_option( $this->wc_am_auto_update_key, 'on' );
671 //} else {
672 // update_option( $this->wc_am_auto_update_key, 'off' );
673 //}
674
675 // Should match the settings_fields() value
676 if ( ! empty( $_REQUEST[ 'option_page' ] ) && $_REQUEST[ 'option_page' ] != $this->wc_am_deactivate_checkbox_key ) {
677 if ( $activation_status == 'Deactivated' || $activation_status == '' || $api_key == '' || $checkbox_status == 'on' || $current_api_key != $api_key ) {
678 /**
679 * If this is a new key, and an existing key already exists in the database,
680 * try to deactivate the existing key before activating the new key.
681 */
682 if ( ! empty( $current_api_key ) && $current_api_key != $api_key ) {
683 $this->replace_license_key( $current_api_key );
684 }
685
686 $args = array(
687 'api_key' => $api_key,
688 );
689
690 $activation_result = $this->activate( $args );
691
692 if ( ! empty( $activation_result ) ) {
693 $activate_results = json_decode( $activation_result, true );
694
695 if ( $activate_results[ 'success' ] === true && $activate_results[ 'activated' ] === true ) {
696 add_settings_error( 'activate_text', 'activate_msg', sprintf( __( '%s activated. ', $this->text_domain ), esc_attr( $this->software_title ) ) . esc_attr( "{$activate_results['message']}." ), 'updated' );
697 update_option( $this->wc_am_activated_key, 'Activated' );
698 update_option( $this->wc_am_deactivate_checkbox_key, 'off' );
699 }
700
701 if ( $activate_results == false && ! empty( $this->data ) && ! empty( $this->wc_am_activated_key ) ) {
702 add_settings_error( 'api_key_check_text', 'api_key_check_error', esc_html__( 'Connection failed to the License Key API server. Try again later. There may be a problem on your server preventing outgoing requests, or the store is blocking your request to activate the plugin/theme.', $this->text_domain ), 'error' );
703 update_option( $this->wc_am_activated_key, 'Deactivated' );
704 }
705
706 if ( isset( $activate_results[ 'data' ][ 'error_code' ] ) && ! empty( $this->data ) && ! empty( $this->wc_am_activated_key ) ) {
707 add_settings_error( 'borderless_client_error_text', 'borderless_client_error', esc_attr( "{$activate_results['data']['error']}" ), 'error' );
708 update_option( $this->wc_am_activated_key, 'Deactivated' );
709 }
710 } else {
711 add_settings_error( 'not_activated_empty_response_text', 'not_activated_empty_response_error', esc_html__( 'The License Key activation could not be commpleted due to an unknown error possibly on the store server The activation results were empty.', $this->text_domain ), 'updated' );
712 }
713 } // End Plugin Activation
714 }
715
716 return $options;
717 }
718
719 // Deactivates the API Key to allow key to be used on another blog
720 public function wc_am_license_key_deactivation( $input ) {
721 $activation_status = get_option( $this->wc_am_activated_key );
722 $options = ( $input == 'on' ? 'on' : 'off' );
723
724 $args = array(
725 'api_key' => ! empty( $this->data[ $this->wc_am_api_key_key ] ) ? $this->data[ $this->wc_am_api_key_key ] : '',
726 );
727
728 if ( ! empty( $this->data[ $this->wc_am_api_key_key ] ) && $options == 'on' && $activation_status == 'Activated' ) {
729 // deactivates API Key key activation
730 $deactivation_result = $this->deactivate( $args );
731
732 if ( ! empty( $deactivation_result ) ) {
733 $activate_results = json_decode( $deactivation_result, true );
734
735 if ( $activate_results[ 'success' ] === true && $activate_results[ 'deactivated' ] === true ) {
736 if ( ! empty( $this->wc_am_activated_key ) ) {
737 update_option( $this->wc_am_activated_key, 'Deactivated' );
738 add_settings_error( 'wc_am_deactivate_text', 'deactivate_msg', esc_html__( 'Key deactivated. ', $this->text_domain ) . esc_attr( "{$activate_results['activations_remaining']}." ), 'updated' );
739 }
740
741 return $options;
742 }
743
744 if ( isset( $activate_results[ 'data' ][ 'error_code' ] ) && ! empty( $this->data ) && ! empty( $this->wc_am_activated_key ) ) {
745 add_settings_error( 'borderless_client_error_text', 'borderless_client_error', esc_attr( "{$activate_results['data']['error']}" ), 'error' );
746 update_option( $this->wc_am_activated_key, 'Deactivated' );
747 }
748 } else {
749 add_settings_error( 'not_deactivated_empty_response_text', 'not_deactivated_empty_response_error', esc_html__( 'The License Key activation could not be commpleted due to an unknown error possibly on the store server The activation results were empty.', $this->text_domain ), 'updated' );
750 }
751 }
752
753 return $options;
754 }
755
756 /**
757 * Deactivate the current API Key before activating the new API Key
758 *
759 * @param string $current_api_key
760 */
761 public function replace_license_key( $current_api_key ) {
762 $args = array(
763 'api_key' => $current_api_key,
764 );
765
766 $this->deactivate( $args );
767 }
768
769 public function wc_am_deactivate_text() { }
770
771 public function wc_am_deactivate_textarea() {
772 echo '<input type="checkbox" id="' . esc_attr( $this->wc_am_deactivate_checkbox_key ) . '" name="' . esc_attr( $this->wc_am_deactivate_checkbox_key ) . '" value="on"';
773 echo checked( get_option( $this->wc_am_deactivate_checkbox_key ), 'on' );
774 echo '/>';
775 ?><span class="description"><?php esc_html_e( 'Deactivates an License Key so it can be used on another blog.', $this->text_domain ); ?></span>
776 <?php
777 }
778
779 /**
780 * Builds the URL containing the API query string for activation, deactivation, and status requests.
781 *
782 * @param array $args
783 *
784 * @return string
785 */
786 public function create_software_api_url( $args ) {
787 return add_query_arg( 'wc-api', 'wc-am-api', $this->api_url ) . '&' . http_build_query( $args );
788 }
789
790 /**
791 * Sends the request to activate to the API Manager.
792 *
793 * @param array $args
794 *
795 * @return string
796 */
797 public function activate( $args ) {
798 if ( empty( $args ) ) {
799 add_settings_error( 'not_activated_text', 'not_activated_error', esc_html__( 'The License Key is missing from the deactivation request.', $this->text_domain ), 'updated' );
800
801 return '';
802 }
803
804 $defaults = array(
805 'wc_am_action' => 'activate',
806 'product_id' => $this->product_id,
807 'instance' => $this->wc_am_instance_id,
808 'object' => $this->wc_am_domain,
809 'software_version' => $this->wc_am_software_version
810 );
811
812 $args = wp_parse_args( $defaults, $args );
813 $target_url = esc_url_raw( $this->create_software_api_url( $args ) );
814 $request = wp_safe_remote_post( $target_url, array( 'timeout' => 15 ) );
815
816 if ( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) != 200 ) {
817 // Request failed
818 return '';
819 }
820
821 return wp_remote_retrieve_body( $request );
822 }
823
824 /**
825 * Sends the request to deactivate to the API Manager.
826 *
827 * @param array $args
828 *
829 * @return string
830 */
831 public function deactivate( $args ) {
832 if ( empty( $args ) ) {
833 add_settings_error( 'not_deactivated_text', 'not_deactivated_error', esc_html__( 'The License Key is missing from the deactivation request.', $this->text_domain ), 'updated' );
834
835 return '';
836 }
837
838 $defaults = array(
839 'wc_am_action' => 'deactivate',
840 'product_id' => $this->product_id,
841 'instance' => $this->wc_am_instance_id,
842 'object' => $this->wc_am_domain
843 );
844
845 $args = wp_parse_args( $defaults, $args );
846 $target_url = esc_url_raw( $this->create_software_api_url( $args ) );
847 $request = wp_safe_remote_post( $target_url, array( 'timeout' => 15 ) );
848
849 if ( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) != 200 ) {
850 // Request failed
851 return '';
852 }
853
854 return wp_remote_retrieve_body( $request );
855 }
856
857 /**
858 * Sends the status check request to the API Manager.
859 *
860 * @return bool|string
861 */
862 public function status() {
863 if ( empty( $this->data[ $this->wc_am_api_key_key ] ) ) {
864 return '';
865 }
866
867 $defaults = array(
868 'wc_am_action' => 'status',
869 'api_key' => $this->data[ $this->wc_am_api_key_key ],
870 'product_id' => $this->product_id,
871 'instance' => $this->wc_am_instance_id,
872 'object' => $this->wc_am_domain
873 );
874
875 $target_url = esc_url_raw( $this->create_software_api_url( $defaults ) );
876 $request = wp_safe_remote_post( $target_url, array( 'timeout' => 15 ) );
877
878 if ( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) != 200 ) {
879 // Request failed
880 return '';
881 }
882
883 return wp_remote_retrieve_body( $request );
884 }
885
886 /**
887 * Check for software updates.
888 */
889 public function check_for_update() {
890 $this->plugin_name = $this->wc_am_plugin_name;
891
892 // Slug should be the same as the plugin/theme directory name
893 if ( strpos( $this->plugin_name, '.php' ) !== 0 ) {
894 $this->slug = dirname( $this->plugin_name );
895 } else {
896 $this->slug = $this->plugin_name;
897 }
898
899 /*********************************************************************
900 * The plugin and theme filters should not be active at the same time
901 *********************************************************************/ /**
902 * More info:
903 * function set_site_transient moved from wp-includes/functions.php
904 * to wp-includes/option.php in WordPress 3.4
905 *
906 * set_site_transient() contains the pre_set_site_transient_{$transient} filter
907 * {$transient} is either update_plugins or update_themes
908 *
909 * Transient data for plugins and themes exist in the Options table:
910 * _site_transient_update_themes
911 * _site_transient_update_plugins
912 */
913
914 // uses the flag above to determine if this is a plugin or a theme update request
915 if ( $this->plugin_or_theme == 'plugin' ) {
916 /**
917 * Plugin Updates
918 */
919 add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'update_check' ) );
920 // Check For Plugin Information to display on the update details page
921 add_filter( 'plugins_api', array( $this, 'information_request' ), 10, 3 );
922 } elseif ( $this->plugin_or_theme == 'theme' ) {
923 /**
924 * Theme Updates
925 */
926 add_filter( 'pre_set_site_transient_update_themes', array( $this, 'update_check' ) );
927
928 // Check For Theme Information to display on the update details page
929 //add_filter( 'themes_api', array( $this, 'information_request' ), 10, 3 );
930
931 }
932 }
933
934 /**
935 * Sends and receives data to and from the server API
936 *
937 * @since 2.0
938 *
939 * @param array $args
940 *
941 * @return bool|string $response
942 */
943 public function send_query( $args ) {
944 $target_url = esc_url_raw( add_query_arg( 'wc-api', 'wc-am-api', $this->api_url ) . '&' . http_build_query( $args ) );
945 $request = wp_safe_remote_post( $target_url, array( 'timeout' => 15 ) );
946
947 if ( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) != 200 ) {
948 return false;
949 }
950
951 $response = wp_remote_retrieve_body( $request );
952
953 return ! empty( $response ) ? $response : false;
954 }
955
956 /**
957 * Check for updates against the remote server.
958 *
959 * @since 2.0
960 *
961 * @param object $transient
962 *
963 * @return object $transient
964 */
965 public function update_check( $transient ) {
966 if ( empty( $transient->checked ) ) {
967 return $transient;
968 }
969
970 $args = array(
971 'wc_am_action' => 'update',
972 'slug' => $this->slug,
973 'plugin_name' => $this->plugin_name,
974 'version' => $this->wc_am_software_version,
975 'product_id' => $this->product_id,
976 'api_key' => ! empty( $this->data[ $this->wc_am_api_key_key ] ) ? $this->data[ $this->wc_am_api_key_key ] : '',
977 'instance' => $this->wc_am_instance_id,
978 );
979
980 // Check for a plugin update
981 $response = json_decode( $this->send_query( $args ), true );
982 // Displays an admin error message in the WordPress dashboard
983 //$this->check_response_for_errors( $response );
984
985 if ( isset( $response[ 'data' ][ 'error_code' ] ) ) {
986 add_settings_error( 'borderless_client_error_text', 'borderless_client_error', "{$response['data']['error']}", 'error' );
987 }
988
989 if ( $response !== false && $response[ 'success' ] === true ) {
990 // New plugin version from the API
991 $new_ver = (string) $response[ 'data' ][ 'package' ][ 'new_version' ];
992 // Current installed plugin version
993 $curr_ver = (string) $this->wc_am_software_version;
994
995 $package = array(
996 'id' => $response[ 'data' ][ 'package' ][ 'id' ],
997 'slug' => $response[ 'data' ][ 'package' ][ 'slug' ],
998 'plugin' => $response[ 'data' ][ 'package' ][ 'plugin' ],
999 'new_version' => $response[ 'data' ][ 'package' ][ 'new_version' ],
1000 'url' => $response[ 'data' ][ 'package' ][ 'url' ],
1001 'tested' => $response[ 'data' ][ 'package' ][ 'tested' ],
1002 'package' => $response[ 'data' ][ 'package' ][ 'package' ],
1003 'upgrade_notice' => $response[ 'data' ][ 'package' ][ 'upgrade_notice' ],
1004 );
1005
1006 if ( isset( $new_ver ) && isset( $curr_ver ) ) {
1007 if ( version_compare( $new_ver, $curr_ver, '>' ) ) {
1008 if ( $this->plugin_or_theme == 'plugin' ) {
1009 $transient->response[ $this->plugin_name ] = (object) $package;
1010 unset( $transient->no_update[ $this->plugin_name ] );
1011 } elseif ( $this->plugin_or_theme == 'theme' ) {
1012 $transient->response[ $this->plugin_name ][ 'new_version' ] = $response[ 'data' ][ 'package' ][ 'new_version' ];
1013 $transient->response[ $this->plugin_name ][ 'url' ] = $response[ 'data' ][ 'package' ][ 'url' ];
1014 $transient->response[ $this->plugin_name ][ 'package' ] = $response[ 'data' ][ 'package' ][ 'package' ];
1015 }
1016 }
1017 }
1018 }
1019
1020 return $transient;
1021 }
1022
1023 /**
1024 * API request for informatin.
1025 *
1026 * If `$action` is 'query_plugins' or 'plugin_information', an object MUST be passed.
1027 * If `$action` is 'hot_tags` or 'hot_categories', an array should be passed.
1028 *
1029 * @param false|object|array $result The result object or array. Default false.
1030 * @param string $action The type of information being requested from the Plugin Install API.
1031 * @param object $args
1032 *
1033 * @return object
1034 */
1035 public function information_request( $result, $action, $args ) {
1036 // Check if this plugins API is about this plugin
1037 if ( isset( $args->slug ) ) {
1038 if ( $args->slug != $this->slug ) {
1039 return $result;
1040 }
1041 } else {
1042 return $result;
1043 }
1044
1045 $args = array(
1046 'wc_am_action' => 'plugininformation',
1047 'plugin_name' => $this->plugin_name,
1048 'version' => $this->wc_am_software_version,
1049 'product_id' => $this->product_id,
1050 'api_key' => ! empty( $this->data[ $this->wc_am_api_key_key ] ) ? $this->data[ $this->wc_am_api_key_key ] : '',
1051 'instance' => $this->wc_am_instance_id,
1052 'object' => $this->wc_am_domain,
1053 );
1054
1055 $response = unserialize( $this->send_query( $args ) );
1056
1057 if ( isset( $response ) && is_object( $response ) && $response !== false ) {
1058 return $response;
1059 }
1060
1061 return $result;
1062 }
1063
1064 }
1065 }