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

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