PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.18.0
GiveWP – Donation Plugin and Fundraising Platform v4.18.0
4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 All 257 releases
← All changes | includes/class-give-license-handler.php +925 -769 2.3.0 → 4.18.0 View file →
@@ -3,167 +3,222 @@
3 3 * Give License handler
4 4 *
5 5 * @package Give
6 6 * @subpackage Admin/License
7 - * @copyright Copyright (c) 2016, WordImpress
7 + * @copyright Copyright (c) 2016, GiveWP
8 8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 9 * @since 1.0
10 10 */
11 11
12 12 // Exit if accessed directly.
13 -if ( ! defined( 'ABSPATH' ) ) {
14 - exit;
13 +use Give\Log\Log;
14 +use Give\Vendors\StellarWP\AdminNotices\AdminNotices;
15 +
16 +if ( ! defined('ABSPATH') ) {
17 + exit;
15 18 }
16 19
17 -if ( ! class_exists( 'Give_License' ) ) :
20 +if ( ! class_exists('Give_License') ) :
18 21
19 - /**
20 - * Give_License Class
21 - *
22 - * This class simplifies the process of adding license information
23 - * to new Give add-ons.
24 - *
25 - * @since 1.0
26 - */
27 - class Give_License {
22 + /**
23 + * Give_License Class
24 + *
25 + * This class simplifies the process of adding license information
26 + * to new Give add-ons.
27 + *
28 + * @since 1.0
29 + */
30 + class Give_License
31 + {
28 32
29 - /**
30 - * File
31 - *
32 - * @access private
33 - * @since 1.0
34 - *
35 - * @var string
36 - */
37 - private $file;
33 + /**
34 + * File
35 + *
36 + * @access private
37 + * @since 1.0
38 + *
39 + * @var string
40 + */
41 + private $file;
38 42
39 - /**
40 - * License
41 - *
42 - * @access private
43 - * @since 1.0
44 - *
45 - * @var string
46 - */
47 - private $license;
43 + /**
44 + * License
45 + *
46 + * @access private
47 + * @since 1.0
48 + *
49 + * @var string
50 + */
51 + private $license;
48 52
49 - /**
50 - * Item name
51 - *
52 - * @access private
53 - * @since 1.0
54 - *
55 - * @var string
56 - */
57 - private $item_name;
53 + /**
54 + * The license bundled with the premium add-on.
55 + *
56 + * @since 3.21.0
57 + *
58 + * @var string|null
59 + */
60 + private $bundled_license;
58 61
59 - /**
60 - * Item ID
61 - *
62 - * @access private
63 - * @since 2.2.4
64 - *
65 - * @var int
66 - */
67 - private $item_id;
62 + /**
63 + * Item name
64 + *
65 + * @access private
66 + * @since 1.0
67 + *
68 + * @var string
69 + */
70 + private $item_name;
68 71
69 - /**
70 - * License Information object.
71 - *
72 - * @access private
73 - * @since 1.7
74 - *
75 - * @var object
76 - */
77 - private $license_data;
72 + /**
73 + * Item ID
74 + *
75 + * @access private
76 + * @since 2.2.4
77 + *
78 + * @var int
79 + */
80 + private $item_id;
78 81
79 - /**
80 - * Item shortname
81 - *
82 - * @access private
83 - * @since 1.0
84 - *
85 - * @var string
86 - */
87 - private $item_shortname;
82 + /**
83 + * License Information object.
84 + *
85 + * @access private
86 + * @since 1.7
87 + *
88 + * @var object
89 + */
90 + private $license_data;
88 91
89 - /**
90 - * Version
91 - *
92 - * @access private
93 - * @since 1.0
94 - *
95 - * @var string
96 - */
97 - private $version;
92 + /**
93 + * Item shortname
94 + *
95 + * @access private
96 + * @since 1.0
97 + *
98 + * @var string
99 + */
100 + private $item_shortname;
98 101
99 - /**
100 - * Author
101 - *
102 - * @access private
103 - * @since 1.0
104 - *
105 - * @var string
106 - */
107 - private $author;
102 + /**
103 + * Version
104 + *
105 + * @access private
106 + * @since 1.0
107 + *
108 + * @var string
109 + */
110 + private $version;
108 111
109 - /**
110 - * API URL
111 - *
112 - * @access private
113 - * @since 1.0
114 - *
115 - * @var string
116 - */
117 - private $api_url = 'https://givewp.com/edd-sl-api/';
112 + /**
113 + * Author
114 + *
115 + * @access private
116 + * @since 1.0
117 + *
118 + * @var string
119 + */
120 + private $author;
118 121
119 - /**
120 - * array of licensed addons
121 - *
122 - * @since 2.1.4
123 - * @access private
124 - *
125 - * @var array
126 - */
127 - private static $licensed_addons = array();
122 + /**
123 + * Plugin basename (as provided by plugin_basename() function)
124 + *
125 + * @var string
126 + */
127 + private $plugin_basename;
128 128
129 - /**
130 - * Account URL
131 - *
132 - * @access private
133 - * @since 1.7
134 - *
135 - * @var null|string
136 - */
137 - private $account_url = 'https://givewp.com/my-account/';
129 + /**
130 + * Plugin directory name
131 + *
132 + * @access private
133 + * @since 2.5.0
134 + *
135 + * @var string
136 + */
137 + private $plugin_dirname;
138 138
139 - /**
140 - * Checkout URL
141 - *
142 - * @access private
143 - * @since 1.7
144 - *
145 - * @var null|string
146 - */
147 - private $checkout_url = 'https://givewp.com/checkout/';
139 + /**
140 + * Website URL
141 + *
142 + * @access private
143 + * @since 1.0
144 + *
145 + * @var string
146 + */
147 + private static $site_url = 'https://givewp.com/';
148 148
149 - /**
150 - * Class Constructor
151 - *
152 - * Set up the Give License Class.
153 - *
154 - * @access public
155 - * @since 1.0
156 - *
157 - * @param string $_file
158 - * @param string $_item_name
159 - * @param string $_version
160 - * @param string $_author
161 - * @param string $_optname
162 - * @param string $_api_url
149 + /**
150 + * API URL
151 + *
152 + * @access private
153 + * @since 1.0
154 + *
155 + * @var string
156 + */
157 + private static $api_url = 'https://givewp.com/edd-sl-api/';
158 +
159 + /**
160 + * array of licensed addons
161 + *
162 + * @since 3.21.0 store the Give_License instances, not just the plugin basenames
163 + * @since 2.1.4
164 + * @access private
165 + *
166 + * @var Give_License[]
167 + */
168 + private static $licensed_addons = [];
169 +
170 + /**
171 + * Account URL
172 + *
173 + * @access private
174 + * @since 1.7
175 + *
176 + * @var null|string
177 + */
178 + private static $account_url = 'http://docs.givewp.com/settings-account';
179 +
180 + /**
181 + * Downloads URL
182 + *
183 + * @access private
184 + * @since 2.5.0
185 + *
186 + * @var null|string
187 + */
188 + private static $downloads_url = 'http://docs.givewp.com/settings-downloads';
189 +
190 + /**
191 + * Checkout URL
192 + *
193 + * @access private
194 + * @since 1.7
195 + *
196 + * @var null|string
197 + */
198 + private static $checkout_url = 'https://givewp.com/checkout/';
199 +
200 + /**
201 + * Class Constructor
202 + *
203 + * Set up the Give License Class.
204 + *
205 + * @access public
206 + *
207 + * @since 3.17.2 removed unused auto_updater_obj property assignment
208 + * @since 1.0
209 + *
210 + * @param string $_file
211 + * @param string $_item_name
212 + * @param string $_version
213 + * @param string $_author
214 + * @param string $_optname
215 + * @param string $_api_url
163 216 * @param string $_checkout_url
164 - * @param string $_account_url
217 + * @param string $_account_url
165 218 * @param int $_item_id
219 + *
220 + * @since 3.21.0 adds plugin_basename property
166 221 */
167 222 public function __construct(
168 223 $_file,
169 224 $_item_name,
@@ -184,48 +239,34 @@
184 239 if ( is_numeric( $_item_id ) ) {
185 240 $this->item_id = absint( $_item_id );
186 241 }
187 242
188 - $give_options = give_get_settings();
189 -
190 243 $this->file = $_file;
191 244 $this->item_name = $_item_name;
245 + $this->plugin_basename = plugin_basename($this->file);
246 + $this->plugin_dirname = dirname( plugin_basename( $this->file ) );
192 247 $this->item_shortname = self::get_short_name( $this->item_name );
248 + $this->license_data = self::get_license_by_plugin_dirname( $this->plugin_dirname );
193 249 $this->version = $_version;
194 - $this->license = isset( $give_options[ $this->item_shortname . '_license_key' ] ) ? trim( $give_options[ $this->item_shortname . '_license_key' ] ) : '';
195 - $this->license_data = __give_get_active_license_info( $this->item_shortname );
250 + $this->license = ! empty( $this->license_data['license_key'] ) ? $this->license_data['license_key'] : '';
251 + $this->bundled_license = self::get_bundled_license($this->file);
196 252 $this->author = $_author;
197 - $this->api_url = is_null( $_api_url ) ? $this->api_url : $_api_url;
198 - $this->checkout_url = is_null( $_checkout_url ) ? $this->checkout_url : $_checkout_url;
199 - $this->account_url = is_null( $_account_url ) ? $this->account_url : $_account_url;
200 - $this->auto_updater_obj = null;
253 + self::$api_url = is_null( $_api_url ) ? self::$api_url : $_api_url;
254 + self::$checkout_url = is_null( $_checkout_url ) ? self::$checkout_url : $_checkout_url;
255 + self::$account_url = is_null( $_account_url ) ? self::$account_url : $_account_url;
201 256
202 - // Add Setting for Give Add-on activation status.
203 - $is_addon_activated = get_option( 'give_is_addon_activated' );
204 - if ( ! $is_addon_activated && is_object( $this ) ) {
205 - update_option( 'give_is_addon_activated', true, false );
206 - Give_Cache::set( 'give_cache_hide_license_notice_after_activation', true, DAY_IN_SECONDS );
207 - }
208 -
209 257 // Add plugin to registered licenses list.
210 - array_push( self::$licensed_addons, plugin_basename( $this->file ) );
211 -
212 - // Setup hooks
213 - $this->includes();
214 - $this->hooks();
215 -
258 + array_push(self::$licensed_addons, $this);
216 259 }
217 260
218 -
219 261 /**
220 262 * Get plugin shortname
221 263 *
222 - * @since 2.1.0
223 - * @access public
224 - *
225 264 * @param $plugin_name
226 265 *
227 266 * @return string
267 + * @since 2.1.0
268 + * @access public
228 269 */
229 270 public static function get_short_name( $plugin_name ) {
230 271 $plugin_name = trim( str_replace( 'Give - ', '', $plugin_name ) );
231 272 $plugin_name = 'give_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $plugin_name ) ) );
@@ -232,789 +273,904 @@
232 273
233 274 return $plugin_name;
234 275 }
235 276
236 - /**
237 - * Includes
238 - *
239 - * Include the updater class.
240 - *
241 - * @access private
242 - * @since 1.0
243 - *
244 - * @return void
245 - */
246 - private function includes() {
277 + /**
278 + * Checks to see if the license was bundled with the add-on and if so, returns it. This is meant to be a
279 + * convenience, so any errors are ignored and the user can still manually enter their license key.
280 + *
281 + * @since 3.21.0
282 + */
283 + public static function get_bundled_license(string $plugin_file): ?string
284 + {
285 + $license = null;
286 + $file_path = plugin_dir_path($plugin_file) . 'PLUGIN_LICENSE.php';
287 + if (is_readable($file_path)) {
288 + $license = include $file_path;
289 + }
247 290
248 - if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
249 - require_once 'admin/EDD_SL_Plugin_Updater.php';
250 - }
251 - }
291 + return $license ?: null;
292 + }
252 293
253 - /**
254 - * Hooks
255 - *
256 - * Setup license hooks.
257 - *
258 - * @access private
259 - * @since 1.0
260 - *
261 - * @return void
262 - */
263 - private function hooks() {
294 + /**
295 + * This sorts through all the registered add-ons and checks to see if any of them have bundled licenses, but
296 + * aren't set up with a license key. If so, it will attempt to activate the license key for them.
297 + *
298 + * It's likely that many add-ons will have the same license key which is a plan, so the license key will only be
299 + * activated once for all add-ons using it.
300 + *
301 + * If any sort of error occurs, an admin notice will be shown to the user providing the error and instructions
302 + * to manually activate the license key.
303 + *
304 + * Note: much of this code is taken directly from give_get_license_info_handler()
305 + *
306 + * @since 3.21.0
307 + */
308 + public static function activate_bundled_licenses(): void
309 + {
310 + $unactivated_bundled_licenses = [];
311 + foreach (self::$licensed_addons as $addon) {
312 + if ($addon->bundled_license && empty($addon->license)) {
313 + // Store a unique associative array where the key is the license key and the value is an array of
314 + // addons using that license
315 + if ( ! isset($unactivated_bundled_licenses[$addon->bundled_license])) {
316 + $unactivated_bundled_licenses[$addon->bundled_license] = [];
317 + }
264 318
265 - // Register settings.
266 - add_filter( 'give_settings_licenses', array( $this, 'settings' ), 1 );
319 + $unactivated_bundled_licenses[$addon->bundled_license][] = $addon;
320 + }
321 + }
267 322
268 - // Activate license key on settings save.
269 - add_action( 'admin_init', array( $this, 'activate_license' ), 10 );
323 + if (empty($unactivated_bundled_licenses)) {
324 + return;
325 + }
270 326
271 - // Deactivate license key.
272 - add_action( 'admin_init', array( $this, 'deactivate_license' ), 11 );
327 + $show_failed_activation_notice = static function ($license_key, $reason) {
328 + AdminNotices::show(
329 + "license-bundle-activation-error-$license_key",
330 + "An error occurred while attempting to activate license <code>$license_key</code>. $reason. Please activate the license manually."
331 + )->autoParagraph()->asError()->dismissible();
332 + };
273 333
274 - // Updater.
275 - add_action( 'admin_init', array( $this, 'auto_updater' ), 0 );
276 - add_action( 'admin_notices', array( $this, 'notices' ) );
334 + foreach ($unactivated_bundled_licenses as $license => $addons) {
335 + $check_license_res = self::request_license_api(
336 + [
337 + 'edd_action' => 'check_license',
338 + 'license' => $license,
339 + ],
340 + true
341 + );
342 + $is_plan_license = ! empty($check_license_res['is_all_access_pass']);
277 343
278 - // Check license weekly.
279 - Give_Cron::add_weekly_event( array( $this, 'weekly_license_check' ) );
344 + if (is_wp_error($check_license_res)) {
345 + $show_failed_activation_notice($license, $check_license_res->get_error_message());
346 + continue;
347 + }
280 348
281 - // Check subscription weekly.
282 - Give_Cron::add_weekly_event( array( $this, 'weekly_subscription_check' ) );
349 + if ( ! $check_license_res['success']) {
350 + $reason = $check_license_res['error'] ?? 'The licensing server was unreachable';
351 + $show_failed_activation_notice( $license, $reason );
352 + continue;
353 + }
283 354
284 - // Show addon notice on plugin page.
285 - $plugin_name = explode( 'plugins/', $this->file );
286 - $plugin_name = end( $plugin_name );
287 - add_action( "after_plugin_row_{$plugin_name}", array( $this, 'plugin_page_notices' ), 10, 3 );
355 + if ( ! $is_plan_license) {
356 + if (count($addons) > 1) {
357 + $show_failed_activation_notice(
358 + $license,
359 + 'A single add-on license cannot be used for multiple add-ons'
360 + );
361 + continue;
362 + }
288 363
289 - }
364 + if ($check_license_res['plugin_slug'] !== $addons[0]->plugin_dirname) {
365 + $show_failed_activation_notice(
366 + $license,
367 + 'The license is not valid for this add-on'
368 + );
369 + continue;
370 + }
371 + }
290 372
373 + $activate_license_res = self::request_license_api(
374 + [
375 + 'edd_action' => 'activate_license',
376 + 'item_name' => $check_license_res['item_name'],
377 + 'license' => $license,
378 + ],
379 + true
380 + );
291 381
292 - /**
293 - * Auto Updater
294 - *
295 - * @access private
296 - * @since 1.0
297 - *
298 - * @return void
299 - */
300 - public function auto_updater() {
382 + if (is_wp_error($activate_license_res)) {
383 + $show_failed_activation_notice($license, $activate_license_res->get_error_message());
384 + continue;
385 + }
301 386
302 - if ( ! empty( $this->item_id ) ) {
303 - $args['item_id'] = $this->item_id;
304 - } else {
305 - $args['item_name'] = $this->item_name;
306 - }
387 + $check_license_res['license'] = $activate_license_res['license'];
388 + $check_license_res['site_count'] = $activate_license_res['site_count'];
389 + $check_license_res['activations_left'] = $activate_license_res['activations_left'];
390 + $licenses = get_option('give_licenses', []);
307 391
308 - // Setup the updater.
309 - $this->auto_updater_obj = new EDD_SL_Plugin_Updater(
310 - $this->api_url,
311 - $this->file,
312 - array(
313 - 'version' => $this->version,
314 - 'license' => $this->license,
315 - 'item_name' => $this->item_name,
316 - 'author' => $this->author,
317 - )
318 - );
319 - }
392 + if ($is_plan_license) {
393 + $addonSlugs = self::getAddonSlugsFromAllAccessPassLicense($check_license_res);
394 + foreach ($licenses as $license_key => $data) {
395 + if (in_array($data['plugin_slug'], $addonSlugs, true) || ! empty($data['is_all_access_pass'])) {
396 + unset($licenses[$license_key]);
397 + }
398 + }
399 + }
320 400
321 - /**
322 - * License Settings
401 + $licenses[$check_license_res['license_key']] = $check_license_res;
402 + update_option('give_licenses', $licenses);
403 + }
404 +
405 + // Have WordPress check for updates
406 + give_refresh_licenses();
407 + }
408 +
409 + /**
410 + * Activate License
323 411 *
324 - * Add license field to settings.
412 + * Activate the license key.
325 413 *
326 414 * @access public
415 + * @return void
327 416 * @since 1.0
328 - *
329 - * @param array $settings License settings.
330 - *
331 - * @return array License settings.
332 417 */
333 - public function settings( $settings ) {
334 -
335 - $give_license_settings = array(
336 - array(
337 - 'name' => $this->item_name,
338 - 'id' => $this->item_shortname . '_license_key',
339 - 'desc' => '',
340 - 'type' => 'license_key',
341 - 'options' => array(
342 - 'license' => get_option( $this->item_shortname . '_license_active' ),
343 - 'shortname' => $this->item_shortname,
344 - 'item_name' => $this->item_name,
345 - 'api_url' => $this->api_url,
346 - 'checkout_url' => $this->checkout_url,
347 - 'account_url' => $this->account_url,
348 - ),
349 - 'size' => 'regular',
350 - ),
351 - );
352 -
353 - return array_merge( $settings, $give_license_settings );
418 + public function activate_license() {
354 419 }
355 420
356 421 /**
357 - * License Settings Content
422 + * Deactivate License
358 423 *
359 - * Add Some Content to the Licensing Settings.
424 + * Deactivate the license key.
360 425 *
361 426 * @access public
427 + * @return void
362 428 * @since 1.0
363 - *
364 - * @param array $settings License settings content.
365 - *
366 - * @return array License settings content.
367 429 */
368 - public function license_settings_content( $settings ) {
430 + public function deactivate_license() {
431 + }
369 432
370 - $give_license_settings = array(
371 - array(
372 - 'name' => __( 'Add-on Licenses', 'give' ),
373 - 'desc' => '<hr>',
374 - 'type' => 'give_title',
375 - 'id' => 'give_title',
376 - ),
377 - );
378 433
379 - return array_merge( $settings, $give_license_settings );
380 - }
381 -
382 434 /**
383 - * Activate License
384 - *
385 - * Activate the license key.
386 - *
387 - * @access public
388 - * @since 1.0
389 - *
390 - * @return void
391 - */
392 - public function activate_license() {
393 - // Bailout.
394 - if ( ! $this->__is_user_can_edit_license() ) {
395 - return;
396 - }
435 + * Get license information.
436 + *
437 + * @param string $edd_action
438 + * @param bool $response_in_array
439 + *
440 + * @return mixed
441 + * @deprecated 2.5.0 Use self::request_license_api instead.
442 + *
443 + * @since 1.8.9
444 + * @access public
445 + */
446 + public function get_license_info($edd_action = '', $response_in_array = false)
447 + {
448 + if ( empty($edd_action) ) {
449 + return false;
450 + }
397 451
398 - // Allow third party addon developers to handle license activation.
399 - if ( $this->__is_third_party_addon() ) {
400 - do_action( 'give_activate_license', $this );
452 + give_doing_it_wrong(__FUNCTION__, 'Use self::request_license_api instead from GiveWP 2.5.0');
401 453
402 - return;
403 - }
454 + // Data to send to the API.
455 + $api_params = [
456 + 'edd_action' => $edd_action, // never change from "edd_" to "give_"!
457 + 'license' => $this->license,
458 + 'item_name' => urlencode($this->item_name),
459 + ];
404 460
405 - // Delete previous license setting if a empty license key submitted.
406 - if ( empty( $_POST[ "{$this->item_shortname}_license_key" ] ) ) {
407 - $this->unset_license();
461 + return self::request_license_api($api_params, $response_in_array);
462 + }
408 463
409 - return;
410 - }
464 + /**
465 + * Return licensed addons info
466 + *
467 + * Note: note only for internal logic
468 + *
469 + * @since 3.21.1 use array_map to safely access the private property
470 + * @since 3.21.0 plucks the basename for backwards compatibility
471 + * @since 2.1.4
472 + * @return string[]
473 + */
474 + static function get_licensed_addons(): array
475 + {
476 + return array_map( static function ( Give_License $license ) {
477 + return $license->plugin_basename;
478 + }, self::$licensed_addons );
479 + }
411 480
412 - // Do not simultaneously activate add-ons if the user want to deactivate a specific add-on.
413 - if ( $this->is_deactivating_license() ) {
414 - return;
415 - }
481 + /**
482 + * Check if license key attached to subscription
483 + *
484 + * @since 2.5.0
485 + *
486 + * @param string $license_key
487 + *
488 + * @return array
489 + */
490 + static function is_subscription($license_key = '')
491 + {
492 + // Check if current license is part of subscription or not.
493 + $subscriptions = get_option('give_subscriptions');
494 + $subscription = [];
416 495
417 - // Check if plugin previously installed.
418 - if ( $this->is_valid_license() ) {
419 - return;
420 - }
496 + if ( $subscriptions ) {
497 + foreach ($subscriptions as $subs) {
498 + if ( in_array($license_key, $subs['licenses']) ) {
499 + $subscription = $subs;
500 + break;
501 + }
502 + }
503 + }
421 504
422 - // Get license key.
423 - $this->license = sanitize_text_field( $_POST[ $this->item_shortname . '_license_key' ] );
505 + return $subscription;
506 + }
424 507
425 - // Delete previous license key from subscription if previously added.
426 - $this->__remove_license_key_from_subscriptions();
508 + /**
509 + * Get license information.
510 + *
511 + * @since 1.8.9
512 + * @since 2.18.0 log failed license api request information
513 + *
514 + * @param bool $response_in_array
515 + *
516 + * @param array $api_params
517 + *
518 + * @return array|WP_Error
519 + */
520 + public static function request_license_api($api_params = [], $response_in_array = false)
521 + {
522 + // Bailout.
523 + if ( empty($api_params['edd_action']) ) {
524 + return new WP_Error('give-invalid-edd-action', __('Valid edd_action not defined', 'give'));
525 + }
427 526
428 - // Make sure there are no api errors.
429 - if ( ! ( $license_data = $this->get_license_info( 'activate_license' ) ) ) {
430 - return;
431 - }
527 + // Data to send to the API.
528 + $default_api_params = [
529 + // 'edd_action' => $edd_action, never change from "edd_" to "give_"!
530 + // 'license' => $this->license,
531 + // 'item_name' => urlencode( $this->item_name ),
532 + 'url' => home_url(),
533 + ];
432 534
433 - // Make sure license is valid.
434 - // return because admin will want to activate license again.
435 - if ( ! $this->is_license( $license_data ) ) {
436 - // Add license key.
437 - give_update_option( "{$this->item_shortname}_license_key", $this->license );
535 + $api_params = wp_parse_args($api_params, $default_api_params);
438 536
439 - return;
440 - }
537 + // Call the API.
538 + $response = wp_remote_post(
539 + self::get_api_url(),
540 + apply_filters(
541 + 'give_request_license_api_args',
542 + [
543 + 'timeout' => 15,
544 + 'sslverify' => false,
545 + 'body' => $api_params,
546 + ]
547 + )
548 + );
441 549
442 - // Tell WordPress to look for updates.
443 - set_site_transient( 'update_plugins', null );
550 + $statusCode = wp_remote_retrieve_response_code($response);
551 + $body = json_decode(wp_remote_retrieve_body($response), $response_in_array);
444 552
445 - // Add license data.
446 - update_option( "{$this->item_shortname}_license_active", $license_data, false );
553 + if ( 200 !== $statusCode ) {
554 + Log::http(
555 + 'License Api request failed',
556 + [
557 + 'category' => 'License',
558 + 'api url' => self::get_api_url(),
559 + 'request' => $api_params,
560 + 'status code' => $statusCode,
561 + 'response' => $response
562 + ]
563 + );
564 + }
447 565
448 - // Add license key.
449 - give_update_option( "{$this->item_shortname}_license_key", $this->license );
566 + // Make sure there are no errors.
567 + if ( is_wp_error($response) ) {
568 + return $response;
569 + }
450 570
451 - // Check subscription for license key and store this to db (if any).
452 - $this->__single_subscription_check();
453 - }
571 + return $body;
572 + }
454 573
455 574 /**
456 - * Deactivate License
575 + * Get license by plugin dirname
457 576 *
458 - * Deactivate the license key.
577 + * @param string $plugin_dirname
459 578 *
579 + * @return array
580 + *
581 + * @since 4.15.0 add support for Harbor unified licenses
582 + * @since 2.5.0
460 583 * @access public
461 - * @since 1.0
462 - *
463 - * @return void
464 584 */
465 - public function deactivate_license() {
466 - // Bailout.
467 - if ( ! $this->__is_user_can_edit_license() ) {
468 - return;
469 - }
585 + public static function get_license_by_plugin_dirname( $plugin_dirname ) {
586 + $license = [];
587 + $give_licenses = get_option( 'give_licenses', [] );
470 588
471 - // Allow third party add-on developers to handle license deactivation.
472 - if ( $this->__is_third_party_addon() ) {
473 - do_action( 'give_deactivate_license', $this );
589 + if ( ! empty( $give_licenses ) ) {
590 + foreach ( $give_licenses as $give_license ) {
474 591
475 - return;
592 + // Logic to match all access pass license to add-on.
593 + $compares = $give_license['is_all_access_pass']
594 + ? $give_license['download']
595 +
596 + // Prevent PHP notice if somehow automatic update does not run properly.
597 + // Because plugin_slug will only define in updated license rest api response.
598 + : [ [ 'plugin_slug' => ! empty( $give_license['plugin_slug'] ) ? $give_license['plugin_slug'] : '' ] ];
599 +
600 + foreach ( $compares as $compare ) {
601 + if ( ! empty( $compare['plugin_slug'] ) && $plugin_dirname === $compare['plugin_slug'] ) {
602 + $license = $give_license;
603 + break;
604 + }
605 + }
606 + }
476 607 }
477 608
478 - // Run on deactivate button press.
479 - if ( isset( $_POST[ $this->item_shortname . '_license_key_deactivate' ] ) ) {
480 - $this->unset_license();
609 + // Fall back to Harbor feature availability when no legacy license is found.
610 + if ( empty( $license ) && lw_harbor_is_feature_available( $plugin_dirname ) ) {
611 + $license = [ 'license' => 'valid' ];
481 612 }
613 +
614 + return $license;
482 615 }
483 616
617 +
484 618 /**
485 - * Check if license key is valid once per week.
619 + * Get checkout url
486 620 *
487 - * @access public
488 - * @since 1.7
621 + * @return string|null
622 + * @since 2.5.0
623 + */
624 + public static function get_checkout_url() {
625 + return self::$checkout_url;
626 + }
627 +
628 + /**
629 + * Get account url
489 630 *
490 - * @return void
631 + * @return string|null
632 + * @since 2.5.0
491 633 */
492 - public function weekly_license_check() {
634 + public static function get_account_url() {
635 + return self::$account_url;
636 + }
493 637
494 - if (
495 - ! empty( $_POST['give_settings'] ) ||
496 - empty( $this->license )
497 - ) {
498 - return;
499 - }
638 + /**
639 + * Get downloads url
640 + *
641 + * @return string|null
642 + * @since 2.5.0
643 + */
644 + public static function get_downloads_url() {
645 + return self::$downloads_url;
646 + }
500 647
501 - // Allow third party add-on developers to handle their license check.
502 - if ( $this->__is_third_party_addon() ) {
503 - do_action( 'give_weekly_license_check', $this );
648 + /**
649 + * Get account url
650 + *
651 + * @since 3.20.0 allows to override the API URL via constant
652 + * @since 2.5.0
653 + */
654 + public static function get_website_url(): ?string
655 + {
656 + if (defined('GIVE_SITE_URL')) {
657 + return GIVE_SITE_URL;
658 + }
504 659
505 - return;
506 - }
660 + return self::$site_url;
661 + }
507 662
508 - // Make sure there are no api errors.
509 - if ( ! ( $license_data = $this->get_license_info( 'check_license' ) ) ) {
510 - return;
511 - }
512 663
513 - // Bailout.
514 - if ( ! $this->is_license( $license_data ) ) {
515 - return;
516 - }
664 + /**
665 + * Get plugin information by id.
666 + * Note: only for internal use
667 + *
668 + * @param string $plugin_slug
669 + *
670 + * @return array
671 + * @since 2.5.0
672 + */
673 + public static function get_plugin_by_slug( $plugin_slug ) {
674 + $give_plugins = give_get_plugins();
675 + $matching_list = wp_list_pluck( $give_plugins, 'Dir', 'Path' );
676 + $is_match_found = array_search( $plugin_slug, $matching_list, true );
517 677
518 - update_option( $this->item_shortname . '_license_active', $license_data, false );
519 -
520 - return;
678 + return $is_match_found ? $give_plugins[ $is_match_found ] : [];
521 679 }
522 680
523 681 /**
524 - * Check subscription validation once per week
682 + * Get plugin information by id.
683 + * Note: only for internal use
525 684 *
526 - * @access public
527 - * @since 1.7
685 + * @param string $plugin_slug
528 686 *
529 - * @return void
687 + * @return string
688 + * @since 2.5.0
530 689 */
531 - public function weekly_subscription_check() {
532 - // Bailout.
533 - if (
534 - ! empty( $_POST['give_settings'] )
535 - || empty( $this->license )
536 - ) {
537 - return;
538 - }
690 + public static function build_plugin_name_from_slug( $plugin_slug ) {
691 + $plugin_name = str_replace( [ '-', 'give ' ], [ ' ', 'Give - ' ], $plugin_slug );
539 692
540 - // Remove old subscription data.
541 - if ( absint( get_option( '_give_subscriptions_edit_last', true ) ) < current_time( 'timestamp', 1 ) ) {
542 - delete_option( 'give_subscriptions' );
543 - update_option( '_give_subscriptions_edit_last', strtotime( '+ 1 day', current_time( 'timestamp', 1 ) ), false );
544 - }
545 -
546 - // Allow third party add-on developers to handle their subscription check.
547 - if ( $this->__is_third_party_addon() ) {
548 - do_action( 'give_weekly_subscription_check', $this );
549 -
550 - return;
551 - }
552 -
553 - $this->__single_subscription_check();
693 + return ucwords( $plugin_name );
554 694 }
555 695
556 696 /**
557 - * Check if license key is part of subscription or not
697 + * Render license section
558 698 *
559 - * @access private
560 - * @since 1.7
561 - *
562 - * @return void
699 + * @return string
700 + * @since 2.5.0
563 701 */
564 - private function __single_subscription_check() {
565 - if ( empty( $this->license ) ) {
566 - return;
702 + public static function render_licenses_list() {
703 + $give_plugins = give_get_plugins( [ 'only_premium_add_ons' => true ] );
704 + $give_licenses = get_option( 'give_licenses', [] );
705 + $licenses_without_addon = $give_licenses;
706 +
707 + // Get all access pass licenses
708 + $all_access_pass_licenses = [];
709 + $all_access_pass_addon_list = [];
710 + foreach ( $give_licenses as $key => $give_license ) {
711 + if ( $give_license['is_all_access_pass'] ) {
712 + $all_access_pass_licenses[ $key ] = $give_license;
713 +
714 + unset( $licenses_without_addon[ $key ] );
715 +
716 + foreach ( $give_license['download'] as $download ) {
717 + $all_access_pass_addon_list[] = $download['plugin_slug'];
718 + }
719 + }
567 720 }
568 721
569 - /**
570 - * Make sure there are no api errors.
571 - *
572 - * Do not get confused with edd_action check_subscription.
573 - * By default edd software licensing api does not have api to check subscription.
574 - * This is a custom feature to check subscriptions.
575 - */
576 - $subscription_data = $this->get_license_info( 'check_subscription', true );
722 + $html = [
723 + 'unlicensed' => '',
724 + 'licensed' => '',
725 + 'licenses_without_addon' => '',
726 + 'all_access_licensed' => '',
727 + ];
577 728
578 - if ( ! empty( $subscription_data['success'] ) && absint( $subscription_data['success'] ) ) {
729 + if ( ! empty( $give_plugins ) ) {
730 + foreach ( $give_plugins as $give_plugin ) {
731 + if ( in_array( $give_plugin['Dir'], $all_access_pass_addon_list ) ) {
732 + continue;
733 + }
579 734
580 - $subscriptions = get_option( 'give_subscriptions', array() );
735 + $addon_license = self::get_license_by_plugin_dirname( $give_plugin['Dir'] );
736 + $html_arr_key = 'unlicensed';
581 737
582 - // Update subscription data only if subscription does not exist already.
583 - $subscriptions[ $subscription_data['id'] ] = $subscription_data;
738 + if ( $addon_license ) {
739 + $html_arr_key = 'licensed';
740 + unset( $licenses_without_addon[ $addon_license['license_key'] ] );
741 + }
584 742
585 - // Initiate default set of license for subscription.
586 - if ( ! isset( $subscriptions[ $subscription_data['id'] ]['licenses'] ) ) {
587 - $subscriptions[ $subscription_data['id'] ]['licenses'] = array();
743 + $html[ "{$html_arr_key}" ] .= self::html_by_plugin( $give_plugin );
588 744 }
745 + }
589 746
590 - // Store licenses for subscription.
591 - if ( ! in_array( $this->license, $subscriptions[ $subscription_data['id'] ]['licenses'] ) ) {
592 - $subscriptions[ $subscription_data['id'] ]['licenses'][] = $this->license;
747 + if ( ! empty( $all_access_pass_licenses ) ) {
748 + foreach ( $all_access_pass_licenses as $key => $all_access_pass_license ) {
749 + $html['all_access_licensed'] .= self::html_by_license( $all_access_pass_license );
593 750 }
751 + }
594 752
595 - update_option( 'give_subscriptions', $subscriptions, false );
753 + if ( ! empty( $licenses_without_addon ) ) {
754 + foreach ( $licenses_without_addon as $key => $license ) {
755 + if ( in_array( $license['plugin_slug'], $all_access_pass_addon_list ) ) {
756 + continue;
757 + }
758 + $html['licenses_without_addon'] .= self::html_by_license( $license );
759 + }
596 760 }
761 +
762 + ksort( $html );
763 +
764 + // After sorting order will be all_access_licensed -> licensed -> unlicensed
765 +
766 + return implode( '', $html );
597 767 }
598 768
599 769 /**
600 - * Admin notices for errors
770 + * Get add-on item html
771 + * Note: only for internal use
601 772 *
602 - * @access public
603 - * @since 1.0
773 + * @param $plugin
604 774 *
605 - * @return void
775 + * @return string
776 + * @since 2.5.0
606 777 */
607 - public function notices() {
608 -
609 - if ( ! current_user_can( 'manage_give_settings' ) ) {
610 - return;
778 + public static function html_by_plugin( $plugin ) {
779 + // Bailout.
780 + if ( empty( $plugin ) ) {
781 + return '';
611 782 }
612 783
613 - // Do not show licenses notices on license tab.
614 - if ( 'licenses' === give_get_current_setting_tab() ) {
615 - return;
616 - }
784 + ob_start();
785 + $license = self::get_license_by_plugin_dirname( $plugin['Dir'] );
617 786
618 - static $showed_invalid_message;
619 - static $showed_subscriptions_message;
620 - static $addon_license_key_in_subscriptions;
787 + $default_plugin = [
788 + 'ChangeLogSlug' => $plugin['Dir'],
789 + 'DownloadURL' => '',
790 + ];
621 791
622 - // Set default value.
623 - $addon_license_key_in_subscriptions = ! empty( $addon_license_key_in_subscriptions ) ? $addon_license_key_in_subscriptions : array();
624 - $messages = array();
792 + if ( false !== strpos( $default_plugin['ChangeLogSlug'], '-gateway' ) ) {
793 + // We found that each gateway addon does not have `-gateway` in changelog file slug
794 + $default_plugin['ChangeLogSlug'] = str_replace( '-gateway', '', $default_plugin['ChangeLogSlug'] );
795 + }
625 796
626 - // Check whether admin has Give Add-on activated since 24 hours?
627 - $is_license_notice_hidden = Give_Cache::get( 'give_cache_hide_license_notice_after_activation' );
797 + if ( $license ) {
798 + $license['renew_url'] = self::$checkout_url . "?edd_license_key={$license['license_key']}";
799 + $default_plugin['ChangeLogSlug'] = $license['readme'];
800 + $default_plugin['DownloadURL'] = $license['download'];
801 + }
628 802
629 - // Display Invalid License notice, if its more than 24 hours since first Give Add-on activation.
630 - if (
631 - empty( $this->license )
632 - && empty( $showed_invalid_message )
633 - && ( false === $is_license_notice_hidden )
634 - ) {
803 + $plugin['License'] = $license = wp_parse_args(
804 + $license,
805 + [
806 + 'item_name' => str_replace( 'give-', '', $plugin['Dir'] ),
807 + 'purchase_link' => $plugin['PluginURI'],
808 + ]
809 + );
635 810
636 - Give()->notices->register_notice(
637 - array(
638 - 'id' => 'give-invalid-license',
639 - 'type' => 'error',
640 - 'description' => sprintf(
641 - __( 'You have invalid or expired license keys for one or more Give Add-ons. Please go to the <a href="%s">licenses page</a> to correct this issue.', 'give' ),
642 - admin_url( 'edit.php?post_type=give_forms&page=give-settings&tab=licenses' )
643 - ),
644 - 'dismissible_type' => 'user',
645 - 'dismiss_interval' => 'shortly',
646 - )
647 - );
811 + $plugin = wp_parse_args( $plugin, $default_plugin );
812 + ?>
813 + <div class="give-addon-wrap">
814 + <div class="give-addon-inner">
815 + <?php echo self::html_license_row( $license, $plugin ); ?>
816 + <?php echo self::html_plugin_row( $plugin ); ?>
817 + </div>
818 + </div>
819 + <?php
648 820
649 - $showed_invalid_message = true;
821 + return ob_get_clean();
822 + }
650 823
651 - }
824 + /**
825 + * Get add-on item html
826 + * Note: only for internal use
827 + *
828 + * @param array $license
829 + *
830 + * @return string
831 + * @since 2.5.0
832 + */
833 + private static function html_by_license( $license ) {
834 + ob_start();
652 835
653 - // Get subscriptions.
654 - $subscriptions = get_option( 'give_subscriptions' );
836 + $license['renew_url'] = self::$checkout_url . "?edd_license_key={$license['license_key']}";
837 + ?>
838 + <div class="give-addon-wrap">
839 + <div class="give-addon-inner">
840 + <?php
841 + echo self::html_license_row( $license );
655 842
656 - // Show subscription messages.
657 - if ( ! empty( $subscriptions ) && ! $showed_subscriptions_message ) {
843 + $addons = $license['download'];
658 844
659 - foreach ( $subscriptions as $subscription ) {
660 - // Subscription expires timestamp.
661 - $subscription_expires = strtotime( $subscription['expires'] );
662 -
663 - // Start showing subscriptions message before one week of renewal date.
664 - if ( strtotime( '- 7 days', $subscription_expires ) > current_time( 'timestamp', 1 ) ) {
665 - continue;
845 + if ( empty( $license['is_all_access_pass'] ) ) {
846 + $addons = [ $license ];
666 847 }
667 848
668 - // Check if subscription message already exist in messages.
669 - if ( array_key_exists( $subscription['id'], $messages ) ) {
670 - continue;
671 - }
849 + foreach ( $addons as $addon ) {
850 + $default_plugin = [
851 + // In single license key we will get item_name instead of name.
852 + 'Name' => ! empty( $addon['item_name'] ) ? $addon['item_name'] : $addon['name'],
672 853
673 - // Check if license already expired.
674 - if ( strtotime( $subscription['expires'] ) < current_time( 'timestamp', 1 ) ) {
675 - Give()->notices->register_notice(
676 - array(
677 - 'id' => "give-expired-subscription-{$subscription['id']}",
678 - 'type' => 'error',
679 - 'description' => sprintf(
680 - __( 'Your Give add-on license expired for payment <a href="%1$s" target="_blank">#%2$d</a>. <a href="%3$s" target="_blank">Click to renew an existing license</a> or %4$s.', 'give' ),
681 - urldecode( $subscription['invoice_url'] ),
682 - $subscription['payment_id'],
683 - "{$this->checkout_url}?edd_license_key={$subscription['license_key']}&utm_campaign=admin&utm_source=licenses&utm_medium=expired",
684 - Give()->notices->get_dismiss_link(
685 - array(
686 - 'title' => __( 'Click here if already renewed', 'give' ),
687 - 'dismissible_type' => 'user',
688 - 'dismiss_interval' => 'permanent',
689 - )
690 - )
691 - ),
692 - 'dismissible_type' => 'user',
693 - 'dismiss_interval' => 'shortly',
694 - )
695 - );
696 - } else {
697 - Give()->notices->register_notice(
698 - array(
699 - 'id' => "give-expires-subscription-{$subscription['id']}",
700 - 'type' => 'error',
701 - 'description' => sprintf(
702 - __( 'Your Give add-on license will expire in %1$s for payment <a href="%2$s" target="_blank">#%3$d</a>. <a href="%4$s" target="_blank">Click to renew an existing license</a> or %5$s.', 'give' ),
703 - human_time_diff( current_time( 'timestamp', 1 ), strtotime( $subscription['expires'] ) ),
704 - urldecode( $subscription['invoice_url'] ),
705 - $subscription['payment_id'],
706 - "{$this->checkout_url}?edd_license_key={$subscription['license_key']}&utm_campaign=admin&utm_source=licenses&utm_medium=expired",
707 - Give()->notices->get_dismiss_link(
708 - array(
709 - 'title' => __( 'Click here if already renewed', 'give' ),
710 - 'dismissible_type' => 'user',
711 - 'dismiss_interval' => 'permanent',
712 - )
713 - )
714 - ),
715 - 'dismissible_type' => 'user',
716 - 'dismiss_interval' => 'shortly',
717 - )
718 - );
719 - }
854 + 'ChangeLogSlug' => $addon['readme'],
855 + 'Version' => $addon['current_version'],
856 + 'Status' => 'not installed',
720 857
721 - // Stop validation for these license keys.
722 - $addon_license_key_in_subscriptions = array_merge( $addon_license_key_in_subscriptions, $subscription['licenses'] );
723 - }// End foreach().
724 - $showed_subscriptions_message = true;
725 - }// End if().
858 + // In single license key we will get download instead of file.
859 + 'DownloadURL' => ! empty( $addon['download'] ) ? $addon['download'] : $addon['file'],
726 860
727 - // Show Non Subscription Give Add-on messages.
728 - if (
729 - ! in_array( $this->license, $addon_license_key_in_subscriptions )
730 - && ! empty( $this->license )
731 - && empty( $showed_invalid_message )
732 - && ! $this->is_valid_license()
733 - ) {
861 + ];
734 862
735 - Give()->notices->register_notice(
736 - array(
737 - 'id' => 'give-invalid-license',
738 - 'type' => 'error',
739 - 'description' => sprintf(
740 - __( 'You have invalid or expired license keys for one or more Give Add-ons. Please go to the <a href="%s">licenses page</a> to correct this issue.', 'give' ),
741 - admin_url( 'edit.php?post_type=give_forms&page=give-settings&tab=licenses' )
742 - ),
743 - 'dismissible_type' => 'user',
744 - 'dismiss_interval' => 'shortly',
745 - )
746 - );
863 + $plugin = wp_parse_args(
864 + self::get_plugin_by_slug( $addon['plugin_slug'] ),
865 + $default_plugin
866 + );
747 867
748 - $showed_invalid_message = true;
868 + $plugin['Name'] = false !== strpos( $plugin['Name'], 'Give' )
869 + ? $plugin['Name']
870 + : self::build_plugin_name_from_slug( $addon['plugin_slug'] );
749 871
750 - }
751 - }
872 + $plugin['License'] = $license;
752 873
753 - /**
754 - * Check if license is valid or not.
755 - *
756 - * @since 1.7
757 - * @access public
758 - *
759 - * @param null|object $licence_data
760 - *
761 - * @return bool
762 - */
763 - public function is_valid_license( $licence_data = null ) {
764 - $license_data = empty( $licence_data ) ? $this->license_data : $licence_data;
874 + echo self::html_plugin_row( $plugin );
875 + }
876 + ?>
877 + </div>
878 + </div>
879 + <?php
765 880
766 - if ( apply_filters( 'give_is_valid_license', ( $this->is_license( $license_data ) && 'valid' === $license_data->license ) ) ) {
767 - return true;
768 - }
769 -
770 - return false;
881 + return ob_get_clean();
771 882 }
772 883
773 884
774 885 /**
775 - * Check if license is license object of no.
886 + * license row html
776 887 *
777 - * @since 1.7
778 - * @access public
888 + * @param array $license
889 + * @param array $plugin
779 890 *
780 - * @param null|object $licence_data
781 - *
782 - * @return bool
891 + * @return string
892 + * @since 2.5.0
783 893 */
784 - public function is_license( $licence_data = null ) {
785 - $license_data = empty( $licence_data ) ? $this->license_data : $licence_data;
894 + private static function html_license_row( $license, $plugin = [] ) {
895 + ob_start();
786 896
787 - if ( apply_filters( 'give_is_license', ( is_object( $license_data ) && ! empty( $license_data ) && property_exists( $license_data, 'license' ) ) ) ) {
788 - return true;
789 - }
897 + $is_license = $license && ! empty( $license['license_key'] );
898 + $license_key = $is_license ? $license['license_key'] : '';
899 + $license_is_inactive = $license_key && ! in_array( $license['license'], [ 'valid', 'expired' ] );
900 + $expires_timestamp = $is_license ? strtotime( $license['expires'] ) : '';
901 + $is_license_expired = $is_license && ( 'expired' === $license['license'] || $expires_timestamp < time() );
902 + $addon_dir = ! empty( $plugin['Dir'] ) ? $plugin['Dir'] : ( ! empty( $license['plugin_slug'] ) ? $license['plugin_slug'] : '' );
903 + ?>
904 + <div class="give-license-row give-clearfix">
905 + <div class="give-license-notice-container"></div>
906 + <div class="give-license-top give-clearfix">
790 907
791 - return false;
792 - }
908 + <div class="give-license-top-column give-license-key-field-wrap">
793 909
794 - /**
795 - * Check if license is valid or not.
796 - *
797 - * @access private
798 - * @since 1.7
799 - *
800 - * @return bool
801 - */
802 - private function __is_third_party_addon() {
803 - return ( false === strpos( $this->api_url, 'givewp.com/' ) );
804 - }
910 + <div class="give-license__key<?php echo $license_key ? ' give-has-license-key' : ''; ?>">
911 + <?php $value = $license_key ? give_hide_char( $license['license_key'], 5 ) : ''; ?>
912 + <label for="give-license-addon-key-field" class="give-license-top-header"><?php _e( 'License Key', 'give' ); ?></label>
913 + <input id="give-license-addon-key-field" type="text" autocomplete="off" value="<?php echo $value; ?>"<?php echo $value ? ' readonly' : ''; ?>>
914 + <?php if ( ! $license_key ) : ?>
915 + <button class="give-button__license-activate button-primary" data-addon="<?php echo $addon_dir; ?>">
916 + <?php _e( 'Activate', 'give' ); ?>
917 + </button>
918 + <?php elseif ( $license_is_inactive ) : ?>
919 + <button class="give-button__license-reactivate button-primary" data-addon="<?php echo $addon_dir; ?>" data-license="<?php echo $license['license_key']; ?>">
920 + <?php _e( 'Reactivate', 'give' ); ?>
921 + </button>
922 + <?php else : ?>
805 923
806 - /**
807 - * Remove license key from subscription.
808 - *
809 - * This function mainly uses when admin user deactivate license key,
810 - * then we do not need subscription information for that license key.
811 - *
812 - * @access private
813 - * @since 1.7
814 - *
815 - * @return bool
816 - */
817 - private function __remove_license_key_from_subscriptions() {
818 - $subscriptions = get_option( 'give_subscriptions', array() );
924 + <?php
925 + echo sprintf(
926 + '<button class="give-license__deactivate button button-secondary" data-license-key="%2$s" data-item-name="%3$s" data-plugin-dirname="%5$s" data-nonce="%4$s">%1$s</button>',
927 + __( 'Deactivate', 'give' ),
928 + $license['license_key'],
929 + $license['item_name'],
930 + wp_create_nonce( "give-deactivate-license-{$license['item_name']}" ),
931 + ! empty( $license['plugin_slug'] ) ? $license['plugin_slug'] : ''
932 + );
933 + ?>
819 934
820 - // Bailout.
821 - if ( empty( $this->license ) ) {
822 - return false;
823 - }
935 + <?php endif; ?>
824 936
825 - if ( ! empty( $subscriptions ) ) {
826 - foreach ( $subscriptions as $subscription_id => $subscription ) {
827 - $license_index = array_search( $this->license, $subscription['licenses'] );
828 - if ( false !== $license_index ) {
829 - // Remove license key.
830 - unset( $subscriptions[ $subscription_id ]['licenses'][ $license_index ] );
937 + <div class="give-license__status">
938 + <?php
939 + echo $license_key && ! $license_is_inactive
940 + ? sprintf(
941 + '<span class="dashicons dashicons-%2$s"></span>&nbsp;%1$s',
942 + $is_license_expired
943 + ? __( 'License is expired. Please activate your license key.', 'give' )
944 + : __( 'License is active and you are receiving updates and support.', 'give' ),
945 + $is_license_expired
946 + ? 'no'
947 + : 'yes'
948 + )
949 + : sprintf(
950 + '<span class="dashicons dashicons-no"></span> %1$s %2$s',
951 + __( 'License is inactive.', 'give' ),
952 + $license_is_inactive
953 + ? sprintf(
954 + __( 'Please <a href="%1$s" target="_blank">Visit your dashboard</a> to check this license details and activate this license to receive updates and support.', 'give' ),
955 + self::get_account_url()
956 + )
957 + : __( 'Please activate your license key.', 'give' )
958 + );
959 + ?>
960 + </div>
961 + </div>
962 + </div>
831 963
832 - // Rearrange license keys.
833 - $subscriptions[ $subscription_id ]['licenses'] = array_values( $subscriptions[ $subscription_id ]['licenses'] );
964 + <div class="give-license-top-column give-license-info-field-wrap">
965 + <h3 class="give-license-top-header"><?php _e( 'License Information', 'give' ); ?></h3>
966 + <?php
967 + // @todo: handle all license status;
968 + if ( $license_key ) :
969 + ?>
834 970
835 - // Update subscription information.
836 - update_option( 'give_subscriptions', $subscriptions, false );
837 - break;
838 - }
839 - }
840 - }
841 - }
971 + <?php if ( $license_key ) : ?>
972 + <?php
973 + echo sprintf(
974 + '<p class="give-license-renewal-date"><span class="dashicons dashicons-calendar-alt"></span> <strong>%1$s</strong> %2$s</p>',
975 + $is_license_expired ? __( 'Expired:', 'give' ) : __( 'Renews:', 'give' ),
976 + date( give_date_format(), $expires_timestamp )
977 + );
978 + ?>
979 + <?php endif; ?>
842 980
843 - /**
844 - * Display plugin page licenses status notices.
845 - *
846 - * @param $plugin_file
847 - * @param $plugin_data
848 - * @param $status
849 - *
850 - * @return bool
851 - */
852 - public function plugin_page_notices( $plugin_file, $plugin_data, $status ) {
853 - // Bailout.
854 - if ( $this->is_valid_license() ) {
855 - return false;
856 - }
981 + <?php
982 + if ( $is_license_expired ) {
983 + // @todo: need to test renew license link
984 + echo sprintf(
985 + '<a href="%1$s" target="_blank">%2$s</a>',
986 + $license['renew_url'],
987 + __( 'Renew to manage sites', 'give' )
988 + );
989 + } elseif ( $license_key ) {
990 + if ( ! $license['activations_left'] ) {
991 + echo sprintf(
992 + '<span class="give-license-activations-left">%1$s</span>',
993 + __( 'No activations remaining', 'give' )
994 + );
995 + } else {
996 + echo sprintf(
997 + '<span class="give-license-activations-left"><span class="give-license-activations-remaining-icon wp-ui-highlight">%1$s</span> %2$s</span>',
998 + $license['activations_left'],
999 + _n( 'Activation Remaining', 'Activations Remaining', $license['activations_left'], 'give' )
1000 + );
1001 + }
1002 + }
1003 + ?>
1004 + <?php else : ?>
857 1005
858 - $update_notice_wrap = '<tr class="give-addon-notice-tr active"><td colspan="3" class="colspanchange"><div class="notice inline notice-warning notice-alt give-invalid-license"><p><span class="dashicons dashicons-info"></span> %s</p></div></td></tr>';
859 - $message = $this->license_state_message();
1006 + <p class="give-field-description"><?php _e( 'This is an unlicensed add-on and is not receiving updates or support. Please activate your license key to fix the issue.', 'give' ); ?></p>
860 1007
861 - if ( ! empty( $message['message'] ) ) {
862 - echo sprintf( $update_notice_wrap, $message['message'] );
863 - }
864 - }
1008 + <?php endif; ?>
1009 + </div>
865 1010
1011 + <div class="give-license-top-column">
1012 + <h3 class="give-license-top-header"><?php _e( 'License Actions', 'give' ); ?></h3>
866 1013
867 - /**
868 - * Get message related to license state.
869 - *
870 - * @since 1.8.7
871 - * @access public
872 - * @return array
873 - */
874 - public function license_state_message() {
875 - $message_data = array();
1014 + <?php
1015 + // Purchase license link.
1016 + if ( ! $license_key ) :
1017 + ?>
1018 + <?php
1019 + echo sprintf(
1020 + '<a class="give-button button-secondary" href="%1$s" target="_blank">%2$s</a>',
1021 + $license['purchase_link'],
1022 + __( 'Purchase License', 'give' )
1023 + );
1024 + ?>
1025 + <?php endif; ?>
876 1026
877 - if ( ! $this->is_valid_license() ) {
1027 + <?php
1028 + // Manage license link on GiveWP.com
1029 + if ( ! $is_license_expired && $license_key ) {
1030 + echo sprintf(
1031 + '<a href="%1$spurchase-history/?license_id=%2$s&action=manage_licenses&payment_id=%3$s" target="_blank" class="give-license-action-link">%4$s</a>',
1032 + trailingslashit( self::get_website_url() ),
1033 + $license['license_id'],
1034 + $license['payment_id'],
1035 + __( 'Manage License', 'give' )
1036 + );
1037 + echo sprintf(
1038 + '<a href="%1$spriority-support/" target="_blank" class="give-license-action-link">%2$s</a>',
1039 + trailingslashit( self::get_website_url() ),
1040 + __( 'Access Support', 'give' )
1041 + );
1042 + }
1043 + ?>
878 1044
879 - $message_data['message'] = sprintf(
880 - 'Please <a href="%1$s">activate your license</a> to receive updates and support for the %2$s add-on.',
881 - esc_url( admin_url( 'edit.php?post_type=give_forms&page=give-settings&tab=licenses' ) ),
882 - $this->item_name
883 - );
884 - }
885 -
886 - return $message_data;
1045 + </div>
1046 + </div>
1047 + </div>
1048 + <?php
1049 + return ob_get_clean();
887 1050 }
888 1051
889 1052
890 1053 /**
891 - * Check if admin can edit license or not.
1054 + * Plugin row html
892 1055 *
893 - * @since 1.8.9
894 - * @access private
1056 + * @param array $plugin
1057 + *
1058 + * @return string
1059 + * @since 2.5.0
895 1060 */
896 - private function __is_user_can_edit_license() {
897 -
1061 + public static function html_plugin_row( $plugin ) {
898 1062 // Bailout.
899 - if (
900 - ! Give_Admin_Settings::verify_nonce()
901 - || ! current_user_can( 'manage_give_settings' )
902 - || 'licenses' !== give_get_current_setting_tab()
903 - ) {
904 - return false;
1063 + if ( ! $plugin ) {
1064 + return '';
905 1065 }
906 1066
907 - // Security check.
908 - if (
909 - isset( $_POST[ $this->item_shortname . '_license_key-nonce' ] )
910 - && ! wp_verify_nonce( $_REQUEST[ $this->item_shortname . '_license_key-nonce' ], $this->item_shortname . '_license_key-nonce' )
911 - ) {
912 - wp_die( __( 'Nonce verification failed.', 'give' ), __( 'Error', 'give' ), array( 'response' => 403 ) );
913 - }
1067 + $is_license = $plugin['License'] && ! empty( $plugin['License']['license_key'] );
1068 + $expires_timestamp = $is_license ? strtotime( $plugin['License']['expires'] ) : '';
1069 + $is_license_expired = $is_license && ( 'expired' === $plugin['License']['license'] || $expires_timestamp < time() );
1070 + ob_start();
1071 + ?>
1072 + <div class="give-addon-info-wrap give-clearfix">
914 1073
915 - return true;
916 - }
1074 + <div class="give-addon-info-left">
1075 + <span class="give-addon-name">
1076 + <?php echo $plugin['Name']; ?>
1077 + </span>
1078 + <span class="give-addon-version">
1079 + <?php echo sprintf( '%1$s %2$s', __( 'Version', 'give' ), $plugin['Version'] ); ?>
1080 + </span>
1081 + </div>
917 1082
1083 + <div class="give-addon-info-right">
1084 + <?php
1085 + echo sprintf(
1086 + '<a href="%1$s" class="give-ajax-modal give-addon-view-changelog" title="%3$s">%2$s</a>',
1087 + give_modal_ajax_url(
1088 + [
1089 + 'url' => filter_var( $plugin['ChangeLogSlug'], FILTER_VALIDATE_URL )
1090 + ? urldecode_deep( $plugin['ChangeLogSlug'] )
1091 + : urlencode_deep( give_get_addon_readme_url( $plugin['ChangeLogSlug'] ) ),
1092 + 'show_changelog' => 1,
1093 + ]
1094 + ),
1095 + __( 'View Changelog', 'give' ),
1096 + __( 'Changelog of', 'give' ) . " {$plugin['Name']}"
1097 + );
1098 + ?>
918 1099
919 - /**
920 - * Get license information.
921 - *
922 - * @since 1.8.9
923 - * @access public
924 - *
925 - * @param string $edd_action
926 - * @param bool $response_in_array
927 - *
928 - * @return mixed
929 - */
930 - public function get_license_info( $edd_action = '', $response_in_array = false ) {
1100 + <?php
1101 + // Activation status.
1102 + if ( in_array( $plugin['Status'], [ 'active', 'inactive' ] ) ) {
1103 + echo sprintf(
1104 + '<span class="give-addon-activation-status give-addon-activation-status__%1$s">%1$s</span>',
1105 + 'active' === $plugin['Status'] ? __( 'activated', 'give' ) : __( 'installed', 'give' )
1106 + );
1107 + }
931 1108
932 - if ( empty( $edd_action ) ) {
933 - return false;
934 - }
1109 + printf(
1110 + '<%3$s class="give-button button button-secondary button-small" href="%1$s"%4$s><span class="dashicons dashicons-download"></span>%2$s</%3$s>',
1111 + $plugin['DownloadURL'],
1112 + __( 'Download', 'give' ),
1113 + $is_license_expired || ! $plugin['DownloadURL'] ? 'button' : 'a',
1114 + $is_license_expired || ! $plugin['DownloadURL'] ? ' disabled' : ''
1115 + );
1116 + ?>
1117 + </div>
1118 + </div>
1119 + <?php
935 1120
936 - // Data to send to the API.
937 - $api_params = array(
938 - 'edd_action' => $edd_action, // never change from "edd_" to "give_"!
939 - 'license' => $this->license,
940 - 'item_name' => urlencode( $this->item_name ),
941 - 'url' => home_url(),
942 - );
943 -
944 - // Call the API.
945 - $response = wp_remote_post(
946 - $this->api_url,
947 - array(
948 - 'timeout' => 15,
949 - 'sslverify' => false,
950 - 'body' => $api_params,
951 - )
952 - );
953 -
954 - // Make sure there are no errors.
955 - if ( is_wp_error( $response ) ) {
956 - return false;
957 - }
958 -
959 - return json_decode( wp_remote_retrieve_body( $response ), $response_in_array );
1121 + return ob_get_clean();
960 1122 }
961 1123
962 1124
963 1125 /**
964 - * Unset license
1126 + * Get refresh license status
965 1127 *
966 - * @since 1.8.14
967 - * @access private
1128 + * @return mixed|void
1129 + * @since 2.5.0
968 1130 */
969 - private function unset_license() {
970 -
971 - // Remove license key from subscriptions if exist.
972 - $this->__remove_license_key_from_subscriptions();
973 -
974 - // Remove license from database.
975 - delete_option( "{$this->item_shortname}_license_active" );
976 - give_delete_option( "{$this->item_shortname}_license_key" );
977 - unset( $_POST[ "{$this->item_shortname}_license_key" ] );
978 -
979 - // Unset license param.
980 - $this->license = '';
1131 + public static function refresh_license_status() {
1132 + return get_option(
1133 + 'give_licenses_refreshed_last_checked',
1134 + [
1135 + 'compare' => date( 'Ymd' ),
1136 + 'time' => time(),
1137 + 'count' => 0,
1138 + ]
1139 + );
981 1140 }
982 1141
983 -
984 1142 /**
985 - * Check if deactivating any license key or not.
1143 + * Get all download slugs from all access pass key.
1144 + * Note: only for internal use and will be refactored in the future.
986 1145 *
987 - * @since 1.8.17
988 - * @access private
1146 + * @param array $license All access pass license data
989 1147 *
990 - * @return bool
1148 + * @return string[]
1149 + * @since 2.6.3
991 1150 */
992 - private function is_deactivating_license() {
993 - $status = false;
1151 + public static function getAddonSlugsFromAllAccessPassLicense( $license ) {
1152 + $result = [];
994 1153
995 - foreach ( $_POST as $key => $value ) {
996 - if ( false !== strpos( $key, 'license_key_deactivate' ) ) {
997 - $status = true;
998 - break;
999 - }
1154 + foreach ( $license['download'] as $download ) {
1155 + $result[] = $download['plugin_slug'];
1000 1156 }
1001 1157
1002 - return $status;
1158 + return $result;
1003 1159 }
1004 1160
1005 - /**
1006 - * Return licensed addons info
1007 - *
1008 - * Note: note only for internal logic
1009 - *
1010 - * @since 2.1.4
1011 - *
1012 - * @return array
1013 - */
1014 - static function get_licensed_addons() {
1015 - return self::$licensed_addons;
1016 - }
1161 + /**
1162 + * Returns the API URL for license requests, checking for a constant first.
1163 + *
1164 + * @since 3.20.0
1165 + */
1166 + public static function get_api_url(): string
1167 + {
1168 + if (defined('GIVE_LICENSE_API_URL')) {
1169 + return GIVE_LICENSE_API_URL;
1170 + }
1017 1171
1172 + return self::$api_url;
1173 + }
1018 1174 }
1019 1175
1020 1176 endif; // end class_exists check.