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

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