PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.4.7
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.4.7
1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 1.8.0 All 210 releases
charitable / charitable.php

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

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