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

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