PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.1.10
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.1.10
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 1.8.0 All 210 releases
charitable / charitable.php

charitable.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.1.10, at charitable.php

1,291 lines 36.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Charitable
4 * Plugin URI: https://www.wpcharitable.com
5 * Description: The WordPress fundraising alternative for non-profits, created to help non-profits raise money on their own website.
6 * Version: 1.8.1.10
7 * Author: Charitable Donations & Fundraising Team
8 * Author URI: https://wpcharitable.com
9 * Requires at least: 4.1
10 * Tested up to: 6.6.1
11 * Stable tag: 1.8.1.10
12 *
13 * Text Domain: charitable
14 * Domain Path: /i18n/languages/
15 *
16 * @package Charitable
17 * @author David Bisset
18 * @copyright Copyright (c) 2023, WP Charitable LLC
19 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
20 */
21
22 // Exit if accessed directly.
23 if ( ! defined( 'ABSPATH' ) ) {
24 exit;
25 }
26
27 if ( ! class_exists( 'Charitable' ) ) :
28
29 /**
30 * Main Charitable class.
31 */
32 class Charitable {
33
34 /** The product name. */
35 const NAME = 'Charitable';
36
37 /** The plugin author name. */
38 const AUTHOR = 'WP Charitable';
39
40 /* Plugin version. */
41 const VERSION = '1.8.1.10';
42
43 /* Version of database schema. */
44 const DB_VERSION = '20180522';
45
46 /* Campaign post type. */
47 const CAMPAIGN_POST_TYPE = 'campaign';
48
49 /* Donation post type. */
50 const DONATION_POST_TYPE = 'donation';
51
52 /**
53 * Single instance of this class.
54 *
55 * @since 1.0.0
56 *
57 * @var Charitable
58 */
59 private static $instance = null;
60
61 /**
62 * The absolute path to this plugin's directory.
63 *
64 * @since 1.0.0
65 *
66 * @var string
67 */
68 private $directory_path;
69
70 /**
71 * The URL of this plugin's directory.
72 *
73 * @since 1.0.0
74 *
75 * @var string
76 */
77 private $directory_url;
78
79 /**
80 * Directory path for the includes folder of the plugin.
81 *
82 * @since 1.0.0
83 *
84 * @var string
85 */
86 private $includes_path;
87
88 /**
89 * Store of registered objects.
90 *
91 * @since 1.0.0
92 * @since 1.5.0 Changed to Charitable_Registry object. Previously it was an array.
93 *
94 * @var Charitable_Registry
95 */
96 private $registry;
97
98 /**
99 * Classmap.
100 *
101 * @since 1.5.0
102 *
103 * @var array
104 */
105 private $classmap;
106
107 /**
108 * Plugin.
109 *
110 * @since 1.8.0
111 *
112 * @var array
113 */
114 private $plugin;
115
116 /**
117 * Create class instance.
118 *
119 * @since 1.0.0
120 */
121 public function __construct() {
122 $this->directory_path = plugin_dir_path( __FILE__ );
123 $this->directory_url = plugin_dir_url( __FILE__ );
124 $this->includes_path = $this->directory_path . 'includes/';
125
126 define( 'CHARTIABLE_DIRECTORY_PATH', plugin_dir_path( __FILE__ ) );
127 define( 'CHARTIABLE_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
128 define( 'CHARTIABLE_MARKETING_URL', 'https://wpcharitable.com/' );
129
130 define( 'CHARITABLE_BUILDER_SHOW_LEGACY_EDIT_LINKS', true ); // 1.8.0 specific.
131
132 spl_autoload_register( array( $this, 'autoloader' ) );
133
134 $this->load_dependencies();
135
136 register_activation_hook( __FILE__, array( $this, 'activate' ) );
137 register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
138
139 add_filter( 'plugin_action_links_' . CHARTIABLE_PLUGIN_BASENAME, array( $this, 'plugin_action_links' ), 99, 2 );
140 add_action( 'plugins_loaded', array( $this, 'start' ), 3 );
141
142 add_action( 'plugins_loaded', array( $this, 'check_for_version_conflicts' ), 2 );
143 }
144
145 /**
146 * Returns the original instance of this class.
147 *
148 * @since 1.0.0
149 *
150 * @return Charitable
151 */
152 public static function get_instance() {
153 return self::$instance;
154 }
155
156 /**
157 * Run the startup sequence.
158 *
159 * This is only ever executed once.
160 *
161 * @since 1.0.0
162 *
163 * @return void
164 */
165 public function start() {
166 /* If we've already started (i.e. run this function once before), do not pass go. */
167 if ( $this->started() ) {
168 return;
169 }
170
171 /* Set static instance. */
172 self::$instance = $this;
173
174 /* Set up the registry and instantiate objects we need straight away. */
175 $this->registry();
176
177 $this->setup_licensing();
178
179 $this->maybe_start_ajax();
180
181 $this->attach_hooks_and_filters();
182
183 $this->maybe_start_admin();
184
185 $this->maybe_start_public();
186
187 Charitable_Addons::load( $this );
188 }
189
190 /**
191 * Include necessary files.
192 *
193 * @since 1.0.0
194 *
195 * @return void
196 */
197 private function load_dependencies() {
198 $includes_path = $this->get_path( 'includes' );
199
200 /* Load files with hooks & functions. Classes are autoloaded. */
201 require_once $includes_path . 'charitable-core-functions.php';
202 require_once $includes_path . 'api/charitable-api-functions.php';
203 require_once $includes_path . 'campaigns/charitable-campaign-functions.php';
204 require_once $includes_path . 'campaigns/charitable-campaign-hooks.php';
205 require_once $includes_path . 'compat/charitable-compat-functions.php';
206 require_once $includes_path . 'currency/charitable-currency-functions.php';
207 require_once $includes_path . 'deprecated/charitable-deprecated-functions.php';
208 require_once $includes_path . 'donations/charitable-donation-hooks.php';
209 require_once $includes_path . 'donations/charitable-donation-functions.php';
210 require_once $includes_path . 'emails/charitable-email-hooks.php';
211 require_once $includes_path . 'endpoints/charitable-endpoints-functions.php';
212 require_once $includes_path . 'privacy/charitable-privacy-functions.php';
213 require_once $includes_path . 'public/charitable-template-helpers.php';
214 require_once $includes_path . 'shortcodes/charitable-shortcodes-hooks.php';
215 require_once $includes_path . 'upgrades/charitable-upgrade-hooks.php';
216 require_once $includes_path . 'users/charitable-user-functions.php';
217 require_once $includes_path . 'user-management/charitable-user-management-hooks.php';
218 require_once $includes_path . 'utilities/charitable-utility-functions.php';
219
220 /* Load Stripe SDK */
221 require_once $this->get_path( 'directory' ) . 'vendor/autoload.php'; // todo: move to load_dependencies()?
222
223 if ( $this->load_core_stripe() ) :
224
225 /* Load Stripe SDK */
226 require_once $this->get_path( 'directory' ) . 'vendor/autoload.php';
227
228 /* Interfaces */
229 require_once $includes_path . 'stripe/interfaces/interface-charitable-stripe-gateway-processor.php';
230
231 /* Abstract classes */
232 require_once $includes_path . 'stripe/abstracts/class-charitable-stripe-gateway-processor.php';
233
234 /* Classes */
235 require_once $includes_path . 'stripe/donations/class-charitable-stripe-donation-log.php';
236 require_once $includes_path . 'stripe/donations/class-charitable-stripe-recurring-donation-log.php';
237 require_once $includes_path . 'stripe/i18n/class-charitable-stripe-i18n.php';
238 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-connected-customer.php';
239 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-customer.php';
240 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-gateway-processor-payment-intents.php';
241 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-payment-intent.php';
242 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-plan.php';
243 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-product.php';
244
245 require_once $includes_path . 'stripe/connect/charitable-stripe-connect-functions.php';
246 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-gateway-processor-checkout.php';
247
248 /* Functions & Hooks */
249 require_once $includes_path . 'stripe/charitable-stripe-core-functions.php';
250 require_once $includes_path . 'stripe/donations/charitable-stripe-donation-functions.php';
251 require_once $includes_path . 'stripe/gateway/charitable-stripe-gateway-hooks.php';
252
253 /* webhooks */
254 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-webhook-api.php';
255 require_once $includes_path . 'stripe/gateway/class-charitable-stripe-webhook-processor.php';
256
257 endif;
258 }
259
260 /**
261 * Load the template functions after theme is loaded.
262 *
263 * This gives themes time to override the functions.
264 *
265 * @since 1.6.10
266 *
267 * @return void
268 */
269 public function load_template_files() {
270 $includes_path = $this->get_path( 'includes' );
271
272 require_once $includes_path . 'public/charitable-template-functions.php';
273 require_once $includes_path . 'public/charitable-template-hooks.php';
274 }
275
276 /**
277 * Dynamically loads the class attempting to be instantiated elsewhere in the
278 * plugin by looking at the $class_name parameter being passed as an argument.
279 *
280 * @since 1.5.0
281 *
282 * @param string $class_name The fully-qualified name of the class to load.
283 * @return boolean
284 */
285 public function autoloader( $class_name ) {
286 /* If the specified $class_name already exists, bail. */
287 if ( class_exists( $class_name ) ) {
288 return false;
289 }
290
291 /* If the specified $class_name does not include our namespace, duck out. */
292 if ( false === strpos( $class_name, 'Charitable_' ) ) {
293 return false;
294 }
295
296 /* Autogenerated class map. */
297 if ( ! isset( $this->classmap ) ) {
298 $this->classmap = include 'includes/autoloader/charitable-class-map.php';
299
300 $this->classmap['Charitable_Gateway_Stripe_AM'] = 'gateways/class-charitable-gateway-stripe-am.php';
301 $this->classmap['Charitable_Gateway_Stripe'] = 'gateways/class-charitable-gateway-stripe-am.php';
302 }
303
304 $file_path = isset( $this->classmap[ $class_name ] ) ? $this->get_path( 'includes' ) . $this->classmap[ $class_name ] : false;
305
306 if ( false !== $file_path && file_exists( $file_path ) && is_file( $file_path ) ) {
307 require_once $file_path;
308 return true;
309 }
310 return false;
311 }
312
313 /**
314 * Returns a registered class object.
315 *
316 * @since 1.5.0
317 *
318 * @return Charitable_Registry
319 */
320 public function registry() {
321 if ( ! isset( $this->registry ) ) {
322 $this->registry = new Charitable_Registry();
323 $this->registry->register_object( Charitable_Emails::get_instance() );
324 $this->registry->register_object( Charitable_Request::get_instance() );
325 $this->registry->register_object( Charitable_Gateways::get_instance() );
326 $this->registry->register_object( Charitable_i18n::get_instance() );
327 $this->registry->register_object( Charitable_Post_Types::get_instance() );
328 $this->registry->register_object( Charitable_Cron::get_instance() );
329 $this->registry->register_object( Charitable_Widgets::get_instance() );
330 $this->registry->register_object( Charitable_Licenses::get_instance() );
331 $this->registry->register_object( Charitable_User_Dashboard::get_instance() );
332 $this->registry->register_object( Charitable_Locations::get_instance() );
333 $this->registry->register_object( Charitable_Currency::get_instance() );
334 $this->registry->register_object( Charitable_Notifications::get_instance() );
335
336 $this->registry->register_object( new Charitable_Privacy() );
337 $this->registry->register_object( new Charitable_Debugging() );
338 $this->registry->register_object( new Charitable_Locale() );
339 }
340
341 return $this->registry;
342 }
343
344 /**
345 * Set up hook and filter callback functions.
346 *
347 * @since 1.0.0
348 *
349 * @return void
350 */
351 private function attach_hooks_and_filters() {
352 add_action( 'wpmu_new_blog', array( $this, 'maybe_activate_charitable_on_new_site' ) );
353 add_action( 'plugins_loaded', array( $this, 'charitable_install' ), 100 );
354 add_action( 'plugins_loaded', array( $this, 'charitable_start' ), 100 );
355 add_action( 'plugins_loaded', array( $this, 'endpoints' ), 100 );
356 add_action( 'plugins_loaded', array( $this, 'donation_fields' ), 100 );
357 add_action( 'plugins_loaded', array( $this, 'campaign_fields' ), 100 );
358 add_action( 'plugins_loaded', array( $this, 'register_donormeta_table' ) );
359 add_action( 'plugins_loaded', 'charitable_load_compat_functions' );
360 add_action( 'setup_theme', array( 'Charitable_Customizer', 'start' ) );
361 add_action( 'after_setup_theme', array( $this, 'load_template_files' ) );
362 add_action( 'wp_enqueue_scripts', array( $this, 'maybe_start_qunit' ), 100 );
363 add_action( 'rest_api_init', 'charitable_register_api_routes' );
364
365 /**
366 * We do this on priority 20 so that any functionality that is loaded on init (such
367 * as addons) has a chance to run before the event.
368 */
369 add_action( 'init', array( $this, 'do_charitable_actions' ), 20 );
370
371 if ( $this->load_core_stripe() ) :
372
373 /**
374 * Set up scripts & stylesheets & enqueue them when appropriate.
375 */
376 add_action( 'charitable_form_after_fields', array( $this, 'maybe_setup_stripe_scripts_in_donation_form' ) );
377 add_action( 'charitable_campaign_loop_after', array( $this, 'maybe_setup_stripe_scripts_in_campaign_loop' ) );
378
379 endif;
380 }
381
382
383 /**
384 * Load Stripe JS, as well as our handling scripts.
385 *
386 * @since 1.4.0
387 *
388 * @return boolean
389 */
390 public function enqueue_stripe_scripts() {
391 if ( ! Charitable_Gateways::get_instance()->is_active_gateway( Charitable_Gateway_Stripe_AM::get_gateway_id() ) ) {
392 return false;
393 }
394
395 wp_enqueue_script( 'charitable-stripe' );
396
397 return true;
398 }
399
400 /**
401 * Load Stripe JS or Stripe Checkout, as well as our handling script.
402 *
403 * @uses Charitable_Stripe::enqueue_scripts()
404 *
405 * @since 1.4.0
406 *
407 * @param Charitable_Donation_Form $form The current form object.
408 * @return boolean
409 */
410 public function maybe_setup_stripe_scripts_in_donation_form( $form ) {
411 if ( ! is_a( $form, 'Charitable_Donation_Form' ) ) {
412 return false;
413 }
414
415 if ( 'make_donation' !== $form->get_form_action() ) {
416 return false;
417 }
418
419 return $this->enqueue_stripe_scripts();
420 }
421
422 /**
423 * Enqueue the Stripe JS/Checkout scripts after a campaign loop if modal donations are in use.
424 *
425 * @uses Charitable_Stripe::enqueue_scripts()
426 *
427 * @since 1.4.0
428 *
429 * @return boolean
430 */
431 public function maybe_setup_stripe_scripts_in_campaign_loop() {
432 if ( 'modal' !== charitable_get_option( 'donation_form_display', 'separate_page' ) ) {
433 return false;
434 }
435
436 return $this->enqueue_stripe_scripts();
437 }
438
439 /**
440 * Checks whether we're in the admin area and if so, loads the admin-only functionality.
441 *
442 * @since 1.0.0
443 *
444 * @return Charitable_Admin|false
445 */
446 private function maybe_start_admin() {
447 if ( ! is_admin() ) {
448 return false;
449 }
450
451 // load blocks/Gutenberg related.
452 require_once $this->get_path( 'admin' ) . 'class-charitable-admin-blocks.php';
453
454 require_once $this->get_path( 'admin' ) . 'class-charitable-admin.php';
455 require_once $this->get_path( 'admin' ) . 'charitable-admin-hooks.php';
456
457 // load campaign builder.
458 require_once $this->get_path( 'admin' ) . 'campaign-builder/util.php';
459 require_once $this->get_path( 'admin' ) . 'campaign-builder/functions.php';
460 require_once $this->get_path( 'admin' ) . 'campaign-builder/ajax-actions.php';
461 require_once $this->get_path( 'admin' ) . 'campaign-builder/debug.php';
462 require_once $this->get_path( 'admin' ) . 'campaign-builder/access.php';
463 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-fields.php';
464 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-form-fields.php';
465
466 // misc.
467 require_once $this->get_path( 'admin' ) . 'class-charitable-admin-pointers.php';
468 require_once $this->get_path( 'admin' ) . 'plugins/charitable-admin-plugin-hooks.php';
469
470 $admin = Charitable_Admin::get_instance();
471 $this->registry->register_object( $admin );
472
473 // Stripe.
474 require_once $this->get_path( 'includes' ) . 'stripe/admin/class-charitable-stripe-admin.php';
475
476 new Charitable_Stripe_Admin();
477
478 return $admin;
479 }
480
481 /**
482 * Checks whether we're on the public-facing side and if so, loads the public-facing functionality.
483 *
484 * @since 1.0.0
485 *
486 * @return Charitable_Public|false
487 */
488 private function maybe_start_public() {
489 if ( is_admin() && ! $this->is_ajax() ) {
490 return false;
491 }
492
493 require_once $this->get_path( 'public' ) . 'class-charitable-public.php';
494
495 // Campaign Builder related (v1.8.0).
496 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-campaign-builder-preview.php';
497 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-fields.php';
498 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-form-fields.php';
499
500 // load blocks/Gutenberg related.
501 require_once $this->get_path( 'admin' ) . 'class-charitable-admin-blocks.php';
502
503 $public = Charitable_Public::get_instance();
504
505 $this->registry->register_object( $public );
506
507 return $public;
508 }
509
510 /**
511 * Load the QUnit tests if ?qunit is appended to the request.
512 *
513 * @since 1.4.17
514 *
515 * @return boolean
516 */
517 public function maybe_start_qunit() {
518 /* Skip out early if ?qunit isn't included in the request. */
519 if ( ! array_key_exists( 'qunit', $_GET ) ) {
520 return false;
521 }
522
523 /* The unit tests have to exist. */
524 if ( ! file_exists( $this->get_path( 'directory' ) . 'tests/qunit/tests.js' ) ) {
525 return false;
526 }
527
528 wp_register_script( 'qunit', 'https://code.jquery.com/qunit/qunit-2.3.3.js', array(), '2.3.3', true );
529
530 /* Version: '20170615-15:44' */
531 wp_register_script( 'qunit-tests', $this->get_path( 'directory', false ) . 'tests/qunit/tests.js', array( 'jquery', 'qunit' ), time(), true );
532 wp_enqueue_script( 'qunit-tests' );
533
534 wp_register_style( 'qunit', 'https://code.jquery.com/qunit/qunit-2.3.3.css', array(), '2.3.3', 'all' );
535 wp_enqueue_style( 'qunit' );
536 }
537
538 /**
539 * Checks whether the current request is an AJAX request.
540 *
541 * @since 1.5.0
542 *
543 * @return boolean
544 */
545 private function is_ajax() {
546 return false !== ( defined( 'DOING_AJAX' ) && DOING_AJAX );
547 }
548
549 /**
550 * Checks whether we're executing an AJAX hook and if so, loads some AJAX functionality.
551 *
552 * @since 1.0.0
553 *
554 * @return void
555 */
556 private function maybe_start_ajax() {
557 if ( ! $this->is_ajax() ) {
558 return;
559 }
560
561 require_once $this->get_path( 'includes' ) . 'ajax/charitable-ajax-functions.php';
562 require_once $this->get_path( 'includes' ) . 'ajax/charitable-ajax-hooks.php';
563 }
564
565 /**
566 * This method is fired after all plugins are loaded and simply fires the charitable_start hook.
567 *
568 * Extensions can use the charitable_start event to load their own functionality.
569 *
570 * @since 1.0.0
571 *
572 * @return void
573 */
574 public function charitable_start() {
575 do_action( 'charitable_start', $this );
576 }
577
578 /**
579 * Fires off an action right after Charitable is installed, allowing other
580 * plugins/themes to do something at this point.
581 *
582 * @since 1.0.1
583 *
584 * @return void
585 */
586 public function charitable_install() {
587 $install = get_transient( 'charitable_install' );
588
589 if ( ! $install ) {
590 return;
591 }
592
593 require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-install.php';
594
595 Charitable_Install::finish_installing();
596
597 do_action( 'charitable_install' );
598
599 delete_transient( 'charitable_install' );
600
601 // Store the date when the initial activation was performed.
602 $type = function_exists( 'charitable_is_pro' ) && charitable_is_pro() ? 'pro' : 'lite';
603 $activated = get_option( 'charitable_activated', array() );
604 if ( empty( $activated[ $type ] ) ) {
605 $activated[ $type ] = time();
606 update_option( 'charitable_activated', $activated );
607 }
608 }
609
610 /**
611 * Returns whether we are currently in the start phase of the plugin.
612 *
613 * @since 1.0.0
614 *
615 * @return boolean
616 */
617 public function is_start() {
618 return current_filter() == 'charitable_start';
619 }
620
621 /**
622 * Returns whether the plugin has already started.
623 *
624 * @since 1.0.0
625 *
626 * @return boolean
627 */
628 public function started() {
629 return did_action( 'charitable_start' ) || current_filter() == 'charitable_start';
630 }
631
632 /**
633 * Returns whether the plugin is being activated.
634 *
635 * @since 1.0.0
636 *
637 * @return boolean
638 */
639 public function is_activation() {
640 return current_filter() == 'activate_charitable/charitable.php';
641 }
642
643 /**
644 * Returns whether the plugin is being deactivated.
645 *
646 * @since 1.0.0
647 *
648 * @return boolean
649 */
650 public function is_deactivation() {
651 return current_filter() == 'deactivate_charitable/charitable.php';
652 }
653
654 /**
655 * Returns plugin paths.
656 *
657 * @since 1.0.0
658 *
659 * @param string $type If empty, returns the path to the plugin.
660 * @param boolean $absolute_path If true, returns the file system path. If false, returns it as a URL.
661 * @return string
662 */
663 public function get_path( $type = '', $absolute_path = true ) {
664 $base = $absolute_path ? $this->directory_path : $this->directory_url;
665
666 switch ( $type ) {
667 case 'includes':
668 $path = $base . 'includes/';
669 break;
670
671 case 'admin':
672 $path = $base . 'includes/admin/';
673 break;
674
675 case 'public':
676 $path = $base . 'includes/public/';
677 break;
678
679 case 'assets':
680 $path = $base . 'assets/';
681 break;
682
683 case 'templates':
684 $path = $base . 'templates/';
685 break;
686
687 case 'plugin-directory':
688 $path = WP_PLUGIN_DIR;
689 break;
690
691 case 'directory':
692 $path = $base;
693 break;
694
695 default:
696 $path = __FILE__;
697
698 }//end switch
699
700 return $path;
701 }
702
703 /**
704 * Returns the plugin's version number.
705 *
706 * @since 1.0.0
707 *
708 * @return string
709 */
710 public function get_version() {
711 $version = self::VERSION;
712
713 if ( false !== strpos( $version, '-' ) ) {
714 $parts = explode( '-', $version );
715 $version = $parts[0];
716 }
717
718 return $version;
719 }
720
721 /**
722 * Get the campaign fields registry
723 *
724 * If the registry has not been set up yet, this will also
725 * perform the task of setting it up initially.
726 *
727 * This method is called on the plugins_loaded hook.
728 *
729 * @since 1.6.0
730 *
731 * @return Charitable_Campaign_Field_Registry
732 */
733 public function campaign_fields() {
734 if ( ! $this->registry->has( 'campaign_field_registry' ) ) {
735 $campaign_fields = new Charitable_Campaign_Field_Registry();
736
737 /* Register it immediately to avoid endless recursion. */
738 $this->registry->register_object( $campaign_fields );
739
740 $fields = include $this->get_path( 'includes' ) . 'fields/default-fields/campaign-fields.php';
741
742 foreach ( $fields as $key => $args ) {
743 $campaign_fields->register_field( new Charitable_Campaign_Field( $key, $args ) );
744 }
745 }
746
747 return $this->registry->get( 'campaign_field_registry' );
748 }
749
750 /**
751 * Get the donation fields registry
752 *
753 * If the registry has not been set up yet, this will also
754 * perform the task of setting it up initially.
755 *
756 * This method is called on the plugins_loaded hook.
757 *
758 * @since 1.5.0
759 *
760 * @return Charitable_Donation_Field_Registry
761 */
762 public function donation_fields() {
763 if ( ! $this->registry->has( 'donation_field_registry' ) ) {
764 $donation_fields = new Charitable_Donation_Field_Registry();
765
766 /* Register it immediately to avoid endless recursion. */
767 $this->registry->register_object( $donation_fields );
768
769 $fields = include $this->get_path( 'includes' ) . 'fields/default-fields/donation-fields.php';
770
771 foreach ( $fields as $key => $args ) {
772 $donation_fields->register_field( new Charitable_Donation_Field( $key, $args ) );
773 }
774 }
775
776 return $this->registry->get( 'donation_field_registry' );
777 }
778
779 /**
780 * Return the Endpoints API object.
781 *
782 * If the Endpoints API has not been set up yet, this will also
783 * perform the task of setting it up initially.
784 *
785 * This method is called on the plugins_loaded hook.
786 *
787 * @since 1.5.0
788 *
789 * @return Charitable_Endpoints
790 */
791 public function endpoints() {
792 if ( ! $this->registry->has( 'endpoints' ) ) {
793 /**
794 * The order in which we register endpoints is important, because
795 * it determines the order in which the endpoints are checked to
796 * find whether they are the current page.
797 *
798 * Any endpoint that builds on another endpoint should be registered
799 * BEFORE the endpoint it builds on. In other words, move from
800 * most specific to least specific.
801 */
802 $endpoints = new Charitable_Endpoints();
803 $endpoints->register( new Charitable_Campaign_Donation_Endpoint() );
804 $endpoints->register( new Charitable_Campaign_Widget_Endpoint() );
805 $endpoints->register( new Charitable_Campaign_Endpoint() );
806 $endpoints->register( new Charitable_Donation_Cancellation_Endpoint() );
807 $endpoints->register( new Charitable_Donation_Processing_Endpoint() );
808 $endpoints->register( new Charitable_Donation_Receipt_Endpoint() );
809 $endpoints->register( new Charitable_Email_Preview_Endpoint() );
810 $endpoints->register( new Charitable_Email_Verification_Endpoint() );
811 $endpoints->register( new Charitable_Forgot_Password_Endpoint() );
812 $endpoints->register( new Charitable_Reset_Password_Endpoint() );
813 $endpoints->register( new Charitable_Registration_Endpoint() );
814 $endpoints->register( new Charitable_Login_Endpoint() );
815 $endpoints->register( new Charitable_Profile_Endpoint() );
816 $endpoints->register( new Charitable_Webhook_Listener_Endpoint() );
817
818 $this->registry->register_object( $endpoints );
819 }
820
821 return $this->registry->get( 'endpoints' );
822 }
823
824 /**
825 * Returns a registered object.
826 *
827 * @since 1.0.0
828 *
829 * @param string $class The type of class to be retrieved.
830 * @return object
831 */
832 public function get_registered_object( $class ) {
833 return $this->registry->get( $class );
834 }
835
836 /**
837 * Registers our donormeta table as a meta data table.
838 *
839 * @since 1.6.0
840 *
841 * @global WPDB $wpdb
842 * @return void
843 */
844 public function register_donormeta_table() {
845 global $wpdb;
846
847 $wpdb->donormeta = $wpdb->prefix . 'charitable_donormeta';
848 }
849
850 /**
851 * Returns the model for one of Charitable's database tables.
852 *
853 * @since 1.0.0
854 *
855 * @param string $table The database table to retrieve.
856 * @return Charitable_DB
857 */
858 public function get_db_table( $table ) {
859 $tables = $this->get_tables();
860
861 if ( ! isset( $tables[ $table ] ) ) {
862 charitable_get_deprecated()->doing_it_wrong(
863 __METHOD__,
864 sprintf( 'Invalid table %s passed', $table ),
865 '1.0.0'
866 );
867 return null;
868 }
869
870 return $this->registry->get( $tables[ $table ] );
871 }
872
873 /**
874 * Return the filtered list of registered tables.
875 *
876 * @since 1.0.0
877 *
878 * @return string[]
879 */
880 private function get_tables() {
881 /**
882 * Filter the array of available Charitable table classes.
883 *
884 * @since 1.0.0
885 * @version 1.8.1
886 *
887 * @param array $tables List of tables as a key=>value array.
888 */
889 return apply_filters(
890 'charitable_db_tables',
891 array(
892 'campaign_donations' => 'Charitable_Campaign_Donations_DB',
893 'donors' => 'Charitable_Donors_DB',
894 'donormeta' => 'Charitable_Donormeta_DB',
895 'donation_activities' => 'Charitable_Donation_Activities_DB',
896 'campaign_activities' => 'Charitable_Campaign_Activities_DB',
897 )
898 );
899 }
900
901 /**
902 * Maybe activate Charitable when a new site is added in a multisite network.
903 *
904 * @since 1.4.6
905 *
906 * @param int $blog_id The blog to activate Charitable on.
907 * @return void
908 */
909 public function maybe_activate_charitable_on_new_site( $blog_id ) {
910 if ( is_plugin_active_for_network( basename( $this->directory_path ) . '/charitable.php' ) ) {
911 switch_to_blog( $blog_id );
912 $this->activate( false );
913 restore_current_blog();
914 }
915 }
916
917 /**
918 * Runs on plugin activation.
919 *
920 * @see register_activation_hook
921 *
922 * @since 1.0.0
923 *
924 * @param boolean $network_wide Whether to enable the plugin for all sites in the network
925 * or just the current site. Multisite only. Default is false.
926 * @return void
927 */
928 public function activate( $network_wide = false ) {
929 require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-install.php';
930
931 if ( is_multisite() && $network_wide ) {
932 global $wpdb;
933
934 foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) {
935 switch_to_blog( $blog_id );
936 new Charitable_Install( $this->includes_path );
937 restore_current_blog();
938 }
939 } else {
940 new Charitable_Install( $this->includes_path );
941 }
942
943 // create or update the install date for future reference.
944 update_option( 'wpcharitable_activated_datetime', current_time( 'timestamp' ) );
945 }
946
947 /**
948 * Runs on plugin deactivation.
949 *
950 * @see register_deactivation_hook
951 *
952 * @since 1.0.0
953 *
954 * @return void
955 */
956 public function deactivate() {
957 require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-uninstall.php';
958 new Charitable_Uninstall();
959 }
960
961 /**
962 * If a charitable_action event is triggered, delegate the event using do_action.
963 *
964 * @since 1.0.0
965 *
966 * @return void
967 */
968 public function do_charitable_actions() {
969 if ( isset( $_REQUEST['charitable_action'] ) ) {
970
971 $action = esc_attr( $_REQUEST['charitable_action'] );
972
973 /**
974 * Handle Charitable action.
975 *
976 * @since 1.0.0
977 */
978 do_action( 'charitable_' . $action );
979 }
980 }
981
982 /**
983 * Throw error on object clone.
984 *
985 * This class is specifically designed to be instantiated once. You can retrieve the instance using charitable()
986 *
987 * @since 1.0.0
988 *
989 * @return void
990 */
991 public function __clone() {
992 charitable_get_deprecated()->doing_it_wrong(
993 __FUNCTION__,
994 __( 'Cloning this object is forbidden.', 'charitable' ),
995 '1.0.0'
996 );
997 }
998
999 /**
1000 * Disable unserializing of the class.
1001 *
1002 * @since 1.0.0
1003 *
1004 * @return void
1005 */
1006 public function __wakeup() {
1007 charitable_get_deprecated()->doing_it_wrong(
1008 __FUNCTION__,
1009 __( 'Unserializing instances of this class is forbidden.', 'charitable' ),
1010 '1.0.0'
1011 );
1012 }
1013
1014 /**
1015 * DEPRECATED METHODS
1016 */
1017
1018 /**
1019 * Load plugin compatibility files on plugins_loaded hook.
1020 *
1021 * @deprecated 1.8.0
1022 *
1023 * @since 1.4.18
1024 * @since 1.5.0 Deprecated.
1025 *
1026 * @return void
1027 */
1028 public function load_plugin_compat_files() {
1029 charitable_get_deprecated()->deprecated_function(
1030 __METHOD__,
1031 '1.5.0.',
1032 'charitable_load_compat_functions'
1033 );
1034
1035 charitable_load_compat_functions();
1036 }
1037
1038 /**
1039 * Stores an object in the plugin's registry.
1040 *
1041 * @deprecated 1.8.0
1042 *
1043 * @since 1.0.0
1044 * @since 1.5.0 Deprecated.
1045 *
1046 * @param mixed $object Object to be registered.
1047 * @return void
1048 */
1049 public function register_object( $object ) {
1050 charitable_get_deprecated()->deprecated_function(
1051 __METHOD__,
1052 '1.5.0',
1053 'charitable()->registry()->register_object()'
1054 );
1055
1056 $this->registry->register_object( $object );
1057 }
1058
1059 /**
1060 * Returns the public class.
1061 *
1062 * @deprecated 1.8.0
1063 *
1064 * @since 1.0.0
1065 * @since 1.5.0 Deprecated.
1066 *
1067 * @return Charitable_Public
1068 */
1069 public function get_public() {
1070 charitable_get_deprecated()->deprecated_function(
1071 __METHOD__,
1072 '1.5.0',
1073 'charitable_get_helper'
1074 );
1075
1076 return $this->registry->get( 'Charitable_Public' );
1077 }
1078
1079 /**
1080 * Returns the admin class.
1081 *
1082 * @deprecated 1.8.0
1083 *
1084 * @since 1.0.0
1085 * @since 1.5.0 Deprecated.
1086 *
1087 * @return Charitable_Admin
1088 */
1089 public function get_admin() {
1090 charitable_get_deprecated()->deprecated_function(
1091 __METHOD__,
1092 '1.5.0',
1093 'charitable_get_helper'
1094 );
1095
1096 return $this->registry->get( 'Charitable_Admin' );
1097 }
1098
1099 /**
1100 * Return the current request object.
1101 *
1102 * @deprecated 1.8.0
1103 *
1104 * @since 1.0.0
1105 * @since 1.5.0 Deprecated.
1106 *
1107 * @return Charitable_Request
1108 */
1109 public function get_request() {
1110 charitable_get_deprecated()->deprecated_function(
1111 __METHOD__,
1112 '1.5.0',
1113 'charitable_get_helper'
1114 );
1115
1116 return $this->registry->get( 'Charitable_Request' );
1117 }
1118
1119 /**
1120 * Returns the instance of Charitable_Currency.
1121 *
1122 * @deprecated 1.7.0
1123 *
1124 * @since 1.4.0 Deprecated.
1125 */
1126 public function get_currency_helper() {
1127 charitable_get_deprecated()->deprecated_function( __METHOD__, '1.4.0', 'charitable_get_currency_helper' );
1128 return charitable_get_currency_helper();
1129 }
1130
1131 /**
1132 * Returns the instance of Charitable_Locations.
1133 *
1134 * @deprecated 1.6.0
1135 *
1136 * @since 1.2.0 Deprecated.
1137 */
1138 public function get_location_helper() {
1139 charitable_get_deprecated()->deprecated_function( __METHOD__, '1.2.0', 'charitable_get_location_helper' );
1140 return charitable_get_location_helper();
1141 }
1142
1143 /**
1144 * Determine if we use Stripe core files or use an addon if that's installed and active. Checks for USE_NEW_STRIPE first.
1145 *
1146 * @since 1.7.0
1147 *
1148 * @return boolean
1149 */
1150 public function load_core_stripe() {
1151
1152 if ( false !== ( defined( 'USE_NEW_STRIPE' ) && USE_NEW_STRIPE ) ) {
1153 return true;
1154 }
1155
1156 // check and see if the core Stripe AM gateway is an active gateway, and if it is not, don't load the core stripe JS, etc.
1157 if ( class_exists( 'Charitable_Gateways' ) && class_exists( 'Charitable_Gateway_Stripe_AM' ) && ! Charitable_Gateways::get_instance()->is_active_gateway( Charitable_Gateway_Stripe_AM::get_gateway_id() ) ) {
1158 return false;
1159 }
1160
1161 return true;
1162 }
1163
1164 /**
1165 * Determine Stripe Connect is active.
1166 *
1167 * @since 1.7.0
1168 *
1169 * @return boolean
1170 */
1171 public function is_stripe_connect_addon() {
1172
1173 if ( in_array( 'charitable-stripe/charitable-stripe.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
1174 return true;
1175 }
1176
1177 return false;
1178 }
1179
1180 /**
1181 * Action links for the plugins page.
1182 *
1183 * @since 1.7.0
1184 *
1185 * @param array $actions An array of existing actions.
1186 * @param string $plugin_file The plugin file we are modifying.
1187 * @return array An array of action links.
1188 */
1189 public function plugin_action_links( $actions, $plugin_file, $action_links = false ) {
1190
1191 if ( ! charitable_is_pro() ) :
1192
1193 // if this isn't pro, add the upgrade link which is visible on the plugins page until the plugin name.
1194
1195 $action_links = [
1196 'proupgrade' => [
1197 // Translators: This is an action link users can click to purchase a license for All in One SEO Pro.
1198 'label' => __( 'Upgrade to Pro', 'charitable' ),
1199 'url' => 'https://wpcharitable.com/lite-vs-pro/?utm_source=WordPress&utm_campaign=WP+Charitable&utm_medium=Action+Link+Plugins+Page&utm_content=Upgrade+to+Pro',
1200 ],
1201 ];
1202
1203 endif;
1204
1205 if ( isset( $actions['edit'] ) ) {
1206 unset( $actions['edit'] );
1207 }
1208
1209 return $this->parse_action_links( $actions, $plugin_file, $action_links, 'before' );
1210 }
1211
1212 /**
1213 * Parse the action links.
1214 *
1215 * @since 1.7.0
1216 *
1217 * @param array $actions
1218 * @param string $pluginFile
1219 * @param
1220 * @return array
1221 */
1222 protected function parse_action_links( $actions, $pluginFile, $action_links = [], $position = 'after' ) {
1223 if ( empty( $this->plugin ) ) {
1224 $this->plugin = CHARTIABLE_PLUGIN_BASENAME;
1225 }
1226
1227 if ( $this->plugin === $pluginFile && ! empty( $action_links ) ) {
1228 foreach ( $action_links as $key => $value ) {
1229 $link = [
1230 $key => '<a href="' . $value['url'] . '">' . $value['label'] . '</a>',
1231 ];
1232
1233 $actions = 'after' === $position ? array_merge( $actions, $link ) : array_merge( $link, $actions );
1234 }
1235 }
1236
1237 return $actions;
1238 }
1239
1240 /**
1241 * Set up licensing for pro.
1242 *
1243 * @since 1.7.0
1244 *
1245 * @return void
1246 */
1247 public function setup_licensing() {
1248 charitable_get_helper( 'licenses' )->register_licensed_product(
1249 self::NAME, // . ' Pro',
1250 self::AUTHOR,
1251 self::VERSION,
1252 __FILE__
1253 );
1254 }
1255
1256 /**
1257 * Deativates and/or warnings about any Charitable verison conflicts.
1258 *
1259 * @since 1.7.0
1260 */
1261 public function check_for_version_conflicts() {
1262
1263 // Check for Charitable Stripe < 1.5.0.
1264 if ( in_array( 'charitable-stripe/charitable-stripe.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
1265 if ( class_exists( 'Charitable_Stripe' ) && version_compare( Charitable_Stripe::VERSION, '1.5.0', '<' ) ) {
1266 // manually deactivate plugin.
1267 $found = false;
1268 $current = get_option( 'active_plugins', array() );
1269 $key = array_search( 'charitable-stripe/charitable-stripe.php', $current, true );
1270 if ( false !== $key ) {
1271 $found = true;
1272
1273 unset( $current[ $key ] );
1274 update_option( 'active_plugins', $current );
1275
1276 $message = __( '<p><strong style="color:red;">NOTICE:</strong> <strong>Charitable</strong> detected an out-of-date and incompatible version of <strong>Charitable Stripe</strong> addon. To avoid issues with Stripe donations, <strong>Charitable Stripe</strong> ' . Charitable_Stripe::VERSION . ' was deactivated. Please update <strong>Charitable Stripe</strong> to version 1.5.0 or higher.</p><p>You can get the latest version of <strong>Charitable Stripe</strong> through your <a href="https://www.wpcharitable.com/account/" target="_blank">Charitable account at wpcharitable.com</a>. All active licenses are accessible in the "My Downloads" tab.</p>', 'charitable-stripe' );
1277
1278 wp_die( $message . ' <a href="' . admin_url( 'plugins.php' ) . '">Click here to return to the plugins screen.</a>' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1279 }
1280 add_option( 'chartiable_version_warning', $message );
1281 } else {
1282 delete_option( 'chartiable_version_warning' );
1283 }
1284 }
1285 }
1286 }
1287
1288 $charitable = new Charitable();
1289
1290 endif;
1291