PluginProbe
Property Hive / 2.4.0
Property Hive v2.4.0
2.4.0 2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 All 262 releases
propertyhive / includes / class-ph-licenses.php

class-ph-licenses.php in Property Hive 2.4.0, at includes/class-ph-licenses.php

1,116 lines 33.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly
5 }
6
7 /**
8 * Licenses Controller
9 *
10 * Property Hive Licenses Class which handles the storing and checking of licenses
11 *
12 * @class PH_Licenses
13 * @version 1.0.0
14 * @package PropertyHive/Classes/Licenses
15 * @category Class
16 * @author PropertyHive
17 */
18 class PH_Licenses {
19
20 /** @var PH_Licenses The single instance of the class */
21 protected static $_instance = null;
22
23 private $pro_license_status = array();
24
25 /**
26 * Main PH_Licenses Instance.
27 *
28 * Ensures only one instance of PH_Licenses is loaded or can be loaded.
29 *
30 * @since 1.0.0
31 * @static
32 * @return PH_Licenses Main instance
33 */
34 public static function instance() {
35 if ( is_null( self::$_instance ) ) {
36 self::$_instance = new self();
37 }
38 return self::$_instance;
39 }
40
41 /**
42 * Cloning is forbidden.
43 *
44 * @since 1.0.0
45 */
46 public function __clone() {
47 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'propertyhive' ), '1.0.0' );
48 }
49
50 /**
51 * Unserializing instances of this class is forbidden.
52 *
53 * @since 1.0.0
54 */
55 public function __wakeup() {
56 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'propertyhive' ), '1.0.0' );
57 }
58
59 /**
60 * Constructor for the licenses class
61 *
62 */
63 public function __construct() {
64 add_action( 'propertyhive_check_licenses', array( $this, 'ph_check_licenses' ) );
65 add_filter( 'propertyhive_add_on_can_be_used', array( $this, 'ph_check_add_on_can_be_used' ), 10, 2 );
66 add_filter( 'propertyhive_add_on_can_be_updated', array( $this, 'ph_check_add_on_can_be_updated' ), 10, 2 );
67 }
68
69 public function ph_check_add_on_can_be_used( $can, $slug )
70 {
71 // Check add on wasn't active before
72 $pre_pro_add_ons = get_option( 'propertyhive_pre_pro_add_ons', array() );
73
74 if ( !empty($pre_pro_add_ons) )
75 {
76 foreach ( $pre_pro_add_ons as $pre_pro_add_on )
77 {
78 if ( isset($pre_pro_add_on['slug']) && $pre_pro_add_on['slug'] == $slug )
79 {
80 // Yes! This add on was being used pre pro so should still be able to be used without license checks
81 return true;
82 }
83 }
84 }
85
86 // Check we have the right kind of license key to operate this add on
87
88 $license_type = $this->get_license_type();
89
90 if ( $license_type == 'pro' )
91 {
92 if ( get_option('propertyhive_pro_license_key', '') != '' )
93 {
94 if ( !$this->is_valid_pro_license_key() )
95 {
96 // show warning
97 return false;
98 }
99
100 // Valid license. Check this plugin is valid for the purchased type of plan (i.e. map search can't be used with an 'import only' plan)
101 $feature = get_ph_pro_feature( $slug );
102 $product_id_and_package = PH()->license->get_pro_license_product_id_and_package();
103
104 if ( isset($product_id_and_package['success']) && $product_id_and_package['success'] === true )
105 {
106 if (
107 isset($feature['plans']) &&
108 isset($product_id_and_package['package']) &&
109 in_array($product_id_and_package['package'], $feature['plans'])
110 )
111 {
112
113 }
114 else
115 {
116 // show warning
117 return false;
118 }
119 }
120 }
121 }
122
123 return $can;
124 }
125
126 public function ph_check_add_on_can_be_updated( $can, $slug )
127 {
128 $license_type = $this->get_license_type();
129
130 if ( $license_type == 'old' )
131 {
132 $license = get_option( 'propertyhive_license_key_details', array() );
133
134 if ( !is_array( $license ) ) { $license = array(); }
135
136 if ( isset($license['active']) && $license['active'] == '1' && isset($license['expires_at']) && $license['expires_at'] != '' && strtotime($license['expires_at']) > time() )
137 {
138 return true;
139 }
140 }
141 elseif ( $license_type == 'pro' )
142 {
143 // get new license information
144 if ( get_option('propertyhive_pro_license_key', '') != '' )
145 {
146 if ( $this->is_valid_pro_license_key() )
147 {
148 // Valid license. Check this plugin is valid for the purchased type of plan (i.e. map search can't be used with an 'import only' plan)
149 $feature = get_ph_pro_feature( $slug );
150 $product_id_and_package = PH()->license->get_pro_license_product_id_and_package();
151
152 if ( isset($product_id_and_package['success']) && $product_id_and_package['success'] === true )
153 {
154 if ( ( $product_id_and_package['is_trial'] ?? null ) !== false )
155 {
156 return false;
157 }
158
159 if (
160 isset($feature['plans']) &&
161 isset($product_id_and_package['package']) &&
162 in_array($product_id_and_package['package'], $feature['plans'])
163 )
164 {
165 return true;
166 }
167 }
168 }
169 }
170 }
171
172 return $can;
173 }
174
175 public function get_license_type()
176 {
177 $license_type = get_option( 'propertyhive_license_type', '' );
178
179 if ( $license_type == '' )
180 {
181 // We don't know. Let's work it out by seeing if they have a license key
182 $existing_license_key = get_option( 'propertyhive_license_key', '' );
183
184 if ( $existing_license_key != '' )
185 {
186 $license = PH()->license->get_current_license();
187
188 if ( isset($license['active']) && $license['active'] == '1' )
189 {
190 return 'old';
191 }
192 }
193 }
194
195 return $license_type; // pro / old
196 }
197
198 private function get_data_for_license_check()
199 {
200 global $wpdb;
201
202 $license_type = $this->get_license_type();
203
204 $data = array();
205 $data['license_key_type'] = $license_type;
206 $data['license_key'] = ( $license_type == 'old' ? get_option( 'propertyhive_license_key', '' ) : get_option( 'propertyhive_pro_license_key', '' ) );
207 $data['url'] = home_url();
208
209 if ( get_option( 'propertyhive_data_sharing' ) != 'no' )
210 {
211 // Not opted-out
212
213 // Retrieve current theme info
214 $theme_data = wp_get_theme();
215 $theme = $theme_data->Name . ' ' . $theme_data->Version;
216
217 $data['php_version'] = phpversion();
218 $data['ph_version'] = PH_VERSION;
219 $data['wp_version'] = get_bloginfo( 'version' );
220 $data['server'] = isset( $_SERVER['SERVER_SOFTWARE'] ) && is_string( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '';
221
222 $data['install_date'] = get_option('propertyhive_install_timestamp', '');
223 if ( $data['install_date'] != '' && $data['install_date'] != 0 )
224 {
225 $data['install_date'] = gmdate("jS F Y", $data['install_date']);
226 }
227
228 $data['multisite'] = is_multisite();
229 $data['theme'] = $theme;
230 $data['email'] = get_bloginfo( 'admin_email' );
231
232 // Retrieve current plugin information
233 if ( !function_exists( 'get_plugins' ) ) {
234 include ABSPATH . '/wp-admin/includes/plugin.php';
235 }
236
237 $plugins = get_plugins(); // Fetch all plugins with details
238 $active_plugins = get_option('active_plugins', array());
239
240 $active_plugins_data = [];
241 $inactive_plugins_data = [];
242
243 // Loop through plugins to separate active and inactive along with version
244 foreach ($plugins as $plugin_path => $plugin_data)
245 {
246 $plugin_info = [
247 'name' => isset($plugin_data['Name']) ? $plugin_data['Name'] : '',
248 'version' => isset($plugin_data['Version']) ? $plugin_data['Version'] : '',
249 'path' => $plugin_path,
250 ];
251
252 if (in_array($plugin_path, $active_plugins))
253 {
254 $active_plugins_data[] = $plugin_info;
255 }
256 else
257 {
258 $inactive_plugins_data[] = $plugin_info;
259 }
260 }
261
262 $data['active_plugins'] = $active_plugins_data;
263 $data['inactive_plugins'] = $inactive_plugins_data;
264
265 $data['locale'] = get_locale();
266
267 // Import info
268 $property_import = get_option( 'propertyhive_property_import', array() );
269 if ( !is_array($property_import) )
270 {
271 $property_import = array();
272 }
273 $formats = array();
274 foreach ( $property_import as $import_id => $options )
275 {
276 if ( $options['running'] == '1' )
277 {
278 if ( $options['format'] == 'xml' )
279 {
280 $options['format'] .= ' (' . esc_url($options['xml_url']) . ')';
281 }
282 elseif ( $options['format'] == 'csv' )
283 {
284 $options['format'] .= ' (' . esc_url($options['csv_url']) . ')';
285 }
286 $formats[] = $options['format'];
287 }
288 }
289 $data['property_import_formats'] = $formats;
290
291 // Exports
292 $formats = array();
293
294 $exports = array(
295 'propertyhive_realtimefeed' => array(
296 'label' => 'RTDF',
297 'field' => 'send_property_api_url',
298 ),
299 'propertyhive_zooplarealtimefeed' => array(
300 'label' => 'Zoopla',
301 'field' => 'send_property_api_url',
302 ),
303 'propertyhive_blmexport' => array(
304 'label' => 'BLM',
305 'field' => 'ftp_host',
306 ),
307 );
308
309 foreach ( $exports as $option_name => $config )
310 {
311 $property_export = get_option( $option_name, array() );
312
313 if ( ! is_array( $property_export ) ) {
314 continue;
315 }
316
317 if ( ! isset( $property_export['portals'] ) ) {
318 continue;
319 }
320
321 if ( ! is_array( $property_export['portals'] ) ) {
322 continue;
323 }
324
325 $portals = isset( $property_export['portals'] ) && is_array( $property_export['portals'] )
326 ? $property_export['portals']
327 : array();
328
329 foreach ( $portals as $portal_id => $portal )
330 {
331 if ( ! is_array( $portal ) ) {
332 continue;
333 }
334
335 if ( ! is_array( $portal ) || ( $portal['mode'] ?? '' ) !== 'live' ) {
336 continue;
337 }
338
339 $destination = $portal[ $config['field'] ] ?? '';
340
341 $formats[] = sprintf(
342 '%s (%s)',
343 $config['label'],
344 $destination
345 );
346 }
347 }
348
349 $data['property_export_formats'] = $formats;
350
351 // Locrating
352 $locrating_settings = get_option( 'propertyhive_locrating', array() );
353 if ( !empty($locrating_settings) && isset($locrating_settings['enabled']) )
354 {
355 $data['locrating_enabled'] = ( $locrating_settings['enabled'] == 1 ? $locrating_settings['enabled'] : 0 );
356 }
357
358 // Search analytics
359
360 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Aggregate current custom-table analytics for the license report; new search events and retention change these counts independently.
361 $counts = $wpdb->get_row(
362 "SELECT
363 COALESCE(
364 SUM(searched_at >= UTC_TIMESTAMP() - INTERVAL 7 DAY),
365 0
366 ) AS last_7_days,
367 COALESCE(
368 SUM(searched_at >= UTC_TIMESTAMP() - INTERVAL 30 DAY),
369 0
370 ) AS last_30_days,
371 COUNT(*) AS last_90_days
372 FROM {$wpdb->prefix}ph_search_log
373 WHERE searched_at >= UTC_TIMESTAMP() - INTERVAL 90 DAY",
374 ARRAY_A
375 );
376
377 if ( is_array($counts) )
378 {
379 $data['searches_last_7_days'] = (int) ( $counts['last_7_days'] ?? 0 );
380 $data['searches_last_30_days'] = (int) ( $counts['last_30_days'] ?? 0 );
381 $data['searches_last_90_days'] = (int) ( $counts['last_90_days'] ?? 0 );
382 }
383
384 // get counts
385 $post_types = array('office', 'property', 'contact', 'appraisal', 'viewing', 'offer', 'sale', 'tenancy', 'key_date');
386 foreach ( $post_types as $post_type )
387 {
388 $args = array(
389 'post_type' => $post_type,
390 'fields' => 'ids',
391 'posts_per_page' => 1,
392 'post_status' => 'publish'
393 );
394 if ( $post_type == 'property' )
395 {
396 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- On-market state is stored in property metadata; retrieve one ID and use found_posts for the aggregate count.
397 $args['meta_query'] = array(
398 array(
399 'key' => '_on_market',
400 'value' => 'yes'
401 )
402 );
403 }
404
405 $post_query = new WP_Query( $args );
406
407 $data['post_type_count_' . $post_type] = $post_query->found_posts;
408
409 wp_reset_postdata();
410 }
411
412 $departments = array_keys( ph_get_departments() );
413 foreach ( $departments as $department )
414 {
415 $department_option = 'propertyhive_active_departments_' . str_replace( 'residential-', '', $department );
416 if ( get_option( $department_option ) != 'yes' )
417 {
418 continue;
419 }
420
421 $args = array(
422 'post_type' => 'property',
423 'fields' => 'ids',
424 'posts_per_page' => 1,
425 'post_status' => 'publish',
426 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Department and on-market state use property metadata; retrieve one ID and use found_posts for the opted-in aggregate count.
427 'meta_query' => array(
428 array(
429 'key' => '_on_market',
430 'value' => 'yes'
431 ),
432 array(
433 'key' => '_department',
434 'value' => $department
435 )
436 )
437 );
438
439 $post_query = new WP_Query( $args );
440
441 $data['property_count_by_department_' . $department] = $post_query->found_posts;
442
443 wp_reset_postdata();
444 }
445
446 // Onboarding wizard step
447 $onboarding_state = get_option( 'propertyhive_onboarding', false );
448
449 if ( is_array( $onboarding_state ) && ! empty( $onboarding_state ) )
450 {
451 $onboarding_status = isset( $onboarding_state['status'] )
452 ? sanitize_key( $onboarding_state['status'] )
453 : 'not_started';
454
455 $onboarding_step = isset( $onboarding_state['last_step'] )
456 ? sanitize_key( $onboarding_state['last_step'] )
457 : '';
458
459 // When skipped, last_step is the exact step on which Skip was clicked.
460 // Otherwise, use the most recently viewed step so abandonment is captured.
461 if (
462 $onboarding_status !== 'skipped' &&
463 ! empty( $onboarding_state['events'] ) &&
464 is_array( $onboarding_state['events'] )
465 )
466 {
467 foreach ( array_reverse( $onboarding_state['events'] ) as $event )
468 {
469 if (
470 isset( $event['event'], $event['data']['step'] ) &&
471 $event['event'] === 'step_viewed'
472 )
473 {
474 $onboarding_step = sanitize_key( $event['data']['step'] );
475 break;
476 }
477 }
478 }
479
480 $data['onboarding_status'] = $onboarding_status;
481 $data['onboarding_step'] = $onboarding_step;
482 }
483
484 $data = apply_filters( 'propertyhive_license_check_data', $data );
485 }
486
487 return $data;
488 }
489
490 /**
491 * Automated check for licenses
492 *
493 */
494 public function ph_check_licenses( $force_check = false )
495 {
496 // Do a maximum of once per week
497 $last_send = get_option( 'propertyhive_last_license_check', '' );
498 if( !$force_check && is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) ) {
499 return false;
500 }
501
502 update_option( 'propertyhive_last_license_check', time() );
503
504 // Retain last-known license details during outages; replace them only with a valid HTTPS response.
505 update_option( 'propertyhive_license_key_error', '', 'no' );
506
507 $data = $this->get_data_for_license_check();
508
509 $request = wp_remote_post( 'http://license.wp-property-hive.com/check-license.php', array(
510 'method' => 'POST',
511 'timeout' => 20,
512 'redirection' => 1,
513 'httpversion' => '1.1',
514 'blocking' => true,
515 'body' => $data,
516 'user-agent' => 'PH/' . PH_VERSION . '; ' . get_bloginfo( 'url' )
517 ) );
518
519 if ( is_wp_error( $request ) )
520 {
521 update_option( 'propertyhive_license_key_error', __( 'The license service could not be reached securely. Your saved license details have been retained.', 'propertyhive' ) . ' ' . $request->get_error_message(), 'no' );
522 return false;
523 }
524
525 if ( 200 !== wp_remote_retrieve_response_code( $request ) || '' === wp_remote_retrieve_body( $request ) )
526 {
527 update_option( 'propertyhive_license_key_error', __( 'The license service returned an invalid response.', 'propertyhive' ) . ' ' . wp_remote_retrieve_response_code( $request ), 'no' );
528 return false;
529 }
530
531 $body = @unserialize($request['body'], ['allowed_classes' => false]);
532 if ( $body !== FALSE && is_array($body) )
533 {
534 update_option( 'propertyhive_license_key_details', $body, 'no' );
535 }
536 else
537 {
538 update_option( 'propertyhive_license_key_error', __( 'The license service returned invalid license data.', 'propertyhive' ) . ' ' . print_r($body, true), 'no' );
539 }
540 }
541
542 public function get_current_license()
543 {
544 $license = get_option( 'propertyhive_license_key_details', array() );
545
546 if ( !is_array( $license ) ) { $license = array(); }
547
548 return $license;
549 }
550
551 public function is_valid_pro_license_key($force = false)
552 {
553 $license = $this->get_current_pro_license($force);
554 if ( isset($license['success']) && $license['success'] === true )
555 {
556 return true;
557 }
558
559 return false;
560 }
561
562 public function activate_pro_license_key()
563 {
564 $license = $this->get_pro_license_product_id_and_package(true);
565
566 if ( isset($license['success']) && $license['success'] === true )
567 {
568 $license_key = get_option( 'propertyhive_pro_license_key', '' );
569
570 $instance_id = get_option( 'propertyhive_pro_instance_id', '' );
571
572 if ( empty($instance_id) )
573 {
574 $instance_id = wp_generate_password( 12, false ); // disable specialchars
575 update_option('propertyhive_pro_instance_id', $instance_id );
576 }
577
578 $data = array();
579
580 // found API key. It's product ID will be stored in product_id
581 $url = 'https://wp-property-hive.com/?';
582 $url .= 'wc-api=wc-am-api&';
583 $url .= 'wc_am_action=activate&';
584 $url .= 'instance=' . $instance_id . '&';
585 $url .= 'object=' . wp_parse_url( get_site_url(), PHP_URL_HOST ) . '&';
586 $url .= 'product_id=' . $license['product_id'] . '&';
587 $url .= 'api_key=' . $license_key;
588
589 $response = wp_remote_post( $url, array(
590 'body' => $data,
591 ) );
592
593 if ( is_wp_error($response) )
594 {
595 $return = array(
596 'success' => false,
597 'error' => __( 'Failed to activate license status', 'propertyhive' ) . ': ' . $response->get_error_message()
598 );
599 return $return;
600 }
601
602 if ( 200 !== wp_remote_retrieve_response_code( $response ) )
603 {
604 $return = array(
605 'success' => false,
606 'error' => sprintf(
607 /* translators: %s: HTTP header response code */
608 __( 'Received response code %s when activating license key status', 'propertyhive' ),
609 wp_remote_retrieve_response_code( $response )
610 )
611 );
612 return $return;
613 }
614
615 $result = $response['body'];
616
617 $body = json_decode($result, true);
618
619 if ( json_last_error() !== JSON_ERROR_NONE )
620 {
621 $return = array(
622 'success' => false,
623 'error' => __( 'Failed to decode response when activating license key status. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
624 );
625 return $return;
626 }
627
628 if ( isset($body['success']) )
629 {
630 if ( $body['success'] === true )
631 {
632 $return = array(
633 'success' => true,
634 );
635 return $return;
636 }
637 else
638 {
639 $return = array(
640 'success' => false,
641 'error' => __( 'Error when activating license key', 'propertyhive' ) . ': ' . $body['error']
642 );
643 return $return;
644 }
645 }
646 else
647 {
648 $return = array(
649 'success' => false,
650 'error' => __( 'Something went wrong when trying to activate license key', 'propertyhive' ) . ': ' . wp_json_encode( $body )
651 );
652 return $return;
653 }
654 }
655 else
656 {
657 return $license;
658 }
659 }
660
661 public function deactivate_pro_license_key()
662 {
663 $license = $this->get_pro_license_product_id_and_package(true);
664
665 if ( isset($license['success']) && $license['success'] === true )
666 {
667 $license_key = get_option( 'propertyhive_pro_license_key', '' );
668
669 $instance_id = get_option( 'propertyhive_pro_instance_id', '' );
670
671 if ( empty($instance_id) )
672 {
673 $instance_id = wp_generate_password( 12, false ); // disable specialchars
674 update_option('propertyhive_pro_instance_id', $instance_id );
675 }
676
677 $data = array();
678
679 // found API key. It's product ID will be stored in product_id
680 $url = 'https://wp-property-hive.com/?';
681 $url .= 'wc-api=wc-am-api&';
682 $url .= 'wc_am_action=deactivate&';
683 $url .= 'instance=' . $instance_id . '&';
684 $url .= 'object=' . wp_parse_url( get_site_url(), PHP_URL_HOST ) . '&';
685 $url .= 'product_id=' . $license['product_id'] . '&';
686 $url .= 'api_key=' . $license_key;
687
688 $response = wp_remote_post( $url, array(
689 'body' => $data,
690 ) );
691
692 if ( is_wp_error($response) )
693 {
694 $return = array(
695 'success' => false,
696 'error' => __( 'Failed to deactivate license status', 'propertyhive' ) . ': ' . $response->get_error_message()
697 );
698 return $return;
699 }
700
701 if ( 200 !== wp_remote_retrieve_response_code( $response ) )
702 {
703 $return = array(
704 'success' => false,
705 'error' => sprintf(
706 /* translators: %s: HTTP header response code */
707 __( 'Received response code %s when deactivating license key status', 'propertyhive' ),
708 wp_remote_retrieve_response_code( $response )
709 )
710 );
711 return $return;
712 }
713
714 $result = $response['body'];
715
716 $body = json_decode($result, true);
717
718 if ( json_last_error() !== JSON_ERROR_NONE )
719 {
720 $return = array(
721 'success' => false,
722 'error' => __( 'Failed to decode response when deactivating license key status. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
723 );
724 return $return;
725 }
726
727 if ( isset($body['success']) )
728 {
729 if ( $body['success'] === true )
730 {
731 $return = array(
732 'success' => true,
733 );
734 return $return;
735 }
736 else
737 {
738 $return = array(
739 'success' => false,
740 'error' => __( 'Error when deactivating license key', 'propertyhive' ) . ': ' . $body['error']
741 );
742 return $return;
743 }
744 }
745 else
746 {
747 $return = array(
748 'success' => false,
749 'error' => __( 'Something went wrong when trying to deactivate license key', 'propertyhive' ) . ': ' . wp_json_encode( $body )
750 );
751 return $return;
752 }
753 }
754 else
755 {
756 return $license;
757 }
758 }
759
760 public function get_pro_license_product_id_and_package($force = false)
761 {
762 if ( $force !== true )
763 {
764 // Not forcing. Get from transient if possible
765 $pro_license_product_id_and_package = get_transient( 'ph_pro_license_product_id_and_package' );
766
767 if ( $pro_license_product_id_and_package !== false )
768 {
769 // return transient value
770 return $pro_license_product_id_and_package;
771 }
772 }
773
774 $license_key = get_option( 'propertyhive_pro_license_key', '' );
775
776 if ( empty($license_key) )
777 {
778 $return = array(
779 'success' => false,
780 'error' => __( 'No license key entered', 'propertyhive' )
781 );
782 set_transient( 'ph_pro_license_product_id_and_package', $return, HOUR_IN_SECONDS );
783 return $return;
784 }
785
786 $instance_id = get_option( 'propertyhive_pro_instance_id', '' );
787
788 if ( empty($instance_id) )
789 {
790 $instance_id = wp_generate_password( 12, false ); // disable specialchars
791 update_option('propertyhive_pro_instance_id', $instance_id );
792 }
793
794 $data = $this->get_data_for_license_check();
795
796 $url = 'https://wp-property-hive.com/?';
797 $url .= 'wc-api=wc-am-api&';
798 $url .= 'wc_am_action=product_list&';
799 $url .= 'instance=' . $instance_id . '&';
800 $url .= 'api_key=' . $license_key;
801
802 $response = wp_remote_post( $url, array(
803 'body' => $data,
804 ) );
805
806 if ( is_wp_error($response) )
807 {
808 $return = array(
809 'success' => false,
810 'error' => __( 'Failed to request license product list', 'propertyhive' ) . ': ' . $response->get_error_message()
811 );
812
813 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
814 if ( !empty($last_known) )
815 {
816 set_transient( 'ph_pro_license_product_id_and_package', $last_known, HOUR_IN_SECONDS );
817 return $last_known;
818 }
819
820 return $return;
821 }
822
823 if ( 200 !== wp_remote_retrieve_response_code( $response ) )
824 {
825 $return = array(
826 'success' => false,
827 'error' => sprintf(
828 /* translators: %s: HTTP header response code */
829 __( 'Received response code %s when requesting license key product list', 'propertyhive' ),
830 wp_remote_retrieve_response_code( $response )
831 )
832 );
833
834 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
835 if ( !empty($last_known) )
836 {
837 set_transient( 'ph_pro_license_product_id_and_package', $last_known, HOUR_IN_SECONDS );
838 return $last_known;
839 }
840
841 return $return;
842 }
843
844 $result = $response['body'];
845
846 $body = json_decode($result, true);
847
848 if ( json_last_error() !== JSON_ERROR_NONE )
849 {
850 $return = array(
851 'success' => false,
852 'error' => __( 'Failed to decode response when requesting license key product list. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
853 );
854
855 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
856 if ( !empty($last_known) )
857 {
858 set_transient( 'ph_pro_license_product_id_and_package', $last_known, HOUR_IN_SECONDS );
859 return $last_known;
860 }
861
862 return $return;
863 }
864
865 if ( isset($body['success']) )
866 {
867 if ( $body['success'] === true )
868 {
869 if ( isset($body['data']['product_list']['wc_subs_resources']) && !empty($body['data']['product_list']['wc_subs_resources']) )
870 {
871 $package = false;
872 $product_id = '';
873 $is_trial = null;
874
875 foreach ( $body['data']['product_list']['wc_subs_resources'] as $resource )
876 {
877 if ( isset($resource['product_id']) )
878 {
879 if ( in_array($resource['product_id'], array(14492, 14493, 14494)) )
880 {
881 $package = 'import';
882 }
883 elseif ( in_array($resource['product_id'], array(14495, 14496, 14497)) )
884 {
885 $package = 'complete';
886 }
887 $product_id = $resource['product_id'];
888 $is_trial = isset( $resource['is_trial'] )
889 && is_bool( $resource['is_trial'] )
890 ? $resource['is_trial']
891 : null;
892 }
893 }
894
895 if ( $package !== FALSE )
896 {
897 $return = array(
898 'success' => true,
899 'package' => $package,
900 'product_id' => $product_id,
901 'is_trial' => $is_trial,
902 );
903 }
904 else
905 {
906 $return = array(
907 'success' => false,
908 'error' => __( 'API key exists but unable to establish the plan', 'propertyhive' )
909 );
910 }
911 }
912 else
913 {
914 $return = array(
915 'success' => false,
916 'error' => __( 'API key doesn\'t appear to belong to any orders', 'propertyhive' ) . ': ' . wp_json_encode( $body )
917 );
918 }
919 }
920 else
921 {
922 $return = array(
923 'success' => false,
924 'error' => __( 'Error when requesting license key product list', 'propertyhive' ) . ': ' . $body['error']
925 );
926 }
927
928 set_transient( 'ph_pro_license_product_id_and_package', $return, HOUR_IN_SECONDS * 3 );
929 update_option( 'ph_pro_last_known_license_product_id_and_package', $return );
930 return $return;
931 }
932 else
933 {
934 $return = array(
935 'success' => false,
936 'error' => __( 'Something went wrong when requesting license key product list', 'propertyhive' ) . ': ' . wp_json_encode( $body )
937 );
938
939 $last_known = get_option('ph_pro_last_known_license_product_id_and_package', array());
940 if ( !empty($last_known) )
941 {
942 set_transient( 'ph_pro_license_product_id_and_package', $last_known, HOUR_IN_SECONDS );
943 return $last_known;
944 }
945
946 return $return;
947 }
948 }
949
950 public function get_current_pro_license($force = false)
951 {
952 if ( $force !== true )
953 {
954 // Not forcing. Get from transient if possible
955 $pro_license_status = get_transient( 'ph_pro_license_status' );
956
957 if ( $pro_license_status !== false )
958 {
959 // return transient value
960 return $pro_license_status;
961 }
962 }
963
964 $product_id_and_package = $this->get_pro_license_product_id_and_package($force);
965
966 if ( !isset($product_id_and_package['success']) || ( isset($product_id_and_package['success']) && $product_id_and_package['success'] === false ) )
967 {
968 return $product_id_and_package;
969 }
970
971 $license_key = get_option( 'propertyhive_pro_license_key', '' );
972
973 if ( empty($license_key) )
974 {
975 $return = array(
976 'success' => false,
977 'error' => __( 'No license key entered', 'propertyhive' )
978 );
979 set_transient( 'ph_pro_license_status', $return, HOUR_IN_SECONDS );
980 return $return;
981 }
982
983 $instance_id = get_option( 'propertyhive_pro_instance_id', '' );
984
985 if ( empty($instance_id) )
986 {
987 $instance_id = wp_generate_password( 12, false ); // disable specialchars
988 update_option('propertyhive_pro_instance_id', $instance_id );
989 }
990
991 $data = $this->get_data_for_license_check();
992
993 $url = 'https://wp-property-hive.com/?';
994 $url .= 'wc-api=wc-am-api&';
995 $url .= 'wc_am_action=status&';
996 $url .= 'product_id=' . $product_id_and_package['product_id'] . '&';
997 $url .= 'instance=' . $instance_id . '&';
998 $url .= 'api_key=' . $license_key;
999
1000 $response = wp_remote_post( $url, array(
1001 'body' => $data,
1002 ) );
1003
1004 if ( is_wp_error($response) )
1005 {
1006 // error for some reason. Return last known status
1007 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );
1008 if ( !empty($previous_license_key_status) )
1009 {
1010 set_transient( 'ph_pro_license_status', $previous_license_key_status, HOUR_IN_SECONDS );
1011 return $previous_license_key_status;
1012 }
1013
1014 $return = array(
1015 'success' => false,
1016 'error' => __( 'Failed to request license status', 'propertyhive' ) . ': ' . $response->get_error_message()
1017 );
1018 return $return;
1019 }
1020
1021 if ( 200 !== wp_remote_retrieve_response_code( $response ) )
1022 {
1023 // error for some reason. Return last known status
1024 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );
1025 if ( !empty($previous_license_key_status) )
1026 {
1027 set_transient( 'ph_pro_license_status', $previous_license_key_status, HOUR_IN_SECONDS );
1028 return $previous_license_key_status;
1029 }
1030
1031 $return = array(
1032 'success' => false,
1033 'error' => sprintf(
1034 /* translators: %s: HTTP header response code */
1035 __( 'Received response code %s when requesting license key status', 'propertyhive' ),
1036 wp_remote_retrieve_response_code( $response )
1037 )
1038 );
1039
1040 return $return;
1041 }
1042
1043 $result = $response['body'];
1044
1045 $body = json_decode($result, true);
1046
1047 if ( json_last_error() !== JSON_ERROR_NONE )
1048 {
1049 $return = array(
1050 'success' => false,
1051 'error' => __( 'Failed to decode response when requesting license key status. Please try again', 'propertyhive' ) . ': ' . wp_json_encode( $result )
1052 );
1053
1054 // error for some reason. Return last known status
1055 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );
1056 if ( !empty($previous_license_key_status) )
1057 {
1058 set_transient( 'ph_pro_license_status', $previous_license_key_status, HOUR_IN_SECONDS );
1059 return $previous_license_key_status;
1060 }
1061
1062 return $return;
1063 }
1064
1065 if ( isset($body['success']) )
1066 {
1067 if ( $body['success'] === true )
1068 {
1069 if ( isset($body['status_check']) && $body['status_check'] === 'active' )
1070 {
1071 $return = array(
1072 'success' => true
1073 );
1074 }
1075 else
1076 {
1077 $return = array(
1078 'success' => false,
1079 'error' => __( 'License key inactive', 'propertyhive' )
1080 );
1081 }
1082 }
1083 else
1084 {
1085 $return = array(
1086 'success' => false,
1087 'error' => __( 'Error when requesting license key status', 'propertyhive' ) . ': ' . $body['error']
1088 );
1089 }
1090
1091 update_option( 'propertyhive_pro_license_key_last_checked', time() );
1092 update_option( 'propertyhive_pro_license_key_status', $return );
1093
1094 set_transient( 'ph_pro_license_status', $return, HOUR_IN_SECONDS * 3 );
1095 return $return;
1096 }
1097 else
1098 {
1099 $return = array(
1100 'success' => false,
1101 'error' => __( 'Something went wrong when requesting license key status', 'propertyhive' ) . ': ' . wp_json_encode( $body )
1102 );
1103
1104 // error for some reason. Return last known status
1105 $previous_license_key_status = get_option( 'propertyhive_pro_license_key_status', '' );
1106 if ( !empty($previous_license_key_status) )
1107 {
1108 set_transient( 'ph_pro_license_status', $previous_license_key_status, HOUR_IN_SECONDS );
1109 return $previous_license_key_status;
1110 }
1111
1112 return $return;
1113 }
1114 }
1115 }
1116