PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.1
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.1
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
charitable / includes / licensing / class-charitable-licenses.php

class-charitable-licenses.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.7.0.1, at includes/licensing/class-charitable-licenses.php

832 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class to assist with the setup of extension licenses.
4 *
5 * @package Charitable/Classes/Charitable_Licenses
6 * @version 1.4.20
7 * @author David Bisset
8 * @copyright Copyright (c) 2022, WP Charitable LLC
9 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 if ( ! class_exists( 'Charitable_Licenses' ) ) :
18
19 /**
20 * Charitable_Licenses
21 *
22 * @since 1.0.0
23 */
24 class Charitable_Licenses {
25
26 /* @var string */
27 const UPDATE_URL = 'https://www.wpcharitable.com';
28
29 /**
30 * The single instance of this class.
31 *
32 * @var Charitable_Licenses|null
33 */
34 private static $instance = null;
35
36 /**
37 * All the registered products requiring licensing.
38 *
39 * @var array
40 */
41 private $products;
42
43 /**
44 * All the stored licenses.
45 *
46 * @var array
47 */
48 private $licenses;
49
50 /**
51 * Cached update data.
52 *
53 * @var array
54 */
55 private $update_data;
56
57 /**
58 * Returns and/or create the single instance of this class.
59 *
60 * @since 1.2.0
61 *
62 * @return Charitable_Licenses
63 */
64 public static function get_instance() {
65 if ( is_null( self::$instance ) ) {
66 self::$instance = new self();
67 }
68
69 return self::$instance;
70 }
71
72 /**
73 * Create class object.
74 *
75 * @since 1.0.0
76 */
77 private function __construct() {
78 $this->products = array();
79 $this->update_data = array();
80
81 add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_for_updates' ) );
82 add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
83 add_action( 'charitable_deactivate_license', array( $this, 'deactivate_license' ) );
84 add_filter( 'upgrader_pre_download', array( $this, 'set_upgrader_error_message' ), 10, 3 );
85 add_filter( 'upgrader_package_options', array( $this, 'set_upgrader_package_options' ) );
86 }
87
88 /**
89 * Checks licenses to see if any are valid.
90 *
91 * @since 1.7.0
92 *
93 * @return boolean
94 */
95 public function is_pro() {
96
97 $products = $this->get_products();
98
99 if ( empty( $products ) ) {
100 return false;
101 }
102
103 // go through licenses - if there is at least ONE VALID ADDON LICNESE then it's pro.
104 foreach ( $products as $slug => $item ) {
105 $valid = $this->has_valid_license( $slug );
106 if ( $valid ) {
107 return true;
108 }
109 }
110 }
111
112 /**
113 * Checks for any Charitable extensions with updates.
114 *
115 * @since 1.4.0
116 *
117 * @param array $_transient_data The plugin updates data.
118 * @return array
119 */
120 public function check_for_updates( $_transient_data ) {
121 global $pagenow;
122
123 if ( ! is_object( $_transient_data ) ) {
124 $_transient_data = new stdClass;
125 }
126
127 if ( 'plugins.php' == $pagenow && is_multisite() ) {
128 return $_transient_data;
129 }
130
131 /* Loop over our licensed products and check whether any are missing transient data. */
132 $missing_data = array();
133
134 foreach ( $this->get_products() as $product ) {
135 if ( $this->is_missing_version_info( $product, $_transient_data ) ) {
136 $missing_data[] = $product;
137 }
138 }
139
140 /* If we are missing data for any of our products, check whether any have an update. */
141 if ( ! empty( $missing_data ) ) {
142
143 $versions = $this->get_versions();
144
145 unset( $versions['request_speed'] );
146
147 if ( ! empty( $versions ) ) {
148
149 $versions_name_lookup = wp_list_pluck( $versions, 'name' );
150
151 foreach ( $missing_data as $product ) {
152
153 if ( ! in_array( $product['name'], $versions_name_lookup ) ) {
154 continue;
155 }
156
157 $plugin_file = plugin_basename( $product['file'] );
158 $product_key = array_search( $product['name'], wp_list_pluck( $this->get_products(), 'name' ) );
159 $version_info = $versions[ array_search( $product['name'], $versions_name_lookup ) ];
160 $version_info['license'] = $this->get_license_details( $product_key );
161
162 if ( version_compare( $product['version'], $version_info['new_version'], '<' ) ) {
163
164 if ( isset( $version_info['sections'] ) ) {
165 $version_info['sections'] = maybe_unserialize( $version_info['sections'] );
166 }
167
168 $can_update = $this->able_to_update( $version_info );
169
170 if ( is_array( $can_update ) ) {
171 $version_info['package'] = $can_update['reason_code'];
172 $version_info['download_link'] = $can_update['reason_code'];
173 $version_info['package_download_restriction'] = $can_update['description'];
174 }
175
176 $_transient_data->response[ $plugin_file ] = (object) $version_info;
177 }
178
179 $_transient_data->last_checked = time();
180 $_transient_data->checked[ $plugin_file ] = $product['version'];
181
182 }//end foreach
183 }//end if
184 }//end if
185
186 return $_transient_data;
187 }
188
189 /**
190 * Updates information on the "View version x.x details" page with custom data.
191 *
192 * @uses api_request()
193 *
194 * @since 1.4.20
195 *
196 * @param mixed $_data Default set of data.
197 * @param string $_action The current action.
198 * @param object $_args Request args.
199 * @return object $_data
200 */
201 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
202 if ( 'plugin_information' != $_action ) {
203 return $_data;
204 }
205
206 if ( ! isset( $_args->slug ) ) {
207 return $_data;
208 }
209
210 $plugin_key = str_replace( '-', '_', $_args->slug );
211
212 if ( ! array_key_exists( $plugin_key, $this->products ) ) {
213 return $_data;
214 }
215
216 $version_info = $this->get_version_info( plugin_basename( $this->products[ $plugin_key ]['file'] ) );
217
218 if ( $version_info ) {
219 $_data = $version_info;
220 }
221
222 return $_data;
223 }
224
225 /**
226 * Return whether a particular plugin is missing version info.
227 *
228 * @since 1.4.20
229 *
230 * @param array $product Product details array.
231 * @param false|object $update_cache Optional argument to pass update cache.
232 * @return boolean
233 */
234 public function is_missing_version_info( $product, $update_cache = false ) {
235 return ! $this->get_version_info( plugin_basename( $product['file'] ), $update_cache );
236 }
237
238 /**
239 * Return the version update info for a particular plugin.
240 *
241 * @since 1.4.20
242 *
243 * @param string $slug The plugin slug.
244 * @param false|object $update_cache Optional argument to pass update cache.
245 * @return array|false Array if an update is available. False otherwise.
246 */
247 public function get_version_info( $slug, $update_cache = false ) {
248 if ( ! $update_cache ) {
249 $update_cache = get_site_transient( 'update_plugins' );
250 }
251
252 if ( ! is_object( $update_cache ) || empty( $update_cache->response ) || ! array_key_exists( $slug, $update_cache->response ) ) {
253 return false;
254 }
255
256 return $update_cache->response[ $slug ];
257 }
258
259 /**
260 * Display an error message when users attempt to update a plugin
261 * without a license or with an expired license.
262 *
263 * @since 1.4.20
264 *
265 * @param false|WP_Error $reply The messaage to return. Set to false by default.
266 * @param string $package Package URL. For Charitable extensions without a
267 * license or that have expired, we set this to a
268 * key. Kind of a hack to pass a message to this hook.
269 * @param Plugin_Upgrader $upgrader The Plugin_Upgrader object.
270 * @return false|WP_Error
271 */
272 public function set_upgrader_error_message( $reply, $package, $upgrader ) {
273 $ajax_skin = 'WP_Ajax_Upgrader_Skin' == get_class( $upgrader->skin );
274
275 if ( 'missing_license' == $package ) {
276 if ( $ajax_skin ) {
277 $message = sprintf( __( 'You have not activated your license key. Activate your license to update: %s', 'charitable' ),
278 admin_url( 'admin.php?page=charitable-settings&tab=licenses' )
279 );
280 } else {
281 $message = sprintf( __( 'You have not activated your license key. <a href="%s" target="_top">Activate your license to update.</a>', 'charitable' ),
282 admin_url( 'admin.php?page=charitable-settings&tab=licenses' )
283 );
284 }
285
286 return new WP_Error( 'missing_license_key', $message );
287 }
288
289 if ( false !== strpos( $package, 'expired_license:' ) ) {
290
291 $renewal_link = str_replace( 'expired_license:', '', $package );
292
293 if ( $ajax_skin ) {
294 $message = sprintf( __( 'Your license has expired. Renew your license key: %s', 'charitable' ),
295 $renewal_link
296 );
297 } else {
298 $message = sprintf( __( 'Your license has expired. <a href="%s" target="_blank">Renew your license key.</a>', 'charitable' ),
299 esc_url( $renewal_link )
300 );
301 }
302
303 return new WP_Error( 'expired_license_key', $message );
304 }
305
306 if ( false !== strpos( $package, 'missing_requirements:' ) ) {
307 $message = str_replace( 'missing_requirements:', '', htmlspecialchars_decode( $package ) );
308
309 return new WP_Error( 'missing_requirements_key', $message );
310 }
311
312 return $reply;
313 }
314
315 /**
316 * Checks whether the given plugin can be updated.
317 *
318 * @since 1.6.14
319 *
320 * @param array $version_info Version information.
321 * @return true|array If it can be updated, returns true. Otherwise
322 * returns an array with a reason_code and description.
323 */
324 protected function able_to_update( $version_info ) {
325 $changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $version_info['name'] . '&slug=' . $version_info['slug'] . '&TB_iframe=true&width=772&height=911' );
326
327 switch ( $version_info['package'] ) {
328
329 case 'missing_license':
330 return array(
331 'reason_code' => 'missing_license',
332 'description' => sprintf(
333 __( '<p>There is a new version of %1$s available but you have not activated your license. <a target="_top" href="%2$s">Activate your license</a> or <a target="_blank" class="thickbox" href="%3$s">view version %4$s details</a>.</p>', 'charitable' ),
334 esc_html( $version_info['name'] ),
335 admin_url( 'admin.php?page=charitable-settings&tab=licenses' ),
336 esc_url( $changelog_link ),
337 esc_html( $version_info['new_version'] )
338 ),
339 );
340
341 case 'expired_license':
342 $base_renewal_url = isset( $version_info['renewal_link'] ) ? $version_info['renewal_link'] : 'https://www.wpcharitable.com/account';
343
344 return array(
345 'reason_code' => 'expired_license',
346 'description' => sprintf(
347 __( '<p>There is a new version of %1$s available but your license has expired. <a target="_blank" href="%2$s">Renew your license</a> or <a target="_blank" class="thickbox" href="%3$s">view version %4$s details</a>.</p>', 'charitable' ),
348 esc_html( $version_info['name'] ),
349 charitable_ga_url(
350 $base_renewal_url,
351 urlencode( 'Expired License Notice'),
352 urlencode( 'Renew your license' )
353 ),
354 esc_url( $changelog_link ),
355 esc_html( $version_info['new_version'] )
356 ),
357 );
358
359 default:
360 if ( ! isset( $version_info['requirements'] ) ) {
361 return true;
362 }
363
364 $messages = array();
365
366 foreach ( $version_info['requirements'] as $type => $details ) {
367
368 switch ( $type ) {
369 case 'php':
370 if ( version_compare( phpversion(), $details, '<' ) ) {
371 $messages[] = esc_html(
372 sprintf(
373 __( '<li>Requires PHP version %s or greater.</li>' ),
374 $details
375 )
376 );
377 }
378 break;
379
380 case 'charitable':
381 if ( version_compare( charitable()->get_version(), $details, '<' ) ) {
382 $messages[] = esc_html(
383 sprintf(
384 __( 'Requires Charitable version %s or greater.' ),
385 $details
386 )
387 );
388 }
389 break;
390 }
391
392 if ( empty( $messages ) ) {
393 return true;
394 }
395
396 return array(
397 'reason_code' => 'missing_requirements',
398 'description' => sprintf(
399 __( '<p>There is a new version of %1$s available but you are missing the following minimum requirements:</p>%2$s', 'charitable' ),
400 esc_html( $version_info['name'] ),
401 '<ul>' . implode( '<br/>', $messages ) . '</ul>'
402 ),
403 );
404 }
405
406 return true;
407 }
408 }
409
410 /**
411 * Set upgrader package options.
412 *
413 * This is used for expired licenses and in certain cases for products that do
414 * not have a license activated.
415 *
416 * @since 1.4.20
417 *
418 * @param array $options Upgrader package options.
419 * @return array
420 */
421 public function set_upgrader_package_options( $options ) {
422 if ( 'expired_license' != $options['package'] && empty( $options['package'] ) ) {
423 return $options;
424 }
425
426 if ( ! array_key_exists( 'hook_extra', $options ) || ! array_key_exists( 'plugin', $options['hook_extra'] ) ) {
427 return $options;
428 }
429
430 list( $plugin_key, ) = explode( '/', str_replace( '-', '_', $options['hook_extra']['plugin'] ) );
431
432 if ( ! array_key_exists( $plugin_key, $this->products ) ) {
433 return $options;
434 }
435
436 /* Set up the renewal link for expired licenses. */
437 if ( 'expired_license' == $options['package'] ) {
438 $options['package'] = $this->get_expired_license_package( $options['hook_extra']['plugin'] );
439
440 return $options;
441 }
442
443 /* Set up the renewal link for plugins where minimum requirements haven't been met. */
444 if ( 'missing_requirements' == $options['package'] ) {
445 $options['package'] = $this->get_missing_requirements_package( $options['hook_extra']['plugin'] );
446
447 return $options;
448 }
449
450 $license_details = $this->get_license_details( $plugin_key );
451
452 if ( ! is_array( $license_details ) || ! array_key_exists( 'license', $license_details ) || empty( $license_details['license'] ) ) {
453 $options['package'] = 'missing_license';
454 }
455
456 return $options;
457 }
458
459 /**
460 * Return the package string for an expired license.
461 *
462 * @since 1.4.20
463 *
464 * @param string $plugin Plugin basename.
465 * @return string
466 */
467 public function get_expired_license_package( $plugin ) {
468 $version_info = $this->get_version_info( $plugin );
469 $base_renewal_url = isset( $version_info->renewal_link ) ? $version_info->renewal_link : 'https://www.wpcharitable.com/account';
470
471 return sprintf( 'expired_license:%s', charitable_ga_url(
472 $base_renewal_url,
473 urlencode( 'WordPress Dashboard'),
474 urlencode( 'Expired License' )
475 ));
476
477 }
478
479 /**
480 * Return the package string for a plugin missing requirements.
481 *
482 * @since 1.6.14
483 *
484 * @param string $plugin Plugin basename.
485 * @return string
486 */
487 public function get_missing_requirements_package( $plugin ) {
488 $version_info = $this->get_version_info( $plugin );
489
490 return sprintf(
491 'missing_requirements:%s',
492 $version_info->package_download_restriction
493 );
494 }
495
496 /**
497 * Register a product that requires licensing.
498 *
499 * @since 1.0.0
500 *
501 * @param string $item_name The title of the product.
502 * @param string $author The author of the product.
503 * @param string $version The current product version we have installed.
504 * @param string $file The path to the plugin file.
505 * @param string $url The base URL where the plugin is licensed. Defaults to Charitable_Licenses::UPDATE_URL.
506 * @return void
507 */
508 public function register_licensed_product( $item_name, $author, $version, $file, $url = false ) {
509 if ( ! $url ) {
510 $url = Charitable_Licenses::UPDATE_URL;
511 }
512
513 $product_key = $this->get_item_key( $item_name );
514
515 $this->products[ $product_key ] = array(
516 'name' => $item_name,
517 'author' => $author,
518 'version' => $version,
519 'url' => $url,
520 'file' => $file,
521 );
522
523 $licenses = $this->get_licenses();
524 $license = isset( $licenses[ $product_key ]['license'] ) ? trim( $licenses[ $product_key ]['license'] ) : '';
525
526 new Charitable_Plugin_Updater( $url, $file, array(
527 'version' => $version,
528 'license' => $license,
529 'item_name' => $item_name,
530 'author' => $author,
531 ) );
532
533 }
534
535 /**
536 * Return the list of products requiring licensing.
537 *
538 * @since 1.0.0
539 *
540 * @return array[]
541 */
542 public function get_products() {
543 return $this->products;
544 }
545
546 /**
547 * Return a specific product's details.
548 *
549 * @since 1.0.0
550 *
551 * @param string $item The item for which we are getting product details.
552 * @return string[]
553 */
554 public function get_product_license_details( $item ) {
555 return isset( $this->products[ $item ] ) ? $this->products[ $item ] : false;
556 }
557
558 /**
559 * Returns whether the given product has a valid license.
560 *
561 * @since 1.0.0
562 *
563 * @param string $item The item to check.
564 * @return boolean
565 */
566 public function has_valid_license( $item ) {
567 $license = $this->get_license_details( $item );
568
569 if ( ! $license || ! isset( $license['valid'] ) ) {
570 return false;
571 }
572
573 return $license['valid'];
574 }
575
576 /**
577 * Returns the license details for the given product.
578 *
579 * @since 1.0.0
580 *
581 * @param string $item The item to get the license for.
582 * @return mixed[]
583 */
584 public function get_license( $item ) {
585 $license = $this->get_license_details( $item );
586
587 if ( ! $license || ! is_array( $license ) ) {
588 return false;
589 }
590
591 return $license['license'];
592 }
593
594 /**
595 * Returns the active license details for the given product.
596 *
597 * @since 1.0.0
598 *
599 * @param string $item The item to get active licensing details for.
600 * @return mixed[]
601 */
602 public function get_license_details( $item ) {
603 $licenses = $this->get_licenses();
604
605 if ( ! isset( $licenses[ $item ] ) ) {
606 return false;
607 }
608
609 return $licenses[ $item ];
610 }
611
612 /**
613 * Return the list of licenses.
614 *
615 * Note: The licenses are not necessarily valid. If a user enters an invalid
616 * license, the license will be stored but it will be flagged as invalid.
617 *
618 * @since 1.0.0
619 *
620 * @return array[]
621 */
622 public function get_licenses() {
623 if ( ! isset( $this->licenses ) ) {
624 $this->licenses = charitable_get_option( 'licenses', array() );
625 }
626
627 return $this->licenses;
628 }
629
630 /**
631 * Verify a license.
632 *
633 * @since 1.0.0
634 *
635 * @param string $item The item to verify.
636 * @param string $license The license key for the item.
637 * @param boolean $force Whether to force the verification check.
638 * @return mixed[]
639 */
640 public function verify_license( $item, $license, $force = false ) {
641 $license = trim( $license );
642
643 if ( $license === $this->get_license( $item ) && ! $force ) {
644 return $this->get_license_details( $item );
645 }
646
647 $product_details = $this->get_product_license_details( $item );
648
649 /* This product was not correctly registered. */
650 if ( ! $product_details ) {
651 return;
652 }
653
654 /* Data to send in our API request */
655 $api_params = array(
656 'edd_action' => 'activate_license',
657 'license' => $license,
658 'item_name' => urlencode( $product_details['name'] ),
659 'url' => home_url(),
660 );
661
662 /* Call the custom API */
663 $response = wp_remote_post(
664 $product_details['url'],
665 array(
666 'timeout' => 15,
667 'sslverify' => false,
668 'body' => $api_params,
669 )
670 );
671
672 /* Make sure the response came back okay */
673 if ( is_wp_error( $response ) ) {
674 return;
675 }
676
677 $this->flush_update_cache();
678
679 $license_data = json_decode( wp_remote_retrieve_body( $response ) );
680
681 return array(
682 'license' => $license,
683 'expiration_date' => $license_data->expires,
684 'valid' => ( 'valid' === $license_data->license ),
685 );
686 }
687
688 /**
689 * Return the URL to deactivate a specific license.
690 *
691 * @since 1.0.0
692 *
693 * @param string $item The item to deactivate.
694 * @return string
695 */
696 public function get_license_deactivation_url( $item ) {
697 return esc_url( add_query_arg( array(
698 'charitable_action' => 'deactivate_license',
699 'product_key' => $item,
700 '_nonce' => wp_create_nonce( 'license' ),
701 ), admin_url( 'admin.php?page=charitable-settings&tab=licenses' ) ) );
702 }
703
704 /**
705 * Deactivate a license.
706 *
707 * @since 1.0.0
708 *
709 * @return void
710 */
711 public function deactivate_license() {
712 if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'license' ) ) {
713 wp_die( esc_attr__( 'Cheatin\' eh?!', 'charitable' ) );
714 }
715
716 $product_key = isset( $_REQUEST['product_key'] ) ? $_REQUEST['product_key'] : false;
717
718 /* Product key must be set */
719 if ( false === $product_key ) {
720 wp_die( esc_attr__( 'Missing product key', 'charitable' ) );
721 }
722
723 $product = $this->get_product_license_details( $product_key );
724
725 /* Make sure we have a valid product with a valid license. */
726 if ( ! $product || ! $this->has_valid_license( $product_key ) ) {
727 wp_die( esc_attr__( 'This product is not valid or does not have a valid license key.', 'charitable' ) );
728 }
729
730 $license = $this->get_license( $product_key );
731
732 /* Data to send to wpcharitable.com to deactivate the license. */
733 $api_params = array(
734 'edd_action' => 'deactivate_license',
735 'license' => $license,
736 'item_name' => urlencode( $product['name'] ),
737 'url' => home_url(),
738 );
739
740 /* Call the custom API. */
741 $response = wp_remote_post( $product['url'], array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
742
743 /* Make sure the response came back okay */
744 if ( is_wp_error( $response ) ) {
745 return;
746 }
747
748 $this->flush_update_cache();
749
750 /* Decode the license data */
751 $license_data = json_decode( wp_remote_retrieve_body( $response ) );
752
753 $settings = get_option( 'charitable_settings' );
754
755 unset( $settings['licenses'][ $product_key ] );
756
757 update_option( 'charitable_settings', $settings );
758
759 wp_redirect( add_query_arg( array( 'tab' => 'licenses' ), admin_url( 'admin.php?page=charitable-settings' ) ) );
760 exit;
761
762 }
763
764 /**
765 * Flush the version update cache.
766 *
767 * @since 1.4.20
768 *
769 * @return void
770 */
771 protected function flush_update_cache() {
772 wp_cache_delete( 'plugin_versions', 'charitable' );
773 set_site_transient( 'update_plugins', null );
774 }
775
776 /**
777 * Return a key for the item, based on the item name.
778 *
779 * @since 1.0.0
780 *
781 * @param string $item_name Name of the item.
782 * @return string
783 */
784 protected function get_item_key( $item_name ) {
785 return strtolower( str_replace( ' ', '_', $item_name ) );
786 }
787
788 /**
789 * Return the latest versions of Charitable plugins.
790 *
791 * @since 1.4.0
792 *
793 * @return array
794 */
795 protected function get_versions() {
796 $versions = wp_cache_get( 'plugin_versions', 'charitable' );
797
798 if ( false === $versions ) {
799
800 $licenses = array();
801
802 foreach ( $this->get_licenses() as $license ) {
803 if ( isset( $license['license'] ) ) {
804 $licenses[] = $license['license'];
805 }
806 }
807
808 $response = wp_remote_post(
809 Charitable_Licenses::UPDATE_URL . '/edd-api/versions-v2/',
810 array(
811 'sslverify' => false,
812 'timeout' => 15,
813 'body' => array(
814 'licenses' => $licenses,
815 'url' => home_url(),
816 ),
817 )
818 );
819
820 $versions = wp_remote_retrieve_body( $response );
821
822 $versions = json_decode( $versions, true );
823
824 wp_cache_set( 'plugin_versions', $versions, 'charitable' );
825 }//end if
826
827 return $versions;
828 }
829 }
830
831 endif;
832