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

1,332 lines 38.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 best WordPress donation plugin. Fundraising with recurring donations, and powerful features to help you raise more money online.
6 * Version: 1.8.5.1
7 * Author: Charitable Donations & Fundraising Team
8 * Author URI: https://wpcharitable.com
9 * Requires at least: 5.0
10 * Stable tag: 1.8.5.1
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.5.1';
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 // connect for upgrade.wpcharitable.com.
469 require_once $this->get_path( 'admin' ) . 'class-charitable-admin-connect.php';
470
471 // misc.
472 require_once $this->get_path( 'admin' ) . 'class-charitable-admin-pointers.php';
473 require_once $this->get_path( 'admin' ) . 'plugins/charitable-admin-plugin-hooks.php';
474 require_once $this->get_path( 'admin' ) . 'class-charitable-admin-getting-started.php';
475
476 $admin = Charitable_Admin::get_instance();
477 $this->registry->register_object( $admin );
478
479 // Stripe.
480 require_once $this->get_path( 'includes' ) . 'stripe/admin/class-charitable-stripe-admin.php';
481
482 new Charitable_Stripe_Admin();
483
484 return $admin;
485 }
486
487 /**
488 * Checks whether we're on the public-facing side and if so, loads the public-facing functionality.
489 *
490 * @since 1.0.0
491 *
492 * @return Charitable_Public|false
493 */
494 private function maybe_start_public() {
495 if ( is_admin() && ! $this->is_ajax() ) {
496 return false;
497 }
498
499 require_once $this->get_path( 'public' ) . 'class-charitable-public.php';
500
501 // Campaign Builder related (v1.8.0).
502 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-campaign-builder-preview.php';
503 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-fields.php';
504 require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-form-fields.php';
505
506 // load blocks/Gutenberg related.
507 require_once $this->get_path( 'admin' ) . 'class-charitable-admin-blocks.php';
508
509 $public = Charitable_Public::get_instance();
510
511 $this->registry->register_object( $public );
512
513 return $public;
514 }
515
516 /**
517 * Load the QUnit tests if ?qunit is appended to the request.
518 *
519 * @since 1.4.17
520 *
521 * @return boolean
522 */
523 public function maybe_start_qunit() {
524 /* Skip out early if ?qunit isn't included in the request. */
525 if ( ! array_key_exists( 'qunit', $_GET ) ) {
526 return false;
527 }
528
529 /* The unit tests have to exist. */
530 if ( ! file_exists( $this->get_path( 'directory' ) . 'tests/qunit/tests.js' ) ) {
531 return false;
532 }
533
534 wp_register_script( 'qunit', 'https://code.jquery.com/qunit/qunit-2.3.3.js', array(), '2.3.3', true );
535
536 /* Version: '20170615-15:44' */
537 wp_register_script( 'qunit-tests', $this->get_path( 'directory', false ) . 'tests/qunit/tests.js', array( 'jquery', 'qunit' ), time(), true );
538 wp_enqueue_script( 'qunit-tests' );
539
540 wp_register_style( 'qunit', 'https://code.jquery.com/qunit/qunit-2.3.3.css', array(), '2.3.3', 'all' );
541 wp_enqueue_style( 'qunit' );
542 }
543
544 /**
545 * Checks whether the current request is an AJAX request.
546 *
547 * @since 1.5.0
548 *
549 * @return boolean
550 */
551 private function is_ajax() {
552 return false !== ( defined( 'DOING_AJAX' ) && DOING_AJAX );
553 }
554
555 /**
556 * Checks whether we're executing an AJAX hook and if so, loads some AJAX functionality.
557 *
558 * @since 1.0.0
559 *
560 * @return void
561 */
562 private function maybe_start_ajax() {
563 if ( ! $this->is_ajax() ) {
564 return;
565 }
566
567 require_once $this->get_path( 'includes' ) . 'ajax/charitable-ajax-functions.php';
568 require_once $this->get_path( 'includes' ) . 'ajax/charitable-ajax-hooks.php';
569 }
570
571 /**
572 * This method is fired after all plugins are loaded and simply fires the charitable_start hook.
573 *
574 * Extensions can use the charitable_start event to load their own functionality.
575 *
576 * @since 1.0.0
577 *
578 * @return void
579 */
580 public function charitable_start() {
581 do_action( 'charitable_start', $this );
582 }
583
584 /**
585 * Fires off an action right after Charitable is installed, allowing other
586 * plugins/themes to do something at this point.
587 *
588 * @since 1.0.1
589 * @version 1.8.1.12 - Added transient for activation redirect.
590 * @version 1.8.3 - Added call to add version and delete notifications.
591 *
592 * @return void
593 */
594 public function charitable_install() {
595 $install = get_transient( 'charitable_install' );
596
597 if ( ! $install ) {
598 return;
599 }
600
601 require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-install.php';
602
603 Charitable_Install::finish_installing();
604
605 do_action( 'charitable_install' );
606
607 delete_transient( 'charitable_install' );
608
609 // Store the date when the initial activation was performed.
610 $type = function_exists( 'charitable_is_pro' ) && charitable_is_pro() ? 'pro' : 'lite';
611 $activated = (array) get_option( 'charitable_activated', array() );
612
613 // If no activation date is set, assume it's a new install and set the activation redirect transient.
614 if ( false === $activated || empty( $activated ) ) {
615 // Add transient to trigger redirect to the Welcome / Getting Started screen.
616 set_transient( 'charitable_activation_redirect', true, 30 );
617 }
618
619 $this->add_version_to_upgraded_from();
620
621 if ( empty( $activated[ $type ] ) ) {
622 $activated[ $type ] = time();
623 update_option( 'charitable_activated', $activated );
624 }
625
626 // Clear notifications.
627 delete_option( 'charitable_notifications' );
628 }
629
630 /**
631 * Returns whether we are currently in the start phase of the plugin.
632 *
633 * @since 1.0.0
634 *
635 * @return boolean
636 */
637 public function is_start() {
638 return current_filter() == 'charitable_start';
639 }
640
641 /**
642 * Returns whether the plugin has already started.
643 *
644 * @since 1.0.0
645 *
646 * @return boolean
647 */
648 public function started() {
649 return did_action( 'charitable_start' ) || current_filter() == 'charitable_start';
650 }
651
652 /**
653 * Returns whether the plugin is being activated.
654 *
655 * @since 1.0.0
656 *
657 * @return boolean
658 */
659 public function is_activation() {
660 return current_filter() == 'activate_charitable/charitable.php';
661 }
662
663 /**
664 * Returns whether the plugin is being deactivated.
665 *
666 * @since 1.0.0
667 *
668 * @return boolean
669 */
670 public function is_deactivation() {
671 return current_filter() == 'deactivate_charitable/charitable.php';
672 }
673
674 /**
675 * Returns plugin paths.
676 *
677 * @since 1.0.0
678 *
679 * @param string $type If empty, returns the path to the plugin.
680 * @param boolean $absolute_path If true, returns the file system path. If false, returns it as a URL.
681 * @return string
682 */
683 public function get_path( $type = '', $absolute_path = true ) {
684 $base = $absolute_path ? $this->directory_path : $this->directory_url;
685
686 switch ( $type ) {
687 case 'includes':
688 $path = $base . 'includes/';
689 break;
690
691 case 'admin':
692 $path = $base . 'includes/admin/';
693 break;
694
695 case 'public':
696 $path = $base . 'includes/public/';
697 break;
698
699 case 'assets':
700 $path = $base . 'assets/';
701 break;
702
703 case 'templates':
704 $path = $base . 'templates/';
705 break;
706
707 case 'plugin-directory':
708 $path = WP_PLUGIN_DIR;
709 break;
710
711 case 'directory':
712 $path = $base;
713 break;
714
715 default:
716 $path = __FILE__;
717
718 }//end switch
719
720 return $path;
721 }
722
723 /**
724 * Returns the plugin's version number.
725 *
726 * @since 1.0.0
727 *
728 * @return string
729 */
730 public function get_version() {
731 $version = self::VERSION;
732
733 if ( false !== strpos( $version, '-' ) ) {
734 $parts = explode( '-', $version );
735 $version = $parts[0];
736 }
737
738 return $version;
739 }
740
741 /**
742 * Adds previous versions to the upgraded_from option.
743 *
744 * @since 1.8.3
745 */
746 public function add_version_to_upgraded_from() {
747
748 $upgraded_from = get_option( 'charitable_version_upgraded_from', array() );
749
750 if ( ! is_array( $upgraded_from ) ) {
751 $upgraded_from = array();
752 }
753
754 $upgraded_from[] = $this->get_version();
755
756 update_option( 'charitable_version_upgraded_from', $upgraded_from, false );
757 }
758
759 /**
760 * Get the campaign fields registry
761 *
762 * If the registry has not been set up yet, this will also
763 * perform the task of setting it up initially.
764 *
765 * This method is called on the plugins_loaded hook.
766 *
767 * @since 1.6.0
768 *
769 * @return Charitable_Campaign_Field_Registry
770 */
771 public function campaign_fields() {
772 if ( ! $this->registry->has( 'campaign_field_registry' ) ) {
773 $campaign_fields = new Charitable_Campaign_Field_Registry();
774
775 /* Register it immediately to avoid endless recursion. */
776 $this->registry->register_object( $campaign_fields );
777
778 $fields = include $this->get_path( 'includes' ) . 'fields/default-fields/campaign-fields.php';
779
780 foreach ( $fields as $key => $args ) {
781 $campaign_fields->register_field( new Charitable_Campaign_Field( $key, $args ) );
782 }
783 }
784
785 return $this->registry->get( 'campaign_field_registry' );
786 }
787
788 /**
789 * Get the donation fields registry
790 *
791 * If the registry has not been set up yet, this will also
792 * perform the task of setting it up initially.
793 *
794 * This method is called on the plugins_loaded hook.
795 *
796 * @since 1.5.0
797 *
798 * @return Charitable_Donation_Field_Registry
799 */
800 public function donation_fields() {
801 if ( ! $this->registry->has( 'donation_field_registry' ) ) {
802 $donation_fields = new Charitable_Donation_Field_Registry();
803
804 /* Register it immediately to avoid endless recursion. */
805 $this->registry->register_object( $donation_fields );
806
807 $fields = include $this->get_path( 'includes' ) . 'fields/default-fields/donation-fields.php';
808
809 foreach ( $fields as $key => $args ) {
810 $donation_fields->register_field( new Charitable_Donation_Field( $key, $args ) );
811 }
812 }
813
814 return $this->registry->get( 'donation_field_registry' );
815 }
816
817 /**
818 * Return the Endpoints API object.
819 *
820 * If the Endpoints API has not been set up yet, this will also
821 * perform the task of setting it up initially.
822 *
823 * This method is called on the plugins_loaded hook.
824 *
825 * @since 1.5.0
826 *
827 * @return Charitable_Endpoints
828 */
829 public function endpoints() {
830 if ( ! $this->registry->has( 'endpoints' ) ) {
831 /**
832 * The order in which we register endpoints is important, because
833 * it determines the order in which the endpoints are checked to
834 * find whether they are the current page.
835 *
836 * Any endpoint that builds on another endpoint should be registered
837 * BEFORE the endpoint it builds on. In other words, move from
838 * most specific to least specific.
839 */
840 $endpoints = new Charitable_Endpoints();
841 $endpoints->register( new Charitable_Campaign_Donation_Endpoint() );
842 $endpoints->register( new Charitable_Campaign_Widget_Endpoint() );
843 $endpoints->register( new Charitable_Campaign_Endpoint() );
844 $endpoints->register( new Charitable_Donation_Cancellation_Endpoint() );
845 $endpoints->register( new Charitable_Donation_Processing_Endpoint() );
846 $endpoints->register( new Charitable_Donation_Receipt_Endpoint() );
847 $endpoints->register( new Charitable_Email_Preview_Endpoint() );
848 $endpoints->register( new Charitable_Email_Verification_Endpoint() );
849 $endpoints->register( new Charitable_Forgot_Password_Endpoint() );
850 $endpoints->register( new Charitable_Reset_Password_Endpoint() );
851 $endpoints->register( new Charitable_Registration_Endpoint() );
852 $endpoints->register( new Charitable_Login_Endpoint() );
853 $endpoints->register( new Charitable_Profile_Endpoint() );
854 $endpoints->register( new Charitable_Webhook_Listener_Endpoint() );
855
856 $this->registry->register_object( $endpoints );
857 }
858
859 return $this->registry->get( 'endpoints' );
860 }
861
862 /**
863 * Returns a registered object.
864 *
865 * @since 1.0.0
866 *
867 * @param string $class The type of class to be retrieved.
868 * @return object
869 */
870 public function get_registered_object( $class ) {
871 return $this->registry->get( $class );
872 }
873
874 /**
875 * Registers our donormeta table as a meta data table.
876 *
877 * @since 1.6.0
878 *
879 * @global WPDB $wpdb
880 * @return void
881 */
882 public function register_donormeta_table() {
883 global $wpdb;
884
885 $wpdb->donormeta = $wpdb->prefix . 'charitable_donormeta';
886 }
887
888 /**
889 * Returns the model for one of Charitable's database tables.
890 *
891 * @since 1.0.0
892 *
893 * @param string $table The database table to retrieve.
894 * @return Charitable_DB
895 */
896 public function get_db_table( $table ) {
897 $tables = $this->get_tables();
898
899 if ( ! isset( $tables[ $table ] ) ) {
900 charitable_get_deprecated()->doing_it_wrong(
901 __METHOD__,
902 sprintf( 'Invalid table %s passed', $table ),
903 '1.0.0'
904 );
905 return null;
906 }
907
908 return $this->registry->get( $tables[ $table ] );
909 }
910
911 /**
912 * Return the filtered list of registered tables.
913 *
914 * @since 1.0.0
915 *
916 * @return string[]
917 */
918 private function get_tables() {
919 /**
920 * Filter the array of available Charitable table classes.
921 *
922 * @since 1.0.0
923 * @version 1.8.1
924 *
925 * @param array $tables List of tables as a key=>value array.
926 */
927 return apply_filters(
928 'charitable_db_tables',
929 array(
930 'campaign_donations' => 'Charitable_Campaign_Donations_DB',
931 'donors' => 'Charitable_Donors_DB',
932 'donormeta' => 'Charitable_Donormeta_DB',
933 'donation_activities' => 'Charitable_Donation_Activities_DB',
934 'campaign_activities' => 'Charitable_Campaign_Activities_DB',
935 )
936 );
937 }
938
939 /**
940 * Maybe activate Charitable when a new site is added in a multisite network.
941 *
942 * @since 1.4.6
943 *
944 * @param int $blog_id The blog to activate Charitable on.
945 * @return void
946 */
947 public function maybe_activate_charitable_on_new_site( $blog_id ) {
948 if ( is_plugin_active_for_network( basename( $this->directory_path ) . '/charitable.php' ) ) {
949 switch_to_blog( $blog_id );
950 $this->activate( false );
951 restore_current_blog();
952 }
953 }
954
955 /**
956 * Runs on plugin activation.
957 *
958 * @see register_activation_hook
959 *
960 * @since 1.0.0
961 *
962 * @param boolean $network_wide Whether to enable the plugin for all sites in the network
963 * or just the current site. Multisite only. Default is false.
964 * @return void
965 */
966 public function activate( $network_wide = false ) {
967 require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-install.php';
968
969 if ( is_multisite() && $network_wide ) {
970 global $wpdb;
971
972 foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) {
973 switch_to_blog( $blog_id );
974 new Charitable_Install( $this->includes_path );
975 restore_current_blog();
976 }
977 } else {
978 new Charitable_Install( $this->includes_path );
979 }
980
981 // create or update the install date for future reference.
982 update_option( 'wpcharitable_activated_datetime', current_time( 'timestamp' ) );
983 }
984
985 /**
986 * Runs on plugin deactivation.
987 *
988 * @see register_deactivation_hook
989 *
990 * @since 1.0.0
991 *
992 * @return void
993 */
994 public function deactivate() {
995 require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-uninstall.php';
996 new Charitable_Uninstall();
997 }
998
999 /**
1000 * If a charitable_action event is triggered, delegate the event using do_action.
1001 *
1002 * @since 1.0.0
1003 *
1004 * @return void
1005 */
1006 public function do_charitable_actions() {
1007 if ( isset( $_REQUEST['charitable_action'] ) ) {
1008
1009 $action = esc_attr( $_REQUEST['charitable_action'] );
1010
1011 /**
1012 * Handle Charitable action.
1013 *
1014 * @since 1.0.0
1015 */
1016 do_action( 'charitable_' . $action );
1017 }
1018 }
1019
1020 /**
1021 * Throw error on object clone.
1022 *
1023 * This class is specifically designed to be instantiated once. You can retrieve the instance using charitable()
1024 *
1025 * @since 1.0.0
1026 *
1027 * @return void
1028 */
1029 public function __clone() {
1030 charitable_get_deprecated()->doing_it_wrong(
1031 __FUNCTION__,
1032 __( 'Cloning this object is forbidden.', 'charitable' ),
1033 '1.0.0'
1034 );
1035 }
1036
1037 /**
1038 * Disable unserializing of the class.
1039 *
1040 * @since 1.0.0
1041 *
1042 * @return void
1043 */
1044 public function __wakeup() {
1045 charitable_get_deprecated()->doing_it_wrong(
1046 __FUNCTION__,
1047 __( 'Unserializing instances of this class is forbidden.', 'charitable' ),
1048 '1.0.0'
1049 );
1050 }
1051
1052 /**
1053 * DEPRECATED METHODS
1054 */
1055
1056 /**
1057 * Load plugin compatibility files on plugins_loaded hook.
1058 *
1059 * @deprecated 1.8.0
1060 *
1061 * @since 1.4.18
1062 * @since 1.5.0 Deprecated.
1063 *
1064 * @return void
1065 */
1066 public function load_plugin_compat_files() {
1067 charitable_get_deprecated()->deprecated_function(
1068 __METHOD__,
1069 '1.5.0.',
1070 'charitable_load_compat_functions'
1071 );
1072
1073 charitable_load_compat_functions();
1074 }
1075
1076 /**
1077 * Stores an object in the plugin's registry.
1078 *
1079 * @deprecated 1.8.0
1080 *
1081 * @since 1.0.0
1082 * @since 1.5.0 Deprecated.
1083 *
1084 * @param mixed $object Object to be registered.
1085 * @return void
1086 */
1087 public function register_object( $object ) {
1088 charitable_get_deprecated()->deprecated_function(
1089 __METHOD__,
1090 '1.5.0',
1091 'charitable()->registry()->register_object()'
1092 );
1093
1094 $this->registry->register_object( $object );
1095 }
1096
1097 /**
1098 * Returns the public class.
1099 *
1100 * @deprecated 1.8.0
1101 *
1102 * @since 1.0.0
1103 * @since 1.5.0 Deprecated.
1104 *
1105 * @return Charitable_Public
1106 */
1107 public function get_public() {
1108 charitable_get_deprecated()->deprecated_function(
1109 __METHOD__,
1110 '1.5.0',
1111 'charitable_get_helper'
1112 );
1113
1114 return $this->registry->get( 'Charitable_Public' );
1115 }
1116
1117 /**
1118 * Returns the admin class.
1119 *
1120 * @deprecated 1.8.0
1121 *
1122 * @since 1.0.0
1123 * @since 1.5.0 Deprecated.
1124 *
1125 * @return Charitable_Admin
1126 */
1127 public function get_admin() {
1128 charitable_get_deprecated()->deprecated_function(
1129 __METHOD__,
1130 '1.5.0',
1131 'charitable_get_helper'
1132 );
1133
1134 return $this->registry->get( 'Charitable_Admin' );
1135 }
1136
1137 /**
1138 * Return the current request object.
1139 *
1140 * @deprecated 1.8.0
1141 *
1142 * @since 1.0.0
1143 * @since 1.5.0 Deprecated.
1144 *
1145 * @return Charitable_Request
1146 */
1147 public function get_request() {
1148 charitable_get_deprecated()->deprecated_function(
1149 __METHOD__,
1150 '1.5.0',
1151 'charitable_get_helper'
1152 );
1153
1154 return $this->registry->get( 'Charitable_Request' );
1155 }
1156
1157 /**
1158 * Returns the instance of Charitable_Currency.
1159 *
1160 * @deprecated 1.7.0
1161 *
1162 * @since 1.4.0 Deprecated.
1163 */
1164 public function get_currency_helper() {
1165 charitable_get_deprecated()->deprecated_function( __METHOD__, '1.4.0', 'charitable_get_currency_helper' );
1166 return charitable_get_currency_helper();
1167 }
1168
1169 /**
1170 * Returns the instance of Charitable_Locations.
1171 *
1172 * @deprecated 1.6.0
1173 *
1174 * @since 1.2.0 Deprecated.
1175 */
1176 public function get_location_helper() {
1177 charitable_get_deprecated()->deprecated_function( __METHOD__, '1.2.0', 'charitable_get_location_helper' );
1178 return charitable_get_location_helper();
1179 }
1180
1181 /**
1182 * Determine if we use Stripe core files or use an addon if that's installed and active. Checks for USE_NEW_STRIPE first.
1183 *
1184 * @since 1.7.0
1185 *
1186 * @return boolean
1187 */
1188 public function load_core_stripe() {
1189
1190 if ( false !== ( defined( 'USE_NEW_STRIPE' ) && USE_NEW_STRIPE ) ) {
1191 return true;
1192 }
1193
1194 // 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.
1195 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() ) ) {
1196 return false;
1197 }
1198
1199 return true;
1200 }
1201
1202 /**
1203 * Determine Stripe Connect is active.
1204 *
1205 * @since 1.7.0
1206 *
1207 * @return boolean
1208 */
1209 public function is_stripe_connect_addon() {
1210
1211 if ( in_array( 'charitable-stripe/charitable-stripe.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
1212 return true;
1213 }
1214
1215 return false;
1216 }
1217
1218 /**
1219 * Action links for the plugins page.
1220 *
1221 * @since 1.7.0
1222 *
1223 * @param array $actions An array of existing actions.
1224 * @param string $plugin_file The plugin file we are modifying.
1225 * @param boolean $action_links An array of action links to add.
1226 * @return array An array of action links.
1227 */
1228 public function plugin_action_links( $actions, $plugin_file, $action_links = false ) {
1229
1230 if ( ! charitable_is_pro() ) :
1231
1232 // if this isn't pro, add the upgrade link which is visible on the plugins page until the plugin name.
1233
1234 $action_links = [
1235 'proupgrade' => [
1236 // Translators: This is an action link users can click to purchase a license for All in One SEO Pro.
1237 'label' => __( 'Upgrade to Pro', 'charitable' ),
1238 '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',
1239 ],
1240 ];
1241
1242 endif;
1243
1244 if ( isset( $actions['edit'] ) ) {
1245 unset( $actions['edit'] );
1246 }
1247
1248 return $this->parse_action_links( $actions, $plugin_file, $action_links, 'before' );
1249 }
1250
1251 /**
1252 * Parse the action links.
1253 *
1254 * @since 1.7.0
1255 *
1256 * @param array $actions An array of existing actions.
1257 * @param string $pluginFile The plugin file we are modifying.
1258 * @param array $action_links An array of action links to add.
1259 * @param string $position The position to add the action links.
1260 * @return array
1261 */
1262 protected function parse_action_links( $actions, $pluginFile, $action_links = [], $position = 'after' ) {
1263 if ( empty( $this->plugin ) ) {
1264 $this->plugin = CHARITABLE_PLUGIN_BASENAME;
1265 }
1266
1267 if ( $this->plugin === $pluginFile && ! empty( $action_links ) ) {
1268 foreach ( $action_links as $key => $value ) {
1269 $link = [
1270 $key => '<a href="' . $value['url'] . '">' . $value['label'] . '</a>',
1271 ];
1272
1273 $actions = 'after' === $position ? array_merge( $actions, $link ) : array_merge( $link, $actions );
1274 }
1275 }
1276
1277 return $actions;
1278 }
1279
1280 /**
1281 * Set up licensing for pro.
1282 *
1283 * @since 1.7.0
1284 *
1285 * @return void
1286 */
1287 public function setup_licensing() {
1288 charitable_get_helper( 'licenses' )->register_licensed_product(
1289 self::NAME,
1290 self::AUTHOR,
1291 self::VERSION,
1292 __FILE__
1293 );
1294 }
1295
1296 /**
1297 * Deativates and/or warnings about any Charitable verison conflicts.
1298 *
1299 * @since 1.7.0
1300 */
1301 public function check_for_version_conflicts() {
1302
1303 // Check for Charitable Stripe < 1.5.0.
1304 if ( in_array( 'charitable-stripe/charitable-stripe.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
1305 if ( class_exists( 'Charitable_Stripe' ) && version_compare( Charitable_Stripe::VERSION, '1.5.0', '<' ) ) {
1306 // manually deactivate plugin.
1307 $found = false;
1308 $current = get_option( 'active_plugins', array() );
1309 $key = array_search( 'charitable-stripe/charitable-stripe.php', $current, true );
1310 if ( false !== $key ) {
1311 $found = true;
1312
1313 unset( $current[ $key ] );
1314 update_option( 'active_plugins', $current );
1315
1316 // translators: %s is the version number.
1317 $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 );
1318
1319 wp_die( $message . ' <a href="' . admin_url( 'plugins.php' ) . '">Click here to return to the plugins screen.</a>' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1320 }
1321 add_option( 'charitable_version_warning', $message );
1322 } else {
1323 delete_option( 'charitable_version_warning' );
1324 }
1325 }
1326 }
1327 }
1328
1329 $charitable = new Charitable();
1330
1331 endif;
1332