PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.0.5
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.0.5
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.0.5, at charitable.php

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