PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
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 1.7.0.9 All 211 releases
← All changes | includes/admin/settings/class-charitable-licenses-settings.php +682 -24 1.6.6 → 1.8.13 View file →
@@ -2,16 +2,18 @@
2 2 /**
3 3 * Charitable Licenses Settings UI.
4 4 *
5 5 * @package Charitable/Classes/Charitable_Licenses_Settings
6 - * @version 1.0.0
7 - * @author Eric Daams
8 - * @copyright Copyright (c) 2018, Studio 164a
6 + * @version 1.8.1.12
7 + * @author David Bisset
8 + * @copyright Copyright (c) 2023, WP Charitable LLC
9 9 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
10 10 */
11 11
12 12 // Exit if accessed directly.
13 -if ( ! defined( 'ABSPATH' ) ) { exit; }
13 +if ( ! defined( 'ABSPATH' ) ) {
14 + exit;
15 +}
14 16
15 17 if ( ! class_exists( 'Charitable_Licenses_Settings' ) ) :
16 18
17 19 /**
@@ -67,19 +69,24 @@
67 69 if ( empty( $products ) ) {
68 70 return $tabs;
69 71 }
70 72
71 - $tabs = charitable_add_settings_tab(
72 - $tabs,
73 - 'licenses',
74 - __( 'Licenses', 'charitable' ),
75 - array(
76 - 'index' => 4,
77 - )
78 - );
73 + $show_licenses_tab = apply_filters( 'charitable_show_old_license_tab', false );
79 74
75 + if ( $show_licenses_tab ) :
76 +
77 + $tabs = charitable_add_settings_tab(
78 + $tabs,
79 + 'licenses',
80 + __( 'Licenses', 'charitable' ),
81 + array(
82 + 'index' => 4,
83 + )
84 + );
85 +
86 + endif;
87 +
80 88 return $tabs;
81 -
82 89 }
83 90
84 91 /**
85 92 * Add the licenses tab settings fields.
@@ -143,8 +150,256 @@
143 150 charitable_admin_view( 'settings/licenses' );
144 151 }
145 152
146 153 /**
154 + * Check if a license is expiring in x seconds.
155 + *
156 + * @since 1.8.1.12
157 + *
158 + * @param int $seconds The number of seconds to check for.
159 + * @return bool
160 + */
161 + public function is_license_expiring( $seconds = 1209600 ) {
162 +
163 + if ( $this->is_license_expired() ) {
164 + return false;
165 + }
166 +
167 + // If the 'CHARITABLE_FORCE_EXPIRING_LICENSE' is defined, then return true.
168 + if ( defined( 'CHARITABLE_FORCE_EXPIRING_LICENSE' ) && CHARITABLE_FORCE_EXPIRING_LICENSE ) {
169 + return true;
170 + }
171 +
172 + $expire_date = $this->get_license_expire_date( 'timestamp' );
173 +
174 + if ( false === $expire_date ) {
175 + return false;
176 + }
177 +
178 + // expire_date must be a timestamp, if not then return false.
179 + if ( ! is_numeric( $expire_date ) ) {
180 + return false;
181 + }
182 +
183 + $current_date = time();
184 + // If the license is expiring in x seconds, return true.
185 + if ( $expire_date - $current_date < $seconds ) {
186 + return true;
187 + }
188 + return false;
189 + }
190 +
191 + /**
192 + * Check if a license has expired,
193 + *
194 + * @since 1.8.1.12
195 + *
196 + * @return bool
197 + */
198 + public function is_license_expired() {
199 +
200 + // If the 'CHARITABLE_FORCE_EXPIRED_LICENSE' is defined, then return true. For troubleshooting.
201 + if ( defined( 'CHARITABLE_FORCE_EXPIRED_LICENSE' ) && CHARITABLE_FORCE_EXPIRED_LICENSE ) {
202 + return true;
203 + }
204 +
205 + $expire_date = $this->get_license_expire_date( 'timestamp' );
206 +
207 + if ( false === $expire_date ) {
208 + return false;
209 + }
210 +
211 + // expire_date must be a timestamp, if not then return false.
212 + if ( ! is_numeric( $expire_date ) ) {
213 + return false;
214 + }
215 +
216 + $current_date = time();
217 + // If the license is expiring in x seconds, return true.
218 + if ( $expire_date - $current_date < 0 ) {
219 + return true;
220 + }
221 + return false;
222 + }
223 +
224 + /**
225 + * If a license has expired, do a license request (to make sure we have the most updated informatino, especially when it comes to license renewals).
226 + *
227 + * @since 1.8.3.2
228 + *
229 + * @return void
230 + */
231 + public function maybe_check_if_license_expired() {
232 +
233 + // We need to be on the settings general page, otherwise bail.
234 + if ( ! charitable_is_settings_view( 'general' ) ) {
235 + return;
236 + }
237 +
238 + // Determine if the license is expired.
239 + if ( ! $this->is_license_expired() ) {
240 + return;
241 + }
242 +
243 + // Determine when (if ever) we last checked.
244 +
245 + $settings = get_option( 'charitable_settings' );
246 + $license_settings = $settings['licenses'];
247 +
248 + if ( false === $license_settings || false === $license_settings['charitable-v2'] || ! isset( $license_settings['checked'] ) || time() > $license_settings['checked'] ) {
249 + /*
250 + * Check and see if this check recently happened.
251 + * If it has within the last day (and the license is still expired) then try again for a while.
252 + */
253 +
254 + if ( ! empty( $license_settings['charitable-v2']['license'] ) ) :
255 +
256 + $license_data = charitable_get_helper( 'licenses' )->verify_license( 'charitable', esc_html( $license_settings['charitable-v2']['license'] ), true, false );
257 +
258 + // if the license "keys" don't match, abort.
259 + if ( empty( $license_data ) || ! isset( $license_data['license'] ) || $license_data['license'] !== $license_settings['charitable-v2']['license'] ) { // phpcs:ignore
260 + // do nothing.
261 + } else {
262 + // Check the expiration_date in the license data - if it's not the same as the current expiration date, update it.
263 + if ( isset( $license_data['expiration_date'] ) && $license_data['expiration_date'] !== $license_settings['charitable-v2']['expiration_date'] ) {
264 + $license_settings['charitable-v2']['expiration_date'] = $license_data['expiration_date'];
265 + }
266 + }
267 +
268 + endif;
269 +
270 + // We've done the check, so update the updated time for one day in the future.
271 + $license_settings['checked'] = strtotime( '+1 day' );
272 + $settings['licenses'] = $license_settings;
273 +
274 + global $wpdb;
275 + // manually update the 'charitable_settings' option.
276 + $wpdb->update( // phpcs:ignore
277 + $wpdb->options,
278 + array(
279 + 'option_value' => maybe_serialize( $settings ),
280 + ),
281 + array(
282 + 'option_name' => 'charitable_settings',
283 + )
284 + );
285 +
286 + // redirect to the settings page.
287 + wp_safe_redirect( admin_url( 'admin.php?page=charitable-settings' ) );
288 + exit;
289 + }
290 + }
291 +
292 + /**
293 + * If a license has expired, do a license request (to make sure we have the most updated informatino, especially when it comes to license renewals).
294 + *
295 + * @since 1.8.3.2
296 + *
297 + * @return void
298 + */
299 + public function maybe_check_if_license_expiring() {
300 +
301 + // We need to be on the settings general page, otherwise bail.
302 + if ( ! charitable_is_settings_view( 'general' ) ) {
303 + return;
304 + }
305 +
306 + // Determine if the license is expired.
307 + if ( ! $this->is_license_expiring() ) {
308 + return;
309 + }
310 +
311 + // Determine when (if ever) we last checked.
312 +
313 + $settings = get_option( 'charitable_settings' );
314 + $license_settings = $settings['licenses'];
315 +
316 + if ( false === $license_settings || false === $license_settings['charitable-v2'] || ! isset( $license_settings['checked'] ) || time() > $license_settings['checked'] ) {
317 + /*
318 + * Check and see if this check recently happened.
319 + * If it has within the last day (and the license is still expired) then try again for a while.
320 + */
321 +
322 + if ( ! empty( $license_settings['charitable-v2']['license'] ) ) :
323 +
324 + $license_data = charitable_get_helper( 'licenses' )->verify_license( 'charitable', esc_html( $license_settings['charitable-v2']['license'] ), true, false );
325 +
326 + // if the license "keys" don't match, abort.
327 + if ( empty( $license_data ) || ! isset( $license_data['license'] ) || $license_data['license'] !== $license_settings['charitable-v2']['license'] ) { // phpcs:ignore
328 + // do nothing.
329 + } else {
330 + // Check the expiration_date in the license data - if it's not the same as the current expiration date, update it.
331 + if ( isset( $license_data['expiration_date'] ) && $license_data['expiration_date'] !== $license_settings['charitable-v2']['expiration_date'] ) {
332 + $license_settings['charitable-v2']['expiration_date'] = $license_data['expiration_date'];
333 + }
334 + }
335 +
336 + endif;
337 +
338 + // We've done the check, so update the updated time for one day in the future.
339 + $license_settings['checked'] = strtotime( '+1 day' );
340 + $settings['licenses'] = $license_settings;
341 +
342 + global $wpdb;
343 + // manually update the 'charitable_settings' option.
344 + $wpdb->update( // phpcs:ignore
345 + $wpdb->options,
346 + array(
347 + 'option_value' => maybe_serialize( $settings ),
348 + ),
349 + array(
350 + 'option_name' => 'charitable_settings',
351 + )
352 + );
353 +
354 + // redirect to the settings page.
355 + wp_safe_redirect( admin_url( 'admin.php?page=charitable-settings' ) );
356 + exit;
357 + }
358 + }
359 +
360 + /**
361 + * Get the expire data of a current license (checks for "is_pro" happen before this function).
362 + *
363 + * @since 1.8.1.12
364 + * @version 1.8.1.14 added lifetime license check.
365 + *
366 + * @param mixed $timestamp Whether to return a timestamp or a formatted date.
367 + *
368 + * @return mixed[]
369 + */
370 + public function get_license_expire_date( $timestamp = false ) {
371 +
372 + $settings = get_option( 'charitable_settings' );
373 +
374 + if ( false === $settings ) {
375 + return false;
376 + }
377 +
378 + $license_key = ! empty( $settings['licenses']['charitable-v2']['license'] ) ? esc_html( $settings['licenses']['charitable-v2']['license'] ) : false;
379 + $license_expires = ! empty( $settings['licenses']['charitable-v2']['expiration_date'] ) ? esc_html( $settings['licenses']['charitable-v2']['expiration_date'] ) : false;
380 +
381 + if ( strtolower( $license_expires ) === 'lifetime' ) {
382 + // make the license expire date a long time from now.
383 + if ( $timestamp ) {
384 + return strtotime( '+100 years' );
385 + } else {
386 + return date_i18n( get_option( 'date_format' ), strtotime( '+100 years' ) );
387 + }
388 + }
389 +
390 + if ( false === $license_key || false === $license_expires ) {
391 + return false;
392 + }
393 +
394 + if ( $timestamp ) {
395 + return strtotime( $license_expires );
396 + }
397 +
398 + return date_i18n( get_option( 'date_format' ), strtotime( $license_expires ) );
399 + }
400 +
401 + /**
147 402 * Add an extra button to the Licenses tab to re-check licenses.
148 403 *
149 404 * @since 1.6.0
150 405 *
@@ -157,15 +412,24 @@
157 412 if ( empty( $licenses ) ) {
158 413 return $button;
159 414 }
160 415
161 - $html = '<input style="margin-left:8px;height:29px;" type="submit" class="button button-secondary" name="recheck" value="' . esc_attr__( 'Save & Re-check All Licenses', 'charitable' ) . '" /></p>';
416 + $slug = Charitable_Addons_Directory::get_current_plan_slug();
162 417
163 - return str_replace(
164 - '</p>',
165 - $html,
166 - $button
167 - );
418 + if ( $slug === false || ( is_string( $slug ) && strtolower( $slug ) === 'lite' ) ) {
419 + // there is no valid updated license so allow this button to output.
420 +
421 + $html = '<input style="margin-left:8px;" type="submit" class="button button-secondary" name="recheck" value="' . esc_attr__( 'Save & Re-check All Licenses', 'charitable' ) . '" /></p>';
422 +
423 + return str_replace(
424 + '</p>',
425 + $html,
426 + $button
427 + );
428 +
429 + }
430 +
431 + return $button;
168 432 }
169 433
170 434 /**
171 435 * Checks for updated license and invalidates status field if not set.
@@ -170,8 +434,11 @@
170 434 /**
171 435 * Checks for updated license and invalidates status field if not set.
172 436 *
173 437 * @since 1.0.0
438 + * @version 1.7.0.4
439 + * @version 1.8.6.2 - clear transient _charitable_plugin_versions
440 + * @version 1.8.9.1
174 441 *
175 442 * @param mixed[] $values The parsed values combining old values & new values.
176 443 * @param mixed[] $new_values The newly submitted values.
177 444 * @return mixed[]
@@ -176,34 +443,425 @@
176 443 * @param mixed[] $new_values The newly submitted values.
177 444 * @return mixed[]
178 445 */
179 446 public function save_license( $values, $new_values ) {
447 +
180 448 /* If we didn't just submit licenses, stop here. */
181 - if ( ! isset( $new_values['licenses'] ) ) {
449 + if ( ! isset( $new_values['licenses_legacy'] ) ) {
182 450 return $values;
183 451 }
184 452
453 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
185 454 $re_check = array_key_exists( 'recheck', $_POST );
186 - $licenses = $new_values['licenses'];
455 + $licenses = $new_values['licenses_legacy'];
187 456
457 + // Delete transients (related to plugin versions).
458 + delete_transient( '_charitable_plugin_versions' );
459 +
460 + // Remember that legacy licenses are passed into values differently in this hook. $values[licenses_legacy].
188 461 foreach ( $licenses as $product_key => $license ) {
189 462 $license = trim( $license );
190 463
191 464 if ( empty( $license ) ) {
192 - $values['licenses'][ $product_key ] = '';
465 + $values['licenses_legacy'][ $product_key ] = '';
193 466 continue;
194 467 }
195 468
196 - $license_data = charitable_get_helper( 'licenses' )->verify_license( $product_key, $license, $re_check );
469 + $license_data = charitable_get_helper( 'licenses' )->verify_license( $product_key, $license, $re_check, true ); // the true added to make sure we let the server know we are attempting to vertify a legacy license.
197 470
198 471 if ( empty( $license_data ) ) {
199 472 continue;
200 473 }
201 474
202 - $values['licenses'][ $product_key ] = $license_data;
475 + $values['licenses'][ $product_key ] = $license_data; // this is ok because this follows previous versions of where the licenses would be going.
203 476 }
204 477
205 478 return $values;
479 + }
480 +
481 + /**
482 + * Outputs the "new" license HTML for the general settings tab.
483 + *
484 + * @since 1.7.0.4
485 + * @version 1.8.3 added charitable_is_pro() check.
486 + * @version 1.8.5 added pro_connect flag.
487 + *
488 + * @param string $has_valid_license Allows us to control HTML based on valid license already in the system.
489 + * @return string
490 + */
491 + public function generate_license_check_html( $has_valid_license = 'false' ) {
492 +
493 + $slug = (string) Charitable_Addons_Directory::get_current_plan_slug();
494 + $is_legacy = Charitable_Addons_Directory::is_current_plan_legacy();
495 + $pro_connect = $this->is_pro_connect();
496 + $readonly = false;
497 + $show_license_form = true;
498 +
499 + // PRE-VALIDATION: Check for existing valid licenses before showing upgrade prompt
500 + $licenses_helper = charitable_get_helper( 'licenses' );
501 + $has_stored_valid_license = false;
502 +
503 + // Check if there's already a valid license stored (prevents duplicate prompts)
504 + if ( $licenses_helper ) {
505 + // Check for v3 license (newer format)
506 + if ( method_exists( $licenses_helper, 'is_v3_license_valid' ) && $licenses_helper->is_v3_license_valid() ) {
507 + $has_stored_valid_license = true;
508 + }
509 + // Check for any valid license in the system
510 + elseif ( method_exists( $licenses_helper, 'has_valid_license' ) && $licenses_helper->has_valid_license( 'charitable' ) ) {
511 + $has_stored_valid_license = true;
512 + }
513 + }
514 +
515 + if ( $slug === false || strtolower( $slug ) === 'lite' ) {
516 + $has_valid_license = $has_stored_valid_license; // Use stored license status instead of always false
517 + } elseif ( charitable_is_pro() ) {
518 + $has_valid_license = true;
519 + }
520 +
521 + $output = '<div id="charitable-license-message" class="license-message license-valid-' . $has_valid_license . '">';
522 + if ( $has_valid_license && ! $is_legacy ) {
523 + $output .= $this->get_licensed_message();
524 + $readonly = 'readonly value="xxxxxxxxxxxxxxxxxxxx"';
525 + } else {
526 + // Getting the current plan slug might be only applicate for newer licenses, so we need to account for "legacy" licenses to see if the install is licensed or not.
527 + if ( charitable_is_pro() && $is_legacy ) {
528 + $output .= $this->get_legacy_licensed_message();
529 + $show_license_form = false;
530 + } else {
531 + // 1.8.5
532 + if ( charitable_is_pro() ) {
533 + $output .= $this->get_licensed_message();
534 + $readonly = 'readonly value="xxxxxxxxxxxxxxxxxxxx"';
535 + $has_valid_license = true;
536 + } else {
537 + $output .= $this->get_unlicensed_message();
538 + }
539 + }
540 + }
541 + if ( $show_license_form ) :
542 + $output .= '<p>';
543 + $output .= '<input type="password" autocomplete="off" name="license-key" id="charitable-settings-upgrade-license-key" ' . $readonly . ' placeholder="' . esc_attr__( 'Paste license key here', 'charitable' ) . '" value="" />';
544 + if ( ! $has_valid_license ) {
545 + $output .= '<button data-action="verify" type="button" class="charitable-btn charitable-btn-md charitable-btn-green charitable-btn-activate" id="charitable-settings-connect-btn" data-pro-connect="' . $pro_connect . '">' . esc_html__( 'Verify Key', 'charitable' ) . '</button>';
546 + } elseif ( $has_valid_license ) {
547 + $output .= '<button data-action="deactivate" type="button" class="charitable-btn charitable-btn-md charitable-btn-orange charitable-btn-deactivate" id="charitable-settings-connect-btn">' . esc_html__( 'Deactivate Key', 'charitable' ) . '</button>';
548 + }
549 + $output .= '</p>';
550 + endif;
551 +
552 + // Add help text to the license field.
553 + $output .= '<div class="charitable-help">' . esc_html__( 'Your license key provides access to updates and addons.', 'charitable' ) . '</div>';
554 +
555 + $output . '</div>';
556 +
557 + return $output;
558 + }
559 +
560 + /**
561 + * Checks if the pro_connect flag is set. This decides if entering a license key will trigger Charitable Connect, an improved migration path to Charitable Pro.
562 + *
563 + * @since 1.8.5
564 + * @version 1.8.5.3
565 + *
566 + * @return boolean
567 + */
568 + public function is_pro_connect() {
569 +
570 + if ( defined( 'CHARITABLE_FORCE_PRO_CONNECT' ) && CHARITABLE_FORCE_PRO_CONNECT ) {
571 + return true;
572 + }
573 +
574 + if ( defined( 'CHARITABLE_MANUAL_LICENSE_ACTIVATION' ) && CHARITABLE_MANUAL_LICENSE_ACTIVATION ) {
575 + return false;
576 + }
577 +
578 + // If the pro plugin is already installed (but not activated), then we don't need to do anything.
579 + if ( file_exists( WP_PLUGIN_DIR . '/charitable-pro/charitable.php' ) ) {
580 + return false;
581 + }
582 +
583 + $charitable_activated = (array) get_option( 'charitable_activated', array() );
584 +
585 + // If pro connect has been done before, it can be done again.
586 + if ( ! empty( $charitable_activated['pro_connect'] ) ) {
587 + return true;
588 + }
589 +
590 + // Allows special cases to be handled by other plugins.
591 + return apply_filters( 'charitable_allow_pro_connect', true );
592 + }
593 +
594 + /**
595 + * Outputs a message for unlicnensed users for the general settings tab.
596 + *
597 + * @since 1.7.0.4
598 + *
599 + * @param boolean $valid Valid license.
600 + * @param array $license_data Available license information.
601 + * @param boolean $error Error flag.
602 + * @return string
603 + */
604 + public function get_unlicensed_message( $valid = false, $license_data = false, $error = true ) {
605 +
606 + $output = '<p>' . esc_html__( 'You\'re using ', 'charitable' );
607 + $output .= '<strong>Charitable Lite</strong>';
608 + $output .= esc_html__( ' - no license needed. Enjoy!', 'charitable' ) . ' 🙂</p>';
609 + $output .=
610 + '<p>' .
611 + sprintf(
612 + wp_kses(
613 + /* translators: %s - charitable.com upgrade URL. */
614 + __( 'To unlock more features consider <strong><a href="%s" target="_blank" rel="noopener noreferrer" class="charitable-upgrade-modal">upgrading to PRO</a></strong>.', 'charitable' ),
615 + array(
616 + 'a' => array(
617 + 'href' => array(),
618 + 'class' => array(),
619 + 'target' => array(),
620 + 'rel' => array(),
621 + ),
622 + 'strong' => array(),
623 + )
624 + ),
625 + esc_url( charitable_pro_upgrade_url( 'settings-upgrade' ) )
626 + ) .
627 + '</p>';
628 + $output .=
629 + '<p class="discount-note">' .
630 + wp_kses(
631 + __( 'As a valued Charitable Lite user, you receive up to <strong>$300 off</strong>, automatically applied at checkout!', 'charitable' ),
632 + array(
633 + 'strong' => array(),
634 + 'br' => array(),
635 + )
636 + ) .
637 + '</p>';
638 +
639 + if ( $valid && false === $error ) {
640 + $output .= '<p>' . esc_html__( 'Already registered? You might have an expired or invalid license. Reach out to us for support.', 'charitable' ) . '</p>';
641 + } elseif ( ! $valid && isset( $license_data['license_limit'] ) && false !== $license_data['license_limit'] ) {
642 + $output .= '<p>' . esc_html__( 'There was an error attempting to validate your license key. Check and see if you have exceeded your license activations.', 'charitable' ) . '</p>';
643 + } elseif ( ! $valid && isset( $license_data['comm_success'] ) && false !== $license_data['comm_success'] ) {
644 + $output .= '<p>' . esc_html__( 'There was an error attempting to contact the license server. Please try again later.', 'charitable' ) . '</p>';
645 + // phpcs:disable WordPress.Security.NonceVerification.Recommended
646 + } elseif ( isset( $_GET['valid'] ) && 'invalid' === sanitize_text_field( wp_unslash( $_GET['valid'] ) ) && isset( $_GET['comm_success'] ) && 0 === intval( wp_unslash( $_GET['comm_success'] ) ) ) {
647 + $output .= '<p style="color:red;">' . esc_html__( 'There was an error attempting to validate your license key. Please try again later.', 'charitable' ) . '</p>';
648 + } elseif ( isset( $_GET['valid'] ) && 'invalid' === sanitize_text_field( wp_unslash( $_GET['valid'] ) ) && isset( $_GET['license_limit'] ) && false !== sanitize_text_field( wp_unslash( $_GET['license_limit'] ) ) ) {
649 + $output .= '<p style="color:red;">' . esc_html__( 'There was an error attempting to validate your license key. Check and see if you have exceeded your license activations.', 'charitable' ) . '</p>';
650 + } elseif ( isset( $_GET['valid'] ) && 'invalid' === sanitize_text_field( wp_unslash( $_GET['valid'] ) ) ) {
651 + $output .= '<p style="color:red;" data-invalid="Unknown">' . esc_html__( 'There was a problem attempting to validate your license key. Please try again later.', 'charitable' ) . '</p>';
652 + // phpcs:enable WordPress.Security.NonceVerification.Recommended
653 + } else {
654 + $output .= '<hr><p>' . esc_html__( 'Already purchased? Simply enter your license key below to enable Charitable PRO!', 'charitable' ) . '</p>';
655 + }
656 +
657 + return $output;
658 + }
659 +
660 + /**
661 + * Outputs a message for licnensed users for the general settings tab.
662 + *
663 + * @since 1.7.0.4
664 + * @version 1.8.1.15 added license expiring message, account for no license expire date (lifetime licenses).
665 + *
666 + * @param boolean $force_valid Force valid license (not used).
667 + * @return string
668 + */
669 + public function get_licensed_message( $force_valid = true ) { // phpcs:ignore
670 +
671 + $settings = get_option( 'charitable_settings' );
672 + $price_id = intval( $settings['licenses']['charitable-v2']['plan_id'] );
673 + $license_expires = ! empty( $settings['licenses']['charitable-v2']['expiration_date'] ) ? esc_html( $settings['licenses']['charitable-v2']['expiration_date'] ) : false;
674 + $valid = $settings['licenses']['charitable-v2']['valid'];
675 + $output = '';
676 +
677 + if ( $valid ) {
678 +
679 + $plan_name = $this->get_license_label_from_plan_id( $price_id );
680 +
681 + $output = '<p>' . esc_html__( 'You\'re using ', 'charitable' );
682 + $output .= '<strong>Charitable ' . $plan_name . '</strong>';
683 + if ( $license_expires ) :
684 + if ( 'lifetime' === $license_expires ) :
685 + $output .= esc_html__( '. You have a lifetime license', 'charitable' );
686 + else :
687 + $output .= esc_html__( '. Your license expires on ', 'charitable' );
688 + $output .= gmdate( 'M d, Y', strtotime( $license_expires ) );
689 + endif;
690 + endif;
691 + $output .= esc_html__( '. Enjoy!', 'charitable' ) . ' 🙂</p>';
692 +
693 + if ( $this->is_license_expiring() ) {
694 + $output .= '<p style="color:red;">' . sprintf(
695 + wp_kses(
696 + /* translators: %s - charitable.com upgrade URL. */
697 + __( 'Your license may be expiring soon. Please renew to continue receiving updates and support. <a target="_blank" href="%s">Learn more</a>.', 'charitable' ),
698 + array(
699 + 'a' => array(
700 + 'href' => array(),
701 + 'class' => array(),
702 + 'target' => array(),
703 + 'rel' => array(),
704 + ),
705 + 'br' => array(),
706 + 'strong' => array(),
707 + )
708 + ),
709 + 'https://wpcharitable.com/documentation/expired-expiring-license'
710 + ) . '</p>';
711 + } elseif ( $this->is_license_expired() ) {
712 +
713 + $output .= '<p style="color:red;">' . sprintf(
714 + wp_kses(
715 + /* translators: %s - charitable.com upgrade URL. */
716 + __( 'It appears your license may have expired. Please renew to continue receiving updates and support. <a target="_blank" href="%s">Learn more</a>.', 'charitable' ),
717 + array(
718 + 'a' => array(
719 + 'href' => array(),
720 + 'class' => array(),
721 + 'target' => array(),
722 + 'rel' => array(),
723 + ),
724 + 'br' => array(),
725 + 'strong' => array(),
726 + )
727 + ),
728 + 'https://wpcharitable.com/documentation/expired-expiring-license'
729 + ) . '</p>';
730 + }
731 +
732 + if ( defined( 'CHARITABLE_DEBUG_LICENSE' ) && CHARITABLE_DEBUG_LICENSE ) {
733 + $output .= '<fieldset style="border: 1px; margin: 10px 0; padding: 10px; border-width: 10px; background-color: #eae2d3;"><legend style="border: 1px; background: white; padding: 10px;">Charitable Debug License Data</legend>';
734 + $license_data = '';
735 + foreach ( $settings['licenses'] as $key => $value ) {
736 + if ( is_array( $settings['licenses'][ $key ] ) ) {
737 + foreach ( $settings['licenses'][ $key ] as $k => $v ) {
738 + $license_data .= '<p>' . $k . ' : ' . $v . '</p>';
739 + }
740 + }
741 + }
742 +
743 + $output .= '<p><strong>' . esc_html__( 'License data:', 'charitable' ) . '</strong> ' . $license_data . '</p>';
744 + if ( $settings ) {
745 + $output .= '<p><strong>' . esc_html__( 'Settings data:', 'charitable' ) . '</strong> ' . print_r( $settings, true ) . '</p>'; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
746 + }
747 + if ( $plan_name ) {
748 + $output .= '<p><strong>' . esc_html__( 'Plan name:', 'charitable' ) . '</strong> ' . print_r( $plan_name, true ) . '</p>'; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
749 + }
750 + $output .= '</fieldset>';
751 + if ( charitable_is_debug() ) {
752 + error_log( 'get_licensed_message - valid' ); // phpcs:ignore
753 + error_log( print_r( $settings, true ) ); // phpcs:ignore
754 + error_log( print_r( $plan_name, true ) ); // phpcs:ignore
755 + }
756 + }
757 + } else {
758 + $plan_name = esc_html__( 'Lite', 'charitable' );
759 + if ( intval( $price_id ) > 0 ) {
760 + $valid = esc_html__( 'Your license is not valid or has expired.', 'charitable' );
761 + } else {
762 + $valid = false;
763 + }
764 + $output .= $this->get_unlicensed_message( $valid );
765 + if ( defined( 'CHARITABLE_DEBUG_LICENSE' ) && CHARITABLE_DEBUG_LICENSE ) {
766 + if ( charitable_is_debug() ) {
767 + error_log( 'get_licensed_message - not valid' ); // phpcs:ignore
768 + error_log( print_r( $valid, true ) ); // phpcs:ignore
769 + }
770 + }
771 + }
772 +
773 + return $output;
774 + }
775 +
776 + /**
777 + * Outputs a message for deactivated licenses for the general settings tab.
778 + *
779 + * @since 1.8.5
780 + * @return string
781 + */
782 + public function get_deactivated_message() {
783 +
784 + return sprintf(
785 + '<p class="charitable-license-message-details">'
786 + . '<strong>' . __( 'Your license key has been removed.', 'charitable' ) . '</strong>'
787 + . '</p>'
788 + );
789 + }
790 +
791 + /**
792 + * Get license label from plan id.
793 + *
794 + * @since 1.8.0
795 + *
796 + * @param boolean $plan_id Plan ID.
797 + * @return string
798 + */
799 + public function get_license_label_from_plan_id( $plan_id = false ) {
800 +
801 + return charitable_get_license_label_from_plan_id( $plan_id );
802 + }
803 +
804 + /**
805 + * Outputs a message for unlicnensed users for the general settings tab.
806 + *
807 + * @since 1.7.0.4
808 + * @version 1.8.3.2 remove upsell message.
809 + * @return string
810 + */
811 + public function get_legacy_licensed_message() {
812 +
813 + $output =
814 + '<p>' .
815 + sprintf(
816 + wp_kses(
817 + /* translators: %s - charitable.com upgrade URL. */
818 + __( 'You\'re using <strong>Charitable</strong> with one or more <a href="%s">activated legacy licenses</a>. Enjoy! 🙂', 'charitable' ),
819 + array(
820 + 'a' => array(
821 + 'href' => array(),
822 + 'class' => array(),
823 + 'target' => array(),
824 + 'rel' => array(),
825 + ),
826 + 'br' => array(),
827 + 'strong' => array(),
828 + )
829 + ),
830 + esc_url( admin_url( 'admin.php?page=charitable-settings&tab=advanced' ) )
831 + ) .
832 + '</p>';
833 +
834 + return $output;
835 + }
836 +
837 + /**
838 + * Activates the pro plugin after a license is activated.
839 + *
840 + * @since 1.8.5.3
841 + * @return void
842 + */
843 + public function activate_pro_plugin_after_license_activation() {
844 +
845 + // Check query params.
846 + if ( ! isset( $_GET['valid'] ) || 'valid' !== $_GET['valid'] ) { // phpcs:ignore
847 + return;
848 + }
849 +
850 + if ( ! isset( $_GET['pro'] ) || 'activate' !== $_GET['pro'] ) { // phpcs:ignore
851 + return;
852 + }
853 + // Confirm pro plugin is installed.
854 + if ( ! file_exists( WP_PLUGIN_DIR . '/charitable-pro/charitable.php' ) ) {
855 + return;
856 + }
857 +
858 + // Activate the pro plugin.
859 + activate_plugin( 'charitable-pro/charitable.php' );
860 +
861 + // Redirect to the settings page.
862 + wp_safe_redirect( admin_url( 'admin.php?page=charitable-settings&tab=general&valid=valid' ) );
863 + exit;
206 864 }
207 865 }
208 866
209 867 endif;