PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.11.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.11.3
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
charitable / includes / admin / splash / class-charitable-admin-splash.php

class-charitable-admin-splash.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.11.3, at includes/admin/splash/class-charitable-admin-splash.php

925 lines 29.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Charitable Admin Splash.
4 *
5 * @package Charitable/Classes/Charitable_Admin_Splash
6 * @author David Bisset
7 * @copyright Copyright (c) 2023, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.8.6
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 if ( ! class_exists( 'Charitable_Admin_Splash' ) ) :
18
19 /**
20 * Charitable_Advanced_Settings
21 *
22 * @final
23 * @since 1.8.6
24 */
25 final class Charitable_Admin_Splash {
26
27 /**
28 * The single instance of this class.
29 *
30 * @var Charitable_Admin_Splash|null
31 */
32 private static $instance = null;
33
34 /**
35 * Default plugin version.
36 *
37 * @since 1.8.6
38 *
39 * @var string
40 */
41 private $default_plugin_version = '1.8.6'; // The last version before the "What's New?" feature.
42
43 /**
44 * Previous plugin version.
45 *
46 * @since 1.8.6
47 *
48 * @var string
49 */
50 private $previous_plugin_version;
51
52 /**
53 * Latest splash version.
54 *
55 * @since 1.8.6
56 *
57 * @var string
58 */
59 private $latest_splash_version;
60
61 /**
62 * Splash data.
63 *
64 * @since 1.8.6
65 *
66 * @var array
67 */
68 private $splash_data = array();
69
70 /**
71 * Whether it is a new Charitable installation.
72 *
73 * @since 1.8.6
74 *
75 * @var bool
76 */
77 private $is_new_install;
78
79 /**
80 * Whether the splash link is added.
81 *
82 * @since 1.8.6
83 *
84 * @var bool
85 */
86 private $splash_link_added = false;
87
88 /**
89 * Create object instance.
90 *
91 * @since 1.8.6
92 */
93 private function __construct() {
94 }
95
96 /**
97 * Returns and/or create the single instance of this class.
98 *
99 * @since 1.8.6
100 *
101 * @return Charitable_Admin_Splash
102 */
103 public static function get_instance() {
104 if ( is_null( self::$instance ) ) {
105 self::$instance = new self();
106 }
107
108 return self::$instance;
109 }
110
111 /**
112 * Initialize splash data.
113 *
114 * @since 1.8.6
115 */
116 public function initialize_splash_data() {
117
118 if ( ! $this->is_allow_splash() ) {
119 return;
120 }
121
122 if ( empty( $this->splash_data ) ) {
123 $this->splash_data = $this->get_default_data();
124
125 // Add splash data to a transient.
126 set_transient( 'charitable_splash_data', $this->splash_data, 60 * 60 * 24 );
127
128 $version = $this->get_major_version( charitable()->get_version() );
129
130 $this->update_splash_data_version( $version );
131 }
132 }
133
134 /**
135 * Enqueue assets.
136 *
137 * @since 1.8.6
138 */
139 public function admin_enqueue_scripts() {
140
141 $min = charitable_get_min_suffix();
142
143 if ( ! wp_style_is( 'jquery-confirm', 'enqueued' ) ) {
144 wp_enqueue_style(
145 'jquery-confirm',
146 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.confirm/jquery-confirm.min.css',
147 null,
148 '3.3.4'
149 );
150 }
151
152 if ( ! wp_script_is( 'jquery-confirm', 'enqueued' ) ) {
153 wp_enqueue_script(
154 'jquery-confirm',
155 charitable()->get_path( 'directory', false ) . 'assets/lib/jquery.confirm/jquery-confirm.min.js',
156 array( 'jquery' ),
157 '3.3.4',
158 false
159 );
160 }
161
162 wp_register_script(
163 'charitable-admin-splash',
164 charitable()->get_path( 'assets', false ) . 'js/admin/charitable-admin-splash' . $min . '.js',
165 array( 'jquery', 'wp-util' ),
166 charitable()->get_version(),
167 true
168 );
169
170 wp_register_style(
171 'charitable-admin-splash',
172 charitable()->get_path( 'assets', false ) . 'css/admin/charitable-admin-splash' . $min . '.css',
173 array(),
174 charitable()->get_version()
175 );
176
177 wp_localize_script(
178 'charitable-admin-splash',
179 'charitable_admin_splash_data',
180 array(
181 'nonce' => wp_create_nonce( 'charitable_admin_splash_nonce' ),
182 'triggerForceOpen' => $this->should_open_splash(),
183 )
184 );
185 }
186
187 /**
188 * Render splash modal.
189 *
190 * @since 1.8.6
191 *
192 * @param array $data Splash modal data.
193 */
194 public function render_modal( array $data = array() ) { // phpcs:ignore
195
196 wp_enqueue_script( 'jquery-confirm' );
197 wp_enqueue_style( 'jquery-confirm' );
198
199 wp_enqueue_script( 'charitable-admin-splash' );
200 wp_enqueue_style( 'charitable-admin-splash' );
201
202 if ( $this->should_open_splash() ) {
203 $this->update_splash_version();
204 }
205
206 // Get splash data from a transient.
207 $this->splash_data = get_transient( 'charitable_splash_data' );
208
209 if ( empty( $this->splash_data ) ) {
210 $this->splash_data = $this->get_default_data();
211 }
212
213 // Always reflect the current plugin major version in the header, even if the transient is stale.
214 $this->splash_data['header']['version'] = $this->get_major_version( charitable()->get_version() );
215
216 $this->splash_data['sections'] = $this->retrieve_sections_for_user( $this->splash_data['sections'] ?? array() );
217
218 $template_location = '/admin/templates/splash/splash-modal';
219 $template_location = apply_filters( 'charitable_admin_splash_modal_template_location', $template_location );
220 echo charitable_render( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
221 $template_location,
222 array(
223 'data' => $this->splash_data,
224 ),
225 true
226 );
227 }
228
229 /**
230 * Retrieve sections for user.
231 *
232 * @since 1.8.6
233 *
234 * @param array $sections Sections.
235 * @return array Sections.
236 */
237 public function retrieve_sections_for_user( array $sections = array() ): array {
238
239 $sections = array(
240 // PayPal Commerce — headline feature, uses same self-hosted video as Pro.
241 array(
242 'new' => true,
243 'version' => '1.8.11',
244 'layout' => 'fifty-fifty',
245 'class' => 'no-order',
246 'title' => __( 'PayPal Commerce', 'charitable' ),
247 'content' => __( 'Accept donations through PayPal, Venmo, Pay Later, cards, Apple Pay, and Google Pay from a single integration. One-click Connect with PayPal setup, with support for one-time and recurring donations, saved payment methods, and refunds handled in the donation admin.', 'charitable' ),
248 'video' => array(
249 'url' => 'https://wpcharitable-space.nyc3.digitaloceanspaces.com/splash/1-8-15/paypal-commerce.mp4',
250 ),
251 'buttons' => array(
252 'main' => array(
253 'text' => __( 'Get Started', 'charitable' ),
254 'url' => charitable_utm_link( 'https://www.wpcharitable.com/paypal-commerce-getting-started/', 'splash-modal', 'PayPal Commerce Main' ),
255 ),
256 'secondary' => array(
257 'text' => __( 'Learn More', 'charitable' ),
258 'url' => charitable_utm_link( 'https://www.wpcharitable.com/paypal-commerce-learn-more/', 'splash-modal', 'PayPal Commerce Secondary' ),
259 ),
260 ),
261 ),
262 // 1.8.10 — Lite headline feature: Migration & Import Tools.
263 array(
264 'new' => true,
265 'version' => '1.8.10',
266 'layout' => 'fifty-fifty',
267 'class' => 'no-order',
268 'title' => __( 'Migration & Import Tools', 'charitable' ),
269 'content' => __( 'Move from GiveWP or GiveButter to Charitable in minutes. Expanded import tools include CSV donations import and a new GiveWP Migration Tool (Beta) under a redesigned, tabbed interface.', 'charitable' ),
270 'img' => array(
271 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-10-import-tools.svg',
272 'shadow' => 'none',
273 ),
274 'buttons' => array(
275 'main' => array(
276 'text' => __( 'Get Started', 'charitable' ),
277 'url' => charitable_utm_link( 'https://www.wpcharitable.com/how-to-switch-from-givewp-to-charitable/', 'splash-modal', 'Import Tools Main' ),
278 ),
279 ),
280 ),
281 // 1.8.14 — Campaign Countdown (Pro-only).
282 array(
283 'new-for-pro' => true,
284 'layout' => 'fifty-fifty',
285 'class' => 'no-order',
286 'title' => __( 'Campaign Countdown', 'charitable' ),
287 'content' => __( 'Add a countdown timer to any campaign with the new Campaign Builder field or Gutenberg block. Fully customizable, with a built-in fireworks effect when the campaign ends.', 'charitable' ),
288 'img' => array(
289 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-14-campaign-countdown.png',
290 'shadow' => 'none',
291 ),
292 'buttons' => array(
293 'main' => array(
294 'text' => __( 'Get Started', 'charitable' ),
295 'url' => charitable_utm_link( 'https://www.wpcharitable.com/campaign-countdown-getting-started/', 'splash-modal', 'Campaign Countdown Main' ),
296 ),
297 'upgrade' => array(
298 'text' => __( 'Upgrade to Pro', 'charitable' ),
299 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Campaign Countdown Upgrade' ),
300 ),
301 ),
302 ),
303 // 1.8.9 — Lite security feature.
304 array(
305 'new' => true,
306 'version' => '1.8.9',
307 'layout' => 'fifty-fifty',
308 'class' => 'no-order',
309 'title' => __( 'Security Enhancements', 'charitable' ),
310 'content' => __( 'Charitable Lite now supports Google reCAPTCHA, hCaptcha, and Cloudflare Turnstile for improved security.', 'charitable' ),
311 'img' => array(
312 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-9-security.svg',
313 'shadow' => 'none',
314 ),
315 'buttons' => array(
316 'main' => array(
317 'text' => __( 'Get Started', 'charitable' ),
318 'url' => charitable_utm_link( 'https://www.wpcharitable.com/introducing-improved-security-and-clean-donation-tool/', 'splash-modal', 'Security Main' ),
319 ),
320 ),
321 ),
322 // 1.8.14 — Donorbox CSV Importer (Pro-only).
323 array(
324 'new-for-pro' => true,
325 'layout' => 'fifty-fifty',
326 'class' => 'no-order',
327 'title' => __( 'Donorbox CSV Importer', 'charitable' ),
328 'content' => __( 'Move from Donorbox to Charitable in a single CSV upload. Import historical donations, donors, campaigns, and recurring plans with preview, dry-run, and rollback.', 'charitable' ),
329 'img' => array(
330 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-14-donorbox-importer.png',
331 'shadow' => 'none',
332 ),
333 'buttons' => array(
334 'main' => array(
335 'text' => __( 'Get Started', 'charitable' ),
336 'url' => charitable_utm_link( 'https://www.wpcharitable.com/donorbox-csv-importer-getting-started/', 'splash-modal', 'Donorbox CSV Importer Main' ),
337 ),
338 'upgrade' => array(
339 'text' => __( 'Upgrade to Pro', 'charitable' ),
340 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Donorbox CSV Importer Upgrade' ),
341 ),
342 ),
343 ),
344 // 1.8.13 — Mini Donation Widget (Pro-only, Vimeo embed for Lite).
345 array(
346 'new-for-pro' => true,
347 'layout' => 'fifty-fifty',
348 'class' => 'no-order',
349 'title' => __( 'Mini Donation Widget', 'charitable' ),
350 'content' => __( 'Embed a compact donation form anywhere on your site, no page redirect required. Add it to sidebars, landing pages, or any widget area using a simple block or shortcode.', 'charitable' ),
351 'video' => array(
352 'vimeo_id' => '1186687749',
353 ),
354 'buttons' => array(
355 'main' => array(
356 'text' => __( 'Get Started', 'charitable' ),
357 'url' => charitable_utm_link( 'https://www.wpcharitable.com/documentation/mini-donation-widget/', 'splash-modal', 'Mini Donation Widget Main' ),
358 ),
359 'upgrade' => array(
360 'text' => __( 'Upgrade to Pro', 'charitable' ),
361 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Mini Donation Widget Upgrade' ),
362 ),
363 ),
364 ),
365 // Pro upsells.
366 array(
367 'new-for-pro' => true,
368 'layout' => 'fifty-fifty',
369 'class' => 'no-order',
370 'title' => __( 'Campaign Showcase', 'charitable' ),
371 'content' => __( 'Display all your campaigns beautifully with full layout control including grid, list, or masonry. No coding required.', 'charitable' ),
372 'img' => array(
373 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-13-campaign-showcase.png',
374 'shadow' => 'none',
375 ),
376 'buttons' => array(
377 'main' => array(
378 'text' => __( 'Get Started', 'charitable' ),
379 'url' => charitable_utm_link( 'https://www.wpcharitable.com/campaign-showcase-getting-started/', 'splash-modal', 'Campaign Showcase Main' ),
380 ),
381 'upgrade' => array(
382 'text' => __( 'Upgrade to Pro', 'charitable' ),
383 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Campaign Showcase Upgrade' ),
384 ),
385 ),
386 ),
387 array(
388 'new-for-pro' => true,
389 'layout' => 'fifty-fifty',
390 'class' => 'no-order',
391 'title' => __( 'Donations Feed', 'charitable' ),
392 'content' => __( 'Display recent donations in beautiful list or card views with sorting, filtering, pagination, and live polling that automatically refreshes when new donations arrive.', 'charitable' ),
393 'img' => array(
394 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-13-donate-feed.png',
395 'shadow' => 'none',
396 ),
397 'buttons' => array(
398 'main' => array(
399 'text' => __( 'Get Started', 'charitable' ),
400 'url' => charitable_utm_link( 'https://www.wpcharitable.com/donations-feed-getting-started/', 'splash-modal', 'Donations Feed Main' ),
401 ),
402 'upgrade' => array(
403 'text' => __( 'Upgrade to Pro', 'charitable' ),
404 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Donations Feed Upgrade' ),
405 ),
406 ),
407 ),
408 array(
409 'new-for-pro' => true,
410 'layout' => 'fifty-fifty',
411 'class' => 'no-order',
412 'title' => __( 'Campaign Modal Button', 'charitable' ),
413 'content' => __( 'Add a donate button anywhere on your site that opens a donation form in a modal popup, no page redirect required. Available as a block or shortcode.', 'charitable' ),
414 'img' => array(
415 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-13-modal-button.png',
416 'shadow' => 'none',
417 ),
418 'buttons' => array(
419 'main' => array(
420 'text' => __( 'Get Started', 'charitable' ),
421 'url' => charitable_utm_link( 'https://www.wpcharitable.com/campaign-modal-button-getting-started/', 'splash-modal', 'Campaign Modal Button Main' ),
422 ),
423 'upgrade' => array(
424 'text' => __( 'Upgrade to Pro', 'charitable' ),
425 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Campaign Modal Button Upgrade' ),
426 ),
427 ),
428 ),
429 array(
430 'new-for-pro' => true,
431 'layout' => 'fifty-fifty',
432 'class' => 'no-order',
433 'title' => __( 'Prefill Donation Forms', 'charitable' ),
434 'content' => __( 'Pre-populate donation form fields via URL query strings. Perfect for email campaigns, targeted landing pages, and personalized donor outreach.', 'charitable' ),
435 'img' => array(
436 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-13-prefill-forms.png',
437 'shadow' => 'none',
438 ),
439 'buttons' => array(
440 'main' => array(
441 'text' => __( 'Get Started', 'charitable' ),
442 'url' => charitable_utm_link( 'https://www.wpcharitable.com/prefill-donation-forms-getting-started/', 'splash-modal', 'Prefill Donation Forms Main' ),
443 ),
444 'upgrade' => array(
445 'text' => __( 'Upgrade to Pro', 'charitable' ),
446 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Prefill Donation Forms Upgrade' ),
447 ),
448 ),
449 ),
450 array(
451 'new-for-pro' => true,
452 'layout' => 'fifty-fifty',
453 'class' => 'no-order',
454 'title' => __( 'Campaign Featured Image', 'charitable' ),
455 'content' => __( 'Set your campaign\'s featured image directly from the Campaign Builder. No need to switch to the post editor. Perfect for giving your campaigns a polished, visual identity.', 'charitable' ),
456 'img' => array(
457 'url' => charitable()->get_path( 'assets', false ) . 'images/splash/1-8-13-featured-image.png',
458 'shadow' => 'none',
459 ),
460 'buttons' => array(
461 'main' => array(
462 'text' => __( 'Get Started', 'charitable' ),
463 'url' => charitable_utm_link( 'https://www.wpcharitable.com/campaign-featured-image-getting-started/', 'splash-modal', 'Campaign Featured Image Main' ),
464 ),
465 'upgrade' => array(
466 'text' => __( 'Upgrade to Pro', 'charitable' ),
467 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'Campaign Featured Image Upgrade' ),
468 ),
469 ),
470 ),
471 // Two-column "More Recent Features" list.
472 array(
473 'layout' => 'more-features',
474 'class' => 'no-order',
475 'title' => __( 'More Recent Features:', 'charitable' ),
476 'items' => array(
477 __( 'Campaign Selector', 'charitable' ),
478 __( 'Envira Gallery Integration', 'charitable' ),
479 __( 'Visual Form Builder', 'charitable' ),
480 __( 'Donor Leaderboards', 'charitable' ),
481 __( 'Magic Donor Dashboard Link', 'charitable' ),
482 __( 'DIVI Integration', 'charitable' ),
483 __( 'DonorTrust', 'charitable' ),
484 __( 'Google Analytics', 'charitable' ),
485 ),
486 ),
487 );
488
489 return $sections;
490 }
491
492 /**
493 * Check if splash data is empty.
494 *
495 * @since 1.8.6
496 *
497 * @return bool True if empty, false otherwise.
498 */
499 public function is_splash_empty(): bool {
500
501 if ( empty( $this->splash_data ) ) {
502 return true;
503 }
504
505 return empty( $this->retrieve_sections_for_user( $this->splash_data['sections'] ?? array() ) );
506 }
507
508 /**
509 * Output splash modal.
510 *
511 * @since 1.8.6
512 */
513 public function admin_footer() {
514 if ( ! $this->is_allow_splash() ) {
515 return;
516 }
517
518 $this->render_modal();
519 }
520
521 /**
522 * Get splash data version.
523 *
524 * @since 1.8.6
525 *
526 * @return string Splash data version.
527 */
528 private function get_splash_data_version(): string {
529
530 return get_option( 'charitable_splash_data_version', charitable()->get_version() );
531 }
532
533 /**
534 * Update splash data version.
535 *
536 * @since 1.8.6
537 *
538 * @param string $version Splash data version.
539 */
540 private function update_splash_data_version( string $version ) {
541
542 update_option( 'charitable_splash_data_version', $version );
543 }
544
545 /**
546 * Get the latest splash version.
547 *
548 * @since 1.8.6
549 *
550 * @return string Splash version.
551 */
552 private function get_latest_splash_version(): string {
553
554 if ( $this->latest_splash_version ) {
555 return $this->latest_splash_version;
556 }
557
558 $this->latest_splash_version = get_option( 'charitable_splash_version', '1.8.6' );
559
560 // Create option if it doesn't exist.
561 if ( empty( $this->latest_splash_version ) ) {
562 $this->latest_splash_version = $this->default_plugin_version;
563
564 update_option( 'charitable_splash_version', $this->latest_splash_version );
565 }
566
567 return $this->latest_splash_version;
568 }
569
570 /**
571 * Update option with the latest splash version.
572 *
573 * @since 1.8.6
574 */
575 private function update_splash_version() {
576
577 update_option( 'charitable_splash_version', $this->get_major_version( charitable()->get_version() ) );
578 }
579
580 /**
581 * Get a major version.
582 *
583 * @since 1.8.6
584 *
585 * @param string $version Version.
586 *
587 * @return string Major version.
588 */
589 private function get_major_version( $version ): string {
590
591 // Allow only digits and dots.
592 $clean_version = preg_replace( '/[^0-9.]/', '.', $version );
593
594 // Get version parts.
595 $version_parts = explode( '.', $clean_version );
596
597 // If a version has more than 3 parts - use only first 3. Get block data only for major versions.
598 if ( count( $version_parts ) > 3 ) {
599 $version = implode( '.', array_slice( $version_parts, 0, 3 ) );
600 }
601
602 return $version;
603 }
604
605 /**
606 * Get user license type.
607 *
608 * @since 1.8.6
609 *
610 * @return string
611 */
612 private function get_user_license(): string {
613
614 /**
615 * License type used for splash screen.
616 *
617 * @since 1.8.6
618 *
619 * @param string $license License type.
620 */
621 return (string) apply_filters( 'charitable_admin_splash_splashtrait_get_user_license', 'lite' );
622 }
623
624 /**
625 * Get default splash modal data.
626 *
627 * @since 1.8.6
628 *
629 * @return array Splash modal data.
630 */
631 private function get_default_data(): array {
632
633 $default_data = array(
634 'license' => $this->get_user_license(),
635 'buttons' => array(
636 'get_started' => __( 'Get Started', 'charitable' ),
637 'learn_more' => __( 'Learn More', 'charitable' ),
638 ),
639 'header' => array(
640 'image' => charitable()->get_path( 'assets', false ) . 'images/charitable-logo.svg',
641 'title' => __( 'What\'s New in Charitable', 'charitable' ),
642 'description' => __( 'Since you\'ve been gone, we\'ve added some great new features to help grow your campaigns and generate more donations. Here are some highlights...', 'charitable' ),
643 'version' => $this->get_major_version( charitable()->get_version() ),
644 ),
645
646 );
647
648 // If the chartiable_pro is active, that means they are licensed but not using Charitable Pro plugin.
649 if ( ! charitable_is_pro() ) :
650 $default_data['footer'] = array(
651 'title' => __( 'Add Your License To Activate Charitable Pro Plugin Now And Start Getting More Donations!', 'charitable' ),
652 'description' => __( 'Charitable Pro is a powerful upgrade that allows you to manage donors along with built-in features like videos, donor comments, PDF receipts, a dashboard for donors, and more.', 'charitable' ),
653 'upgrade' => array(
654 'text' => __( 'Learn More', 'charitable' ),
655 'url' => charitable_utm_link( 'https://www.wpcharitable.com/lite-upgrade/', 'splash-modal', 'learn-more' ),
656 ),
657 );
658 else :
659 $default_data['footer'] = array(
660 'title' => __( 'Upgrade To The Charitable Pro Plugin At No Cost!', 'charitable' ),
661 'description' => __( 'Registered users with active license can upgrade to Charitable Pro plugin at NO COST. It\'s included in all plans (basic, plus, pro, elite).', 'charitable' ),
662 'upgrade' => array(
663 'text' => __( 'Learn More', 'charitable' ),
664 'url' => charitable_utm_link( 'https://www.wpcharitable.com/pricing/upgrade-lite-to-pro/', 'splash-modal', 'learn-more' ),
665 ),
666 );
667 endif;
668
669 return $default_data;
670 }
671
672 /**
673 * Determine if the current update is a minor update.
674 *
675 * Checks the charitable_upgrade_log option for the latest upgrade entry
676 * and compares its version with the current version to determine if this is
677 * a minor update (same major version) or major update (different major version).
678 *
679 * @since 1.8.6
680 *
681 * @return bool True if it's a minor update, false otherwise.
682 */
683 private function is_minor_update(): bool {
684 $upgrade_log = get_option( 'charitable_upgrade_log', array() );
685
686 // If no upgrade log exists, this is not a minor update.
687 if ( empty( $upgrade_log ) ) {
688 return false;
689 }
690
691 // Get the latest upgrade entry.
692 $latest_entry = end( $upgrade_log );
693
694 // If no version in the latest entry, this is not a minor update.
695 if ( ! isset( $latest_entry['version'] ) ) {
696 return false;
697 }
698
699 $latest_version = $latest_entry['version'];
700 $current_version = charitable()->get_version();
701
702 // Get major versions (e.g., 1.8.5 from 1.8.5.1).
703 $latest_major = $this->get_major_version( $latest_version );
704 $current_major = $this->get_major_version( $current_version );
705
706 // If major versions match, this is a minor update.
707 return $latest_major === $current_major;
708 }
709
710 /**
711 * Check if splash modal is allowed.
712 * Only allow on Charitable dashboard or settings screens; never on onboarding/setup welcome.
713 *
714 * @since 1.8.6
715 *
716 * @return bool True if allowed, false otherwise.
717 */
718 public function is_allow_splash(): bool {
719
720 // Never show on onboarding/setup welcome flow (splash would sit on top of onboarding UI).
721 if ( $this->is_onboarding_setup_page() ) {
722 return false;
723 }
724
725 // Only show on Charitable pages OR dashboard.
726 return charitable_is_admin_screen() || $this->is_dashboard();
727 }
728
729 /**
730 * Check if current screen is the onboarding/setup welcome flow.
731 * Splash must not show here so it doesn't overlay the onboarding UI.
732 *
733 * @since 1.8.9.6
734 *
735 * @return bool True if on onboarding setup page, false otherwise.
736 */
737 private function is_onboarding_setup_page(): bool {
738
739 if ( ! is_admin() || empty( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
740 return false;
741 }
742
743 $page = sanitize_text_field( $_GET['page'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
744
745 // Block splash on the setup wizard, checklist, and any charitable-setup* pages.
746 if ( strpos( $page, 'charitable-setup' ) !== false ) {
747 return true;
748 }
749
750 // Block splash on the welcome/onboarding flow (page=charitable&wpchar_lite=lite&setup=...).
751 if ( 'charitable' !== $page ) {
752 return false;
753 }
754
755 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
756 if ( empty( $_GET['wpchar_lite'] ) || 'lite' !== $_GET['wpchar_lite'] ) {
757 return false;
758 }
759
760 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
761 if ( empty( $_GET['setup'] ) ) {
762 return false;
763 }
764
765 $setup = sanitize_key( $_GET['setup'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
766
767 return in_array( $setup, array( 'welcome', 'cancelled', 'return' ), true );
768 }
769
770 /**
771 * Check if splash modal should be opened.
772 *
773 * @since 1.8.6
774 *
775 * @return bool True if splash should open, false otherwise.
776 */
777 private function should_open_splash(): bool {
778
779 // Skip if announcements are hidden, or it is the dashboard page.
780 if ( $this->is_dashboard() || $this->hide_splash_modal() ) {
781 return false;
782 }
783
784 // If we are forcing the preview, then we should open the splash.
785 if ( $this->is_force_open() ) {
786 return true;
787 }
788
789 if ( ! $this->is_allow_splash() ) {
790 return false;
791 }
792
793 // Allow if a splash version different from the current plugin major version, and it's not a new installation.
794 if ( charitable_is_debug( 'splash' ) ) {
795 // phpcs:disable
796 error_log( 'Charitable Admin Splash: Latest splash version: ' . $this->get_latest_splash_version() );
797 error_log( 'Charitable Admin Splash: Current major version: ' . $this->get_major_version( charitable()->get_version() ) );
798 error_log( 'Charitable Admin Splash: Is new install: ' . ( $this->is_new_install() ? 'true' : 'false' ) );
799 error_log( 'Charitable Admin Splash: Is force open: ' . ( $this->is_force_open() ? 'true' : 'false' ) );
800 // phpcs:enable
801 }
802
803 $should_open_splash = $this->get_latest_splash_version() !== $this->get_major_version( charitable()->get_version() ) &&
804 ( ! $this->is_new_install() || $this->is_force_open() );
805
806 if ( ! $should_open_splash ) {
807 return false;
808 }
809
810 // Skip if user on the builder page and the Challenge can be started.
811 if ( $this->is_builder_page() ) {
812 return false;
813 }
814
815 return true;
816 }
817
818 /**
819 * Check if the current page is the builder page.
820 *
821 * @since 1.8.6
822 *
823 * @return bool True if it is the builder page, false otherwise.
824 */
825 private function is_builder_page(): bool {
826 return ! empty( $_GET['page'] ) && 'charitable-campaign-builder' === $_GET['page']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
827 }
828
829 /**
830 * Check if the current page is the dashboard.
831 *
832 * @since 1.8.6
833 *
834 * @return bool True if it is the dashboard, false otherwise.
835 */
836 private function is_dashboard(): bool {
837
838 global $pagenow;
839
840 if ( ! empty( $_GET['page'] ) && 'charitable-dashboard' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
841 return true;
842 }
843
844 return false;
845 }
846
847 /**
848 * Check if splash modal should be forced open.
849 *
850 * @since 1.8.6
851 *
852 * @return bool True if it should be forced open, false otherwise.
853 */
854 private function is_force_open(): bool {
855
856 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
857 return sanitize_key( $_GET['charitable_action'] ?? '' ) === 'preview-splash-screen';
858 }
859
860 /**
861 * Check if the plugin is newly installed.
862 *
863 * Checks the charitable_upgrade_log option for the initial installation entry
864 * and compares its version with the current version to determine if this is
865 * a new installation.
866 *
867 * @since 1.8.6
868 *
869 * @return bool True if new install, false otherwise.
870 */
871 private function is_new_install(): bool {
872 $upgrade_log = get_option( 'charitable_upgrade_log', array() );
873
874 // If no upgrade log exists, this is a new install.
875 if ( empty( $upgrade_log ) ) {
876 return true;
877 }
878
879 // Find the initial installation entry.
880 $install_entry = null;
881 foreach ( $upgrade_log as $entry ) {
882 if ( isset( $entry['message'] ) && 'Charitable was installed.' === $entry['message'] ) {
883 $install_entry = $entry;
884 break;
885 }
886 }
887
888 // If no installation entry found, this is a new install.
889 if ( ! $install_entry || ! isset( $install_entry['version'] ) ) {
890 return true;
891 }
892
893 $installed_version = $install_entry['version'];
894 $current_version = charitable()->get_version();
895
896 // Get major versions (e.g., 1.8.5 from 1.8.5.1).
897 $installed_major = $this->get_major_version( $installed_version );
898 $current_major = $this->get_major_version( $current_version );
899
900 // If major versions match and current version is not greater, this is a new install.
901 return $installed_major === $current_major && version_compare( $current_version, $installed_version, '<=' );
902 }
903
904 /**
905 * Check if splash modal should be hidden.
906 *
907 * @since 1.8.6
908 *
909 * @return bool True if hidden, false otherwise.
910 */
911 private function hide_splash_modal(): bool {
912
913 /**
914 * Force to hide splash modal.
915 *
916 * @since 1.8.6
917 *
918 * @param bool $hide_splash_modal True to hide, false otherwise.
919 */
920 return (bool) apply_filters( 'charitable_admin_splash_screen_hide_splash_modal', charitable_get_option( 'hide_announcements' ) );
921 }
922 }
923
924 endif;
925