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

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