| @@ -1,22 +1,25 @@ | ||
| 1 | 1 | <?php |
| 2 | 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.6.6 | |
| 7 | - * Author: WP Charitable | |
| 8 | - * Author URI: https://wpcharitable.com | |
| 9 | - * Requires at least: 4.1 | |
| 10 | - * Tested up to: 4.9.8 | |
| 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.13 | |
| 7 | + * Author: Charitable Donations & Fundraising Team | |
| 8 | + * Author URI: https://wpcharitable.com | |
| 9 | + * Requires at least: 5.9 | |
| 10 | + * Requires PHP: 7.4 | |
| 11 | + * Stable tag: 1.8.13 | |
| 12 | + * License: GPLv2 or later | |
| 13 | + * License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html | |
| 11 | 14 | * |
| 12 | - * Text Domain: charitable | |
| 13 | - * Domain Path: /i18n/languages/ | |
| 15 | + * Text Domain: charitable | |
| 16 | + * Domain Path: /i18n/languages/ | |
| 14 | 17 | * |
| 15 | - * @package Charitable | |
| 16 | - * @author Eric Daams | |
| 17 | - * @copyright Copyright (c) 2018, Studio 164a | |
| 18 | - * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License | |
| 18 | + * @package Charitable | |
| 19 | + * @author David Bisset | |
| 20 | + * @copyright Copyright (c) 2026, WP Charitable LLC | |
| 21 | + * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License | |
| 19 | 22 | */ |
| 20 | 23 | |
| 21 | 24 | // Exit if accessed directly. |
| 22 | 25 | if ( ! defined( 'ABSPATH' ) ) { |
| @@ -25,40 +28,28 @@ | ||
| 25 | 28 | |
| 26 | 29 | if ( ! class_exists( 'Charitable' ) ) : |
| 27 | 30 | |
| 28 | 31 | /** |
| 29 | - * Main Charitable class | |
| 30 | - * | |
| 31 | - * @version 1.6.2 | |
| 32 | + * Main Charitable class. | |
| 32 | 33 | */ |
| 33 | 34 | class Charitable { |
| 34 | 35 | |
| 35 | - /** | |
| 36 | - * Plugin version. | |
| 37 | - * | |
| 38 | - * @var string | |
| 39 | - */ | |
| 40 | - const VERSION = '1.6.6'; | |
| 36 | + /** The product name. */ | |
| 37 | + const NAME = 'Charitable'; | |
| 41 | 38 | |
| 42 | - /** | |
| 43 | - * Version of database schema. | |
| 44 | - * | |
| 45 | - * @var string A date in the format: YYYYMMDD | |
| 46 | - */ | |
| 39 | + /** The plugin author name. */ | |
| 40 | + const AUTHOR = 'WP Charitable'; | |
| 41 | + | |
| 42 | + /* Plugin version. */ | |
| 43 | + const VERSION = '1.8.13'; | |
| 44 | + | |
| 45 | + /* Version of database schema. */ | |
| 47 | 46 | const DB_VERSION = '20180522'; |
| 48 | 47 | |
| 49 | - /** | |
| 50 | - * Campaign post type. | |
| 51 | - * | |
| 52 | - * @var string | |
| 53 | - */ | |
| 48 | + /* Campaign post type. */ | |
| 54 | 49 | const CAMPAIGN_POST_TYPE = 'campaign'; |
| 55 | 50 | |
| 56 | - /** | |
| 57 | - * Donation post type. | |
| 58 | - * | |
| 59 | - * @var string | |
| 60 | - */ | |
| 51 | + /* Donation post type. */ | |
| 61 | 52 | const DONATION_POST_TYPE = 'donation'; |
| 62 | 53 | |
| 63 | 54 | /** |
| 64 | 55 | * Single instance of this class. |
| @@ -115,8 +106,17 @@ | ||
| 115 | 106 | */ |
| 116 | 107 | private $classmap; |
| 117 | 108 | |
| 118 | 109 | /** |
| 110 | + * Plugin. | |
| 111 | + * | |
| 112 | + * @since 1.8.0 | |
| 113 | + * | |
| 114 | + * @var array | |
| 115 | + */ | |
| 116 | + private $plugin; | |
| 117 | + | |
| 118 | + /** | |
| 119 | 119 | * Create class instance. |
| 120 | 120 | * |
| 121 | 121 | * @since 1.0.0 |
| 122 | 122 | */ |
| @@ -124,8 +124,26 @@ | ||
| 124 | 124 | $this->directory_path = plugin_dir_path( __FILE__ ); |
| 125 | 125 | $this->directory_url = plugin_dir_url( __FILE__ ); |
| 126 | 126 | $this->includes_path = $this->directory_path . 'includes/'; |
| 127 | 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 | + if ( ! defined( 'CHARITABLE_ANALYSIS_API_URL' ) ) { | |
| 132 | + define( 'CHARITABLE_ANALYSIS_API_URL', apply_filters( 'charitable_analysis_api_url', 'https://nonprofitscore.org/api/v1/charitable/recommendations' ) ); | |
| 133 | + } | |
| 134 | + // No credential is shipped. Each site earns a runtime-minted, quota-limited per-site token from | |
| 135 | + // the register endpoint (see Charitable_Site_Analysis::register()); the token is not in plugin source. | |
| 136 | + if ( ! defined( 'CHARITABLE_ANALYSIS_REGISTER_URL' ) ) { | |
| 137 | + define( 'CHARITABLE_ANALYSIS_REGISTER_URL', apply_filters( 'charitable_analysis_register_url', 'https://nonprofitscore.org/api/v1/charitable/register' ) ); | |
| 138 | + } | |
| 139 | + // Note: CHARITABLE_ANALYSIS_SALT is intentionally NOT defined here. It would need wp_salt(), | |
| 140 | + // which lives in pluggable.php and is not loaded yet at plugin-construct time. The salt is | |
| 141 | + // resolved lazily in Charitable_Site_Analysis::gather_config() (admin-ajax time), and a host | |
| 142 | + // may still pre-define the CHARITABLE_ANALYSIS_SALT constant (e.g. in wp-config.php). | |
| 143 | + | |
| 144 | + define( 'CHARITABLE_BUILDER_SHOW_LEGACY_EDIT_LINKS', true ); // 1.8.0 specific. | |
| 145 | + | |
| 128 | 146 | spl_autoload_register( array( $this, 'autoloader' ) ); |
| 129 | 147 | |
| 130 | 148 | $this->load_dependencies(); |
| 131 | 149 | |
| @@ -131,9 +149,28 @@ | ||
| 131 | 149 | |
| 132 | 150 | register_activation_hook( __FILE__, array( $this, 'activate' ) ); |
| 133 | 151 | register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) ); |
| 134 | 152 | |
| 135 | - add_action( 'plugins_loaded', array( $this, 'start' ), 1 ); | |
| 153 | + add_filter( 'plugin_action_links_' . CHARITABLE_PLUGIN_BASENAME, array( $this, 'plugin_action_links' ), 99, 2 ); | |
| 154 | + add_action( 'plugins_loaded', array( $this, 'start' ), 3 ); | |
| 155 | + | |
| 156 | + add_action( 'plugins_loaded', array( $this, 'check_for_version_conflicts' ), 2 ); | |
| 157 | + | |
| 158 | + // Run upgrade-server callback before any redirect (e.g. login) can run. Request from connect-callback.php. | |
| 159 | + if ( defined( 'CHARITABLE_CONNECT_CALLBACK' ) && CHARITABLE_CONNECT_CALLBACK ) { | |
| 160 | + add_action( 'init', array( $this, 'run_connect_callback' ), -9999 ); | |
| 161 | + } | |
| 162 | + | |
| 163 | + // Initialize error handler early. | |
| 164 | + add_action( | |
| 165 | + 'plugins_loaded', | |
| 166 | + function () { | |
| 167 | + require_once $this->get_path( 'includes' ) . 'class-charitable-error-handler.php'; | |
| 168 | + $error_handler = new Charitable_Error_Handler(); | |
| 169 | + $error_handler->init(); | |
| 170 | + }, | |
| 171 | + 1 | |
| 172 | + ); | |
| 136 | 173 | } |
| 137 | 174 | |
| 138 | 175 | /** |
| 139 | 176 | * Returns the original instance of this class. |
| @@ -166,8 +203,10 @@ | ||
| 166 | 203 | |
| 167 | 204 | /* Set up the registry and instantiate objects we need straight away. */ |
| 168 | 205 | $this->registry(); |
| 169 | 206 | |
| 207 | + $this->setup_licensing(); | |
| 208 | + | |
| 170 | 209 | $this->maybe_start_ajax(); |
| 171 | 210 | |
| 172 | 211 | $this->attach_hooks_and_filters(); |
| 173 | 212 | |
| @@ -188,29 +227,97 @@ | ||
| 188 | 227 | private function load_dependencies() { |
| 189 | 228 | $includes_path = $this->get_path( 'includes' ); |
| 190 | 229 | |
| 191 | 230 | /* Load files with hooks & functions. Classes are autoloaded. */ |
| 192 | - require_once( $includes_path . 'charitable-core-functions.php' ); | |
| 193 | - require_once( $includes_path . 'api/charitable-api-functions.php' ); | |
| 194 | - require_once( $includes_path . 'campaigns/charitable-campaign-functions.php' ); | |
| 195 | - require_once( $includes_path . 'campaigns/charitable-campaign-hooks.php' ); | |
| 196 | - require_once( $includes_path . 'compat/charitable-compat-functions.php' ); | |
| 197 | - require_once( $includes_path . 'currency/charitable-currency-functions.php' ); | |
| 198 | - require_once( $includes_path . 'deprecated/charitable-deprecated-functions.php' ); | |
| 199 | - require_once( $includes_path . 'donations/charitable-donation-hooks.php' ); | |
| 200 | - require_once( $includes_path . 'donations/charitable-donation-functions.php' ); | |
| 201 | - require_once( $includes_path . 'emails/charitable-email-hooks.php' ); | |
| 202 | - require_once( $includes_path . 'endpoints/charitable-endpoints-functions.php' ); | |
| 203 | - require_once( $includes_path . 'privacy/charitable-privacy-functions.php' ); | |
| 204 | - require_once( $includes_path . 'public/charitable-template-helpers.php' ); | |
| 205 | - require_once( $includes_path . 'shortcodes/charitable-shortcodes-hooks.php' ); | |
| 206 | - require_once( $includes_path . 'upgrades/charitable-upgrade-hooks.php' ); | |
| 207 | - require_once( $includes_path . 'users/charitable-user-functions.php' ); | |
| 208 | - require_once( $includes_path . 'user-management/charitable-user-management-hooks.php' ); | |
| 209 | - require_once( $includes_path . 'utilities/charitable-utility-functions.php' ); | |
| 231 | + require_once $includes_path . 'class-charitable-log-muter.php'; | |
| 232 | + require_once $includes_path . 'charitable-core-functions.php'; | |
| 233 | + require_once $includes_path . 'api/charitable-api-functions.php'; | |
| 234 | + require_once $includes_path . 'campaigns/charitable-campaign-functions.php'; | |
| 235 | + require_once $includes_path . 'campaigns/charitable-campaign-hooks.php'; | |
| 236 | + require_once $includes_path . 'compat/charitable-compat-functions.php'; | |
| 237 | + require_once $includes_path . 'currency/charitable-currency-functions.php'; | |
| 238 | + require_once $includes_path . 'deprecated/charitable-deprecated-functions.php'; | |
| 239 | + require_once $includes_path . 'donations/charitable-donation-hooks.php'; | |
| 240 | + require_once $includes_path . 'donations/charitable-donation-functions.php'; | |
| 241 | + require_once $includes_path . 'emails/charitable-email-hooks.php'; | |
| 242 | + require_once $includes_path . 'endpoints/charitable-endpoints-functions.php'; | |
| 243 | + require_once $includes_path . 'privacy/charitable-privacy-functions.php'; | |
| 244 | + require_once $includes_path . 'public/charitable-template-helpers.php'; | |
| 245 | + require_once $includes_path . 'shortcodes/charitable-shortcodes-hooks.php'; | |
| 246 | + require_once $includes_path . 'tracking/charitable-tracking-hooks.php'; // 1.8.12 - MUST be outside the admin gate; see the file header. | |
| 247 | + require_once $includes_path . 'abilities/charitable-abilities-hooks.php'; // 1.8.13 - MUST be outside the admin gate: abilities register on REST and WP-CLI requests, neither of which is is_admin(). | |
| 248 | + require_once $includes_path . 'upgrades/charitable-upgrade-hooks.php'; | |
| 249 | + require_once $includes_path . 'users/charitable-user-functions.php'; | |
| 250 | + require_once $includes_path . 'user-management/charitable-user-management-hooks.php'; | |
| 251 | + require_once $includes_path . 'utilities/charitable-utility-functions.php'; | |
| 252 | + require_once $includes_path . 'elementor/charitable-elementor-hooks.php'; | |
| 253 | + | |
| 254 | + // Load security hooks on both admin and frontend (CAPTCHA needs to work on frontend). | |
| 255 | + require_once $this->get_path( 'includes', true ) . 'admin/security/charitable-security-hooks.php'; | |
| 256 | + | |
| 257 | + /* Load vendor/autoload.php - our modified platform_check.php and autoload_real.php will handle conditional loading */ | |
| 258 | + require_once $this->get_path( 'directory' ) . 'vendor/autoload.php'; | |
| 259 | + | |
| 260 | + /* Square Compatibility Wrapper - always load this regardless of PHP version */ | |
| 261 | + require_once $includes_path . 'square/class-charitable-square-compatibility.php'; | |
| 262 | + | |
| 263 | + /* Initialize Square conditionally - will check for compatibility internally */ | |
| 264 | + Charitable_Square_Compatibility::init(); | |
| 265 | + | |
| 266 | + if ( $this->load_core_stripe() ) : | |
| 267 | + | |
| 268 | + /* Interfaces */ | |
| 269 | + require_once $includes_path . 'stripe/interfaces/interface-charitable-stripe-gateway-processor.php'; | |
| 270 | + | |
| 271 | + /* Abstract classes */ | |
| 272 | + require_once $includes_path . 'stripe/abstracts/class-charitable-stripe-gateway-processor.php'; | |
| 273 | + | |
| 274 | + /* Classes */ | |
| 275 | + require_once $includes_path . 'stripe/donations/class-charitable-stripe-donation-log.php'; | |
| 276 | + require_once $includes_path . 'stripe/donations/class-charitable-stripe-recurring-donation-log.php'; | |
| 277 | + require_once $includes_path . 'stripe/i18n/class-charitable-stripe-i18n.php'; | |
| 278 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-connected-customer.php'; | |
| 279 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-customer.php'; | |
| 280 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-gateway-processor-payment-intents.php'; | |
| 281 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-payment-intent.php'; | |
| 282 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-plan.php'; | |
| 283 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-product.php'; | |
| 284 | + | |
| 285 | + require_once $includes_path . 'stripe/connect/charitable-stripe-connect-functions.php'; | |
| 286 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-gateway-processor-checkout.php'; | |
| 287 | + | |
| 288 | + /* Functions & Hooks */ | |
| 289 | + require_once $includes_path . 'stripe/charitable-stripe-core-functions.php'; | |
| 290 | + require_once $includes_path . 'stripe/donations/charitable-stripe-donation-functions.php'; | |
| 291 | + require_once $includes_path . 'stripe/gateway/charitable-stripe-gateway-hooks.php'; | |
| 292 | + | |
| 293 | + /* webhooks */ | |
| 294 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-webhook-api.php'; | |
| 295 | + require_once $includes_path . 'stripe/gateway/class-charitable-stripe-webhook-processor.php'; | |
| 296 | + | |
| 297 | + endif; | |
| 298 | + | |
| 299 | + /* Load PayPal Commerce Gateway */ | |
| 300 | + require_once $includes_path . 'gateways/paypal-commerce/charitable-paypal-commerce.php'; | |
| 210 | 301 | } |
| 211 | 302 | |
| 212 | 303 | /** |
| 304 | + * Load the template functions after theme is loaded. | |
| 305 | + * | |
| 306 | + * This gives themes time to override the functions. | |
| 307 | + * | |
| 308 | + * @since 1.6.10 | |
| 309 | + * | |
| 310 | + * @return void | |
| 311 | + */ | |
| 312 | + public function load_template_files() { | |
| 313 | + $includes_path = $this->get_path( 'includes' ); | |
| 314 | + | |
| 315 | + require_once $includes_path . 'public/charitable-template-functions.php'; | |
| 316 | + require_once $includes_path . 'public/charitable-template-hooks.php'; | |
| 317 | + } | |
| 318 | + | |
| 319 | + /** | |
| 213 | 320 | * Dynamically loads the class attempting to be instantiated elsewhere in the |
| 214 | 321 | * plugin by looking at the $class_name parameter being passed as an argument. |
| 215 | 322 | * |
| 216 | 323 | * @since 1.5.0 |
| @@ -230,18 +337,20 @@ | ||
| 230 | 337 | } |
| 231 | 338 | |
| 232 | 339 | /* Autogenerated class map. */ |
| 233 | 340 | if ( ! isset( $this->classmap ) ) { |
| 234 | - $this->classmap = include( 'includes/autoloader/charitable-class-map.php' ); | |
| 341 | + $this->classmap = include 'includes/autoloader/charitable-class-map.php'; | |
| 342 | + | |
| 343 | + $this->classmap['Charitable_Gateway_Stripe_AM'] = 'gateways/class-charitable-gateway-stripe-am.php'; | |
| 344 | + $this->classmap['Charitable_Gateway_Stripe'] = 'gateways/class-charitable-gateway-stripe-am.php'; | |
| 235 | 345 | } |
| 236 | 346 | |
| 237 | 347 | $file_path = isset( $this->classmap[ $class_name ] ) ? $this->get_path( 'includes' ) . $this->classmap[ $class_name ] : false; |
| 238 | 348 | |
| 239 | 349 | if ( false !== $file_path && file_exists( $file_path ) && is_file( $file_path ) ) { |
| 240 | - require_once( $file_path ); | |
| 350 | + require_once $file_path; | |
| 241 | 351 | return true; |
| 242 | 352 | } |
| 243 | - | |
| 244 | 353 | return false; |
| 245 | 354 | } |
| 246 | 355 | |
| 247 | 356 | /** |
| @@ -263,10 +372,14 @@ | ||
| 263 | 372 | $this->registry->register_object( Charitable_Widgets::get_instance() ); |
| 264 | 373 | $this->registry->register_object( Charitable_Licenses::get_instance() ); |
| 265 | 374 | $this->registry->register_object( Charitable_User_Dashboard::get_instance() ); |
| 266 | 375 | $this->registry->register_object( Charitable_Locations::get_instance() ); |
| 376 | + $this->registry->register_object( Charitable_Currency::get_instance() ); | |
| 377 | + $this->registry->register_object( Charitable_Notifications::get_instance() ); | |
| 267 | 378 | |
| 268 | - $this->registry->register_object( new Charitable_Privacy ); | |
| 379 | + $this->registry->register_object( new Charitable_Privacy() ); | |
| 380 | + $this->registry->register_object( new Charitable_Debugging() ); | |
| 381 | + $this->registry->register_object( new Charitable_Locale() ); | |
| 269 | 382 | } |
| 270 | 383 | |
| 271 | 384 | return $this->registry; |
| 272 | 385 | } |
| @@ -282,13 +395,14 @@ | ||
| 282 | 395 | add_action( 'wpmu_new_blog', array( $this, 'maybe_activate_charitable_on_new_site' ) ); |
| 283 | 396 | add_action( 'plugins_loaded', array( $this, 'charitable_install' ), 100 ); |
| 284 | 397 | add_action( 'plugins_loaded', array( $this, 'charitable_start' ), 100 ); |
| 285 | 398 | add_action( 'plugins_loaded', array( $this, 'endpoints' ), 100 ); |
| 286 | - add_action( 'plugins_loaded', array( $this, 'donation_fields' ), 100 ); | |
| 287 | - add_action( 'plugins_loaded', array( $this, 'campaign_fields' ), 100 ); | |
| 399 | + add_action( 'init', array( $this, 'donation_fields' ), 100 ); | |
| 400 | + add_action( 'init', array( $this, 'campaign_fields' ), 100 ); | |
| 288 | 401 | add_action( 'plugins_loaded', array( $this, 'register_donormeta_table' ) ); |
| 289 | 402 | add_action( 'plugins_loaded', 'charitable_load_compat_functions' ); |
| 290 | 403 | add_action( 'setup_theme', array( 'Charitable_Customizer', 'start' ) ); |
| 404 | + add_action( 'after_setup_theme', array( $this, 'load_template_files' ) ); | |
| 291 | 405 | add_action( 'wp_enqueue_scripts', array( $this, 'maybe_start_qunit' ), 100 ); |
| 292 | 406 | add_action( 'rest_api_init', 'charitable_register_api_routes' ); |
| 293 | 407 | |
| 294 | 408 | /** |
| @@ -295,11 +409,78 @@ | ||
| 295 | 409 | * We do this on priority 20 so that any functionality that is loaded on init (such |
| 296 | 410 | * as addons) has a chance to run before the event. |
| 297 | 411 | */ |
| 298 | 412 | add_action( 'init', array( $this, 'do_charitable_actions' ), 20 ); |
| 413 | + | |
| 414 | + if ( $this->load_core_stripe() ) : | |
| 415 | + | |
| 416 | + /** | |
| 417 | + * Set up scripts & stylesheets & enqueue them when appropriate. | |
| 418 | + */ | |
| 419 | + add_action( 'charitable_form_after_fields', array( $this, 'maybe_setup_stripe_scripts_in_donation_form' ) ); | |
| 420 | + add_action( 'charitable_campaign_loop_after', array( $this, 'maybe_setup_stripe_scripts_in_campaign_loop' ) ); | |
| 421 | + | |
| 422 | + endif; | |
| 299 | 423 | } |
| 300 | 424 | |
| 425 | + | |
| 301 | 426 | /** |
| 427 | + * Load Stripe JS, as well as our handling scripts. | |
| 428 | + * | |
| 429 | + * @since 1.4.0 | |
| 430 | + * | |
| 431 | + * @return boolean | |
| 432 | + */ | |
| 433 | + public function enqueue_stripe_scripts() { | |
| 434 | + if ( ! Charitable_Gateways::get_instance()->is_active_gateway( Charitable_Gateway_Stripe_AM::get_gateway_id() ) ) { | |
| 435 | + return false; | |
| 436 | + } | |
| 437 | + | |
| 438 | + wp_enqueue_script( 'charitable-stripe' ); | |
| 439 | + | |
| 440 | + return true; | |
| 441 | + } | |
| 442 | + | |
| 443 | + /** | |
| 444 | + * Load Stripe JS or Stripe Checkout, as well as our handling script. | |
| 445 | + * | |
| 446 | + * @uses Charitable_Stripe::enqueue_scripts() | |
| 447 | + * | |
| 448 | + * @since 1.4.0 | |
| 449 | + * | |
| 450 | + * @param Charitable_Donation_Form $form The current form object. | |
| 451 | + * @return boolean | |
| 452 | + */ | |
| 453 | + public function maybe_setup_stripe_scripts_in_donation_form( $form ) { | |
| 454 | + if ( ! is_a( $form, 'Charitable_Donation_Form' ) ) { | |
| 455 | + return false; | |
| 456 | + } | |
| 457 | + | |
| 458 | + if ( 'make_donation' !== $form->get_form_action() ) { | |
| 459 | + return false; | |
| 460 | + } | |
| 461 | + | |
| 462 | + return $this->enqueue_stripe_scripts(); | |
| 463 | + } | |
| 464 | + | |
| 465 | + /** | |
| 466 | + * Enqueue the Stripe JS/Checkout scripts after a campaign loop if modal donations are in use. | |
| 467 | + * | |
| 468 | + * @uses Charitable_Stripe::enqueue_scripts() | |
| 469 | + * | |
| 470 | + * @since 1.4.0 | |
| 471 | + * | |
| 472 | + * @return boolean | |
| 473 | + */ | |
| 474 | + public function maybe_setup_stripe_scripts_in_campaign_loop() { | |
| 475 | + if ( 'modal' !== charitable_get_option( 'donation_form_display', 'separate_page' ) ) { | |
| 476 | + return false; | |
| 477 | + } | |
| 478 | + | |
| 479 | + return $this->enqueue_stripe_scripts(); | |
| 480 | + } | |
| 481 | + | |
| 482 | + /** | |
| 302 | 483 | * Checks whether we're in the admin area and if so, loads the admin-only functionality. |
| 303 | 484 | * |
| 304 | 485 | * @since 1.0.0 |
| 305 | 486 | * |
| @@ -309,19 +490,70 @@ | ||
| 309 | 490 | if ( ! is_admin() ) { |
| 310 | 491 | return false; |
| 311 | 492 | } |
| 312 | 493 | |
| 313 | - require_once( $this->get_path( 'admin' ) . 'class-charitable-admin.php' ); | |
| 314 | - require_once( $this->get_path( 'admin' ) . 'charitable-admin-hooks.php' ); | |
| 494 | + // load blocks/Gutenberg related. | |
| 495 | + require_once $this->get_path( 'admin' ) . 'class-charitable-admin-blocks.php'; | |
| 315 | 496 | |
| 497 | + require_once $this->get_path( 'admin' ) . 'class-charitable-admin.php'; | |
| 498 | + require_once $this->get_path( 'admin' ) . 'charitable-admin-hooks.php'; | |
| 499 | + | |
| 500 | + // load campaign builder. | |
| 501 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/util.php'; | |
| 502 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/functions.php'; | |
| 503 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/ajax-actions.php'; | |
| 504 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/functions-legacy.php'; | |
| 505 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/debug.php'; | |
| 506 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/access.php'; | |
| 507 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-fields.php'; | |
| 508 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-form-fields.php'; | |
| 509 | + | |
| 510 | + // connect for upgrade.wpcharitable.com. | |
| 511 | + require_once $this->get_path( 'admin' ) . 'class-charitable-admin-connect.php'; | |
| 512 | + | |
| 513 | + // misc. | |
| 514 | + require_once $this->get_path( 'admin' ) . 'class-charitable-admin-pointers.php'; | |
| 515 | + require_once $this->get_path( 'admin' ) . 'plugins/charitable-admin-plugin-hooks.php'; | |
| 516 | + require_once $this->get_path( 'admin' ) . 'class-charitable-admin-getting-started.php'; | |
| 517 | + | |
| 518 | + // Site Analysis / Recommendations tab. | |
| 519 | + require_once $this->get_path( 'admin' ) . 'site-analysis/class-charitable-site-analysis.php'; | |
| 520 | + Charitable_Site_Analysis::get_instance(); | |
| 521 | + | |
| 316 | 522 | $admin = Charitable_Admin::get_instance(); |
| 523 | + $this->registry->register_object( $admin ); | |
| 317 | 524 | |
| 318 | - $this->registry->register_object( $admin ); | |
| 525 | + // Stripe. | |
| 526 | + require_once $this->get_path( 'includes' ) . 'stripe/admin/class-charitable-stripe-admin.php'; | |
| 527 | + new Charitable_Stripe_Admin(); | |
| 319 | 528 | |
| 320 | 529 | return $admin; |
| 321 | 530 | } |
| 322 | 531 | |
| 323 | 532 | /** |
| 533 | + * Run the upgrade-server connect callback on init before any redirect (e.g. to login) can run. | |
| 534 | + * Only registered when CHARITABLE_CONNECT_CALLBACK is defined (request came from connect-callback.php). | |
| 535 | + * | |
| 536 | + * @since 1.8.9.6 | |
| 537 | + */ | |
| 538 | + public function run_connect_callback() { | |
| 539 | + ini_set( 'display_errors', '0' ); | |
| 540 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; | |
| 541 | + require_once ABSPATH . 'wp-admin/includes/file.php'; | |
| 542 | + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; | |
| 543 | + $connect_file = $this->get_path( 'admin' ) . 'class-charitable-admin-connect.php'; | |
| 544 | + if ( file_exists( $connect_file ) ) { | |
| 545 | + require_once $connect_file; | |
| 546 | + } | |
| 547 | + if ( ! class_exists( 'Charitable_Admin_Connect' ) ) { | |
| 548 | + header( 'Content-Type: application/json' ); | |
| 549 | + wp_send_json( array( 'success' => false, 'data' => array( 'message' => 'Charitable not loaded.' ) ) ); | |
| 550 | + } | |
| 551 | + Charitable_Admin_Connect::get_instance()->process(); | |
| 552 | + exit; | |
| 553 | + } | |
| 554 | + | |
| 555 | + /** | |
| 324 | 556 | * Checks whether we're on the public-facing side and if so, loads the public-facing functionality. |
| 325 | 557 | * |
| 326 | 558 | * @since 1.0.0 |
| 327 | 559 | * |
| @@ -331,10 +563,18 @@ | ||
| 331 | 563 | if ( is_admin() && ! $this->is_ajax() ) { |
| 332 | 564 | return false; |
| 333 | 565 | } |
| 334 | 566 | |
| 335 | - require_once( $this->get_path( 'public' ) . 'class-charitable-public.php' ); | |
| 567 | + require_once $this->get_path( 'public' ) . 'class-charitable-public.php'; | |
| 336 | 568 | |
| 569 | + // Campaign Builder related (v1.8.0). | |
| 570 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/class-campaign-builder-preview.php'; | |
| 571 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-fields.php'; | |
| 572 | + require_once $this->get_path( 'admin' ) . 'campaign-builder/class-builder-form-fields.php'; | |
| 573 | + | |
| 574 | + // load blocks/Gutenberg related. | |
| 575 | + require_once $this->get_path( 'admin' ) . 'class-charitable-admin-blocks.php'; | |
| 576 | + | |
| 337 | 577 | $public = Charitable_Public::get_instance(); |
| 338 | 578 | |
| 339 | 579 | $this->registry->register_object( $public ); |
| 340 | 580 | |
| @@ -349,24 +589,51 @@ | ||
| 349 | 589 | * @return boolean |
| 350 | 590 | */ |
| 351 | 591 | public function maybe_start_qunit() { |
| 352 | 592 | /* Skip out early if ?qunit isn't included in the request. */ |
| 353 | - if ( ! array_key_exists( 'qunit', $_GET ) ) { | |
| 593 | + if ( ! array_key_exists( 'qunit', $_GET ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 354 | 594 | return false; |
| 355 | 595 | } |
| 356 | 596 | |
| 357 | - /* The unit tests have to exist. */ | |
| 358 | - if ( ! file_exists( $this->get_path( 'directory' ) . 'tests/qunit/tests.js' ) ) { | |
| 359 | - return false; | |
| 360 | - } | |
| 597 | + /* The unit tests have to exist. */ | |
| 598 | + if ( ! file_exists( $this->get_path( 'directory' ) . 'tests/qunit/tests.js' ) ) { | |
| 599 | + return false; | |
| 600 | + } | |
| 361 | 601 | |
| 362 | - wp_register_script( 'qunit', 'https://code.jquery.com/qunit/qunit-2.3.3.js', array(), '2.3.3', true ); | |
| 363 | - /* Version: '20170615-15:44' */ | |
| 364 | - wp_register_script( 'qunit-tests', $this->get_path( 'directory', false ) . 'tests/qunit/tests.js', array( 'jquery-core', 'qunit' ), time(), true ); | |
| 365 | - wp_enqueue_script( 'qunit-tests' ); | |
| 602 | + /** | |
| 603 | + * Register QUnit testing library. | |
| 604 | + * | |
| 605 | + * Note: These files must be bundled locally for WordPress.org compliance. | |
| 606 | + * Download from: | |
| 607 | + * - JS: https://code.jquery.com/qunit/qunit-2.3.3.js | |
| 608 | + * - CSS: https://code.jquery.com/qunit/qunit-2.3.3.css | |
| 609 | + * Save to: | |
| 610 | + * - assets/js/libraries/qunit-2.3.3.js | |
| 611 | + * - assets/css/libraries/qunit-2.3.3.css | |
| 612 | + * | |
| 613 | + * @since 1.0.0 | |
| 614 | + * @version 1.8.9.1 | |
| 615 | + */ | |
| 616 | + wp_register_script( | |
| 617 | + 'qunit', | |
| 618 | + $this->get_path( 'directory', false ) . 'assets/js/libraries/qunit-2.3.3.js', | |
| 619 | + array(), | |
| 620 | + '2.3.3', | |
| 621 | + true | |
| 622 | + ); | |
| 366 | 623 | |
| 367 | - wp_register_style( 'qunit', 'https://code.jquery.com/qunit/qunit-2.3.3.css', array(), '2.3.3', 'all' ); | |
| 368 | - wp_enqueue_style( 'qunit' ); | |
| 624 | + /* Version: '20170615-15:44' */ | |
| 625 | + wp_register_script( 'qunit-tests', $this->get_path( 'directory', false ) . 'tests/qunit/tests.js', array( 'jquery', 'qunit' ), time(), true ); | |
| 626 | + wp_enqueue_script( 'qunit-tests' ); | |
| 627 | + | |
| 628 | + wp_register_style( | |
| 629 | + 'qunit', | |
| 630 | + $this->get_path( 'directory', false ) . 'assets/css/libraries/qunit-2.3.3.css', | |
| 631 | + array(), | |
| 632 | + '2.3.3', | |
| 633 | + 'all' | |
| 634 | + ); | |
| 635 | + wp_enqueue_style( 'qunit' ); | |
| 369 | 636 | } |
| 370 | 637 | |
| 371 | 638 | /** |
| 372 | 639 | * Checks whether the current request is an AJAX request. |
| @@ -390,10 +657,10 @@ | ||
| 390 | 657 | if ( ! $this->is_ajax() ) { |
| 391 | 658 | return; |
| 392 | 659 | } |
| 393 | 660 | |
| 394 | - require_once( $this->get_path( 'includes' ) . 'ajax/charitable-ajax-functions.php' ); | |
| 395 | - require_once( $this->get_path( 'includes' ) . 'ajax/charitable-ajax-hooks.php' ); | |
| 661 | + require_once $this->get_path( 'includes' ) . 'ajax/charitable-ajax-functions.php'; | |
| 662 | + require_once $this->get_path( 'includes' ) . 'ajax/charitable-ajax-hooks.php'; | |
| 396 | 663 | } |
| 397 | 664 | |
| 398 | 665 | /** |
| 399 | 666 | * This method is fired after all plugins are loaded and simply fires the charitable_start hook. |
| @@ -411,9 +678,11 @@ | ||
| 411 | 678 | /** |
| 412 | 679 | * Fires off an action right after Charitable is installed, allowing other |
| 413 | 680 | * plugins/themes to do something at this point. |
| 414 | 681 | * |
| 415 | - * @since 1.0.1 | |
| 682 | + * @since 1.0.1 | |
| 683 | + * @version 1.8.1.12 - Added transient for activation redirect. | |
| 684 | + * @version 1.8.3 - Added call to add version and delete notifications. | |
| 416 | 685 | * |
| 417 | 686 | * @return void |
| 418 | 687 | */ |
| 419 | 688 | public function charitable_install() { |
| @@ -422,9 +691,9 @@ | ||
| 422 | 691 | if ( ! $install ) { |
| 423 | 692 | return; |
| 424 | 693 | } |
| 425 | 694 | |
| 426 | - require_once( $this->get_path( 'includes' ) . 'class-charitable-install.php' ); | |
| 695 | + require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-install.php'; | |
| 427 | 696 | |
| 428 | 697 | Charitable_Install::finish_installing(); |
| 429 | 698 | |
| 430 | 699 | do_action( 'charitable_install' ); |
| @@ -429,8 +698,28 @@ | ||
| 429 | 698 | |
| 430 | 699 | do_action( 'charitable_install' ); |
| 431 | 700 | |
| 432 | 701 | delete_transient( 'charitable_install' ); |
| 702 | + | |
| 703 | + // Store the date when the initial activation was performed. | |
| 704 | + $type = function_exists( 'charitable_is_pro' ) && charitable_is_pro() ? 'pro' : 'lite'; | |
| 705 | + $activated = (array) get_option( 'charitable_activated', array() ); | |
| 706 | + | |
| 707 | + // If no activation date is set, assume it's a new install and set the activation redirect transient. | |
| 708 | + if ( false === $activated || empty( $activated ) ) { | |
| 709 | + // Add transient to trigger redirect to the Welcome / Getting Started screen. | |
| 710 | + set_transient( 'charitable_activation_redirect', true, 30 ); | |
| 711 | + } | |
| 712 | + | |
| 713 | + $this->add_version_to_upgraded_from(); | |
| 714 | + | |
| 715 | + if ( empty( $activated[ $type ] ) ) { | |
| 716 | + $activated[ $type ] = time(); | |
| 717 | + update_option( 'charitable_activated', $activated ); | |
| 718 | + } | |
| 719 | + | |
| 720 | + // Clear notifications. | |
| 721 | + delete_option( 'charitable_notifications' ); | |
| 433 | 722 | } |
| 434 | 723 | |
| 435 | 724 | /** |
| 436 | 725 | * Returns whether we are currently in the start phase of the plugin. |
| @@ -439,9 +728,9 @@ | ||
| 439 | 728 | * |
| 440 | 729 | * @return boolean |
| 441 | 730 | */ |
| 442 | 731 | public function is_start() { |
| 443 | - return current_filter() == 'charitable_start'; | |
| 732 | + return current_filter() == 'charitable_start'; // phpcs:ignore | |
| 444 | 733 | } |
| 445 | 734 | |
| 446 | 735 | /** |
| 447 | 736 | * Returns whether the plugin has already started. |
| @@ -450,9 +739,9 @@ | ||
| 450 | 739 | * |
| 451 | 740 | * @return boolean |
| 452 | 741 | */ |
| 453 | 742 | public function started() { |
| 454 | - return did_action( 'charitable_start' ) || current_filter() == 'charitable_start'; | |
| 743 | + return did_action( 'charitable_start' ) || current_filter() == 'charitable_start'; // phpcs:ignore | |
| 455 | 744 | } |
| 456 | 745 | |
| 457 | 746 | /** |
| 458 | 747 | * Returns whether the plugin is being activated. |
| @@ -461,9 +750,9 @@ | ||
| 461 | 750 | * |
| 462 | 751 | * @return boolean |
| 463 | 752 | */ |
| 464 | 753 | public function is_activation() { |
| 465 | - return current_filter() == 'activate_charitable/charitable.php'; | |
| 754 | + return current_filter() == 'activate_charitable/charitable.php'; // phpcs:ignore | |
| 466 | 755 | } |
| 467 | 756 | |
| 468 | 757 | /** |
| 469 | 758 | * Returns whether the plugin is being deactivated. |
| @@ -472,9 +761,9 @@ | ||
| 472 | 761 | * |
| 473 | 762 | * @return boolean |
| 474 | 763 | */ |
| 475 | 764 | public function is_deactivation() { |
| 476 | - return current_filter() == 'deactivate_charitable/charitable.php'; | |
| 765 | + return current_filter() == 'deactivate_charitable/charitable.php'; // phpcs:ignore | |
| 477 | 766 | } |
| 478 | 767 | |
| 479 | 768 | /** |
| 480 | 769 | * Returns plugin paths. |
| @@ -508,8 +797,12 @@ | ||
| 508 | 797 | case 'templates': |
| 509 | 798 | $path = $base . 'templates/'; |
| 510 | 799 | break; |
| 511 | 800 | |
| 801 | + case 'plugin-directory': | |
| 802 | + $path = WP_PLUGIN_DIR; | |
| 803 | + break; | |
| 804 | + | |
| 512 | 805 | case 'directory': |
| 513 | 806 | $path = $base; |
| 514 | 807 | break; |
| 515 | 808 | |
| @@ -539,8 +832,26 @@ | ||
| 539 | 832 | return $version; |
| 540 | 833 | } |
| 541 | 834 | |
| 542 | 835 | /** |
| 836 | + * Adds previous versions to the upgraded_from option. | |
| 837 | + * | |
| 838 | + * @since 1.8.3 | |
| 839 | + */ | |
| 840 | + public function add_version_to_upgraded_from() { | |
| 841 | + | |
| 842 | + $upgraded_from = get_option( 'charitable_version_upgraded_from', array() ); | |
| 843 | + | |
| 844 | + if ( ! is_array( $upgraded_from ) ) { | |
| 845 | + $upgraded_from = array(); | |
| 846 | + } | |
| 847 | + | |
| 848 | + $upgraded_from[] = $this->get_version(); | |
| 849 | + | |
| 850 | + update_option( 'charitable_version_upgraded_from', $upgraded_from, false ); | |
| 851 | + } | |
| 852 | + | |
| 853 | + /** | |
| 543 | 854 | * Get the campaign fields registry |
| 544 | 855 | * |
| 545 | 856 | * If the registry has not been set up yet, this will also |
| 546 | 857 | * perform the task of setting it up initially. |
| @@ -557,9 +868,9 @@ | ||
| 557 | 868 | |
| 558 | 869 | /* Register it immediately to avoid endless recursion. */ |
| 559 | 870 | $this->registry->register_object( $campaign_fields ); |
| 560 | 871 | |
| 561 | - $fields = include( $this->get_path( 'includes' ) . 'fields/default-fields/campaign-fields.php' ); | |
| 872 | + $fields = include $this->get_path( 'includes' ) . 'fields/default-fields/campaign-fields.php'; | |
| 562 | 873 | |
| 563 | 874 | foreach ( $fields as $key => $args ) { |
| 564 | 875 | $campaign_fields->register_field( new Charitable_Campaign_Field( $key, $args ) ); |
| 565 | 876 | } |
| @@ -586,9 +897,9 @@ | ||
| 586 | 897 | |
| 587 | 898 | /* Register it immediately to avoid endless recursion. */ |
| 588 | 899 | $this->registry->register_object( $donation_fields ); |
| 589 | 900 | |
| 590 | - $fields = include( $this->get_path( 'includes' ) . 'fields/default-fields/donation-fields.php' ); | |
| 901 | + $fields = include $this->get_path( 'includes' ) . 'fields/default-fields/donation-fields.php'; | |
| 591 | 902 | |
| 592 | 903 | foreach ( $fields as $key => $args ) { |
| 593 | 904 | $donation_fields->register_field( new Charitable_Donation_Field( $key, $args ) ); |
| 594 | 905 | } |
| @@ -620,21 +931,22 @@ | ||
| 620 | 931 | * BEFORE the endpoint it builds on. In other words, move from |
| 621 | 932 | * most specific to least specific. |
| 622 | 933 | */ |
| 623 | 934 | $endpoints = new Charitable_Endpoints(); |
| 624 | - $endpoints->register( new Charitable_Campaign_Donation_Endpoint ); | |
| 625 | - $endpoints->register( new Charitable_Campaign_Widget_Endpoint ); | |
| 626 | - $endpoints->register( new Charitable_Campaign_Endpoint ); | |
| 627 | - $endpoints->register( new Charitable_Donation_Cancellation_Endpoint ); | |
| 628 | - $endpoints->register( new Charitable_Donation_Processing_Endpoint ); | |
| 629 | - $endpoints->register( new Charitable_Donation_Receipt_Endpoint ); | |
| 630 | - $endpoints->register( new Charitable_Email_Preview_Endpoint ); | |
| 631 | - $endpoints->register( new Charitable_Email_Verification_Endpoint ); | |
| 632 | - $endpoints->register( new Charitable_Forgot_Password_Endpoint ); | |
| 633 | - $endpoints->register( new Charitable_Reset_Password_Endpoint ); | |
| 634 | - $endpoints->register( new Charitable_Registration_Endpoint ); | |
| 635 | - $endpoints->register( new Charitable_Login_Endpoint ); | |
| 636 | - $endpoints->register( new Charitable_Profile_Endpoint ); | |
| 935 | + $endpoints->register( new Charitable_Campaign_Donation_Endpoint() ); | |
| 936 | + $endpoints->register( new Charitable_Campaign_Widget_Endpoint() ); | |
| 937 | + $endpoints->register( new Charitable_Campaign_Endpoint() ); | |
| 938 | + $endpoints->register( new Charitable_Donation_Cancellation_Endpoint() ); | |
| 939 | + $endpoints->register( new Charitable_Donation_Processing_Endpoint() ); | |
| 940 | + $endpoints->register( new Charitable_Donation_Receipt_Endpoint() ); | |
| 941 | + $endpoints->register( new Charitable_Email_Preview_Endpoint() ); | |
| 942 | + $endpoints->register( new Charitable_Email_Verification_Endpoint() ); | |
| 943 | + $endpoints->register( new Charitable_Forgot_Password_Endpoint() ); | |
| 944 | + $endpoints->register( new Charitable_Reset_Password_Endpoint() ); | |
| 945 | + $endpoints->register( new Charitable_Registration_Endpoint() ); | |
| 946 | + $endpoints->register( new Charitable_Login_Endpoint() ); | |
| 947 | + $endpoints->register( new Charitable_Profile_Endpoint() ); | |
| 948 | + $endpoints->register( new Charitable_Webhook_Listener_Endpoint() ); | |
| 637 | 949 | |
| 638 | 950 | $this->registry->register_object( $endpoints ); |
| 639 | 951 | } |
| 640 | 952 | |
| @@ -648,9 +960,9 @@ | ||
| 648 | 960 | * |
| 649 | 961 | * @param string $class The type of class to be retrieved. |
| 650 | 962 | * @return object |
| 651 | 963 | */ |
| 652 | - public function get_registered_object( $class ) { | |
| 964 | + public function get_registered_object( $class ) { // phpcs:ignore | |
| 653 | 965 | return $this->registry->get( $class ); |
| 654 | 966 | } |
| 655 | 967 | |
| 656 | 968 | /** |
| @@ -701,16 +1013,22 @@ | ||
| 701 | 1013 | /** |
| 702 | 1014 | * Filter the array of available Charitable table classes. |
| 703 | 1015 | * |
| 704 | 1016 | * @since 1.0.0 |
| 1017 | + * @version 1.8.1 | |
| 705 | 1018 | * |
| 706 | 1019 | * @param array $tables List of tables as a key=>value array. |
| 707 | 1020 | */ |
| 708 | - return apply_filters( 'charitable_db_tables', array( | |
| 709 | - 'campaign_donations' => 'Charitable_Campaign_Donations_DB', | |
| 710 | - 'donors' => 'Charitable_Donors_DB', | |
| 711 | - 'donormeta' => 'Charitable_Donormeta_DB', | |
| 712 | - ) ); | |
| 1021 | + return apply_filters( | |
| 1022 | + 'charitable_db_tables', | |
| 1023 | + array( | |
| 1024 | + 'campaign_donations' => 'Charitable_Campaign_Donations_DB', | |
| 1025 | + 'donors' => 'Charitable_Donors_DB', | |
| 1026 | + 'donormeta' => 'Charitable_Donormeta_DB', | |
| 1027 | + 'donation_activities' => 'Charitable_Donation_Activities_DB', | |
| 1028 | + 'campaign_activities' => 'Charitable_Campaign_Activities_DB', | |
| 1029 | + ) | |
| 1030 | + ); | |
| 713 | 1031 | } |
| 714 | 1032 | |
| 715 | 1033 | /** |
| 716 | 1034 | * Maybe activate Charitable when a new site is added in a multisite network. |
| @@ -739,21 +1057,27 @@ | ||
| 739 | 1057 | * or just the current site. Multisite only. Default is false. |
| 740 | 1058 | * @return void |
| 741 | 1059 | */ |
| 742 | 1060 | public function activate( $network_wide = false ) { |
| 743 | - require_once( $this->get_path( 'includes' ) . 'class-charitable-install.php' ); | |
| 1061 | + require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-install.php'; | |
| 744 | 1062 | |
| 745 | 1063 | if ( is_multisite() && $network_wide ) { |
| 746 | 1064 | global $wpdb; |
| 747 | 1065 | |
| 748 | - foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) { | |
| 1066 | + foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) { // phpcs:ignore | |
| 749 | 1067 | switch_to_blog( $blog_id ); |
| 750 | - new Charitable_Install(); | |
| 1068 | + new Charitable_Install( $this->includes_path ); | |
| 751 | 1069 | restore_current_blog(); |
| 752 | 1070 | } |
| 753 | 1071 | } else { |
| 754 | - new Charitable_Install(); | |
| 1072 | + new Charitable_Install( $this->includes_path ); | |
| 755 | 1073 | } |
| 1074 | + | |
| 1075 | + // create or update the install date for future reference. | |
| 1076 | + update_option( 'wpcharitable_activated_datetime', current_time( 'timestamp' ) ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested | |
| 1077 | + | |
| 1078 | + // Set initial timestamps for rotating menu items if they're already installed | |
| 1079 | + $this->set_initial_rotating_menu_timestamps(); | |
| 756 | 1080 | } |
| 757 | 1081 | |
| 758 | 1082 | /** |
| 759 | 1083 | * Runs on plugin deactivation. |
| @@ -764,9 +1088,9 @@ | ||
| 764 | 1088 | * |
| 765 | 1089 | * @return void |
| 766 | 1090 | */ |
| 767 | 1091 | public function deactivate() { |
| 768 | - require_once( $this->get_path( 'includes' ) . 'class-charitable-uninstall.php' ); | |
| 1092 | + require_once $this->get_path( 'includes' ) . 'plugin/class-charitable-uninstall.php'; | |
| 769 | 1093 | new Charitable_Uninstall(); |
| 770 | 1094 | } |
| 771 | 1095 | |
| 772 | 1096 | /** |
| @@ -776,11 +1100,11 @@ | ||
| 776 | 1100 | * |
| 777 | 1101 | * @return void |
| 778 | 1102 | */ |
| 779 | 1103 | public function do_charitable_actions() { |
| 780 | - if ( isset( $_REQUEST['charitable_action'] ) ) { | |
| 1104 | + if ( isset( $_REQUEST['charitable_action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 781 | 1105 | |
| 782 | - $action = $_REQUEST['charitable_action']; | |
| 1106 | + $action = esc_attr( $_REQUEST['charitable_action'] ); // phpcs:ignore | |
| 783 | 1107 | |
| 784 | 1108 | /** |
| 785 | 1109 | * Handle Charitable action. |
| 786 | 1110 | * |
| @@ -856,9 +1180,9 @@ | ||
| 856 | 1180 | * |
| 857 | 1181 | * @param mixed $object Object to be registered. |
| 858 | 1182 | * @return void |
| 859 | 1183 | */ |
| 860 | - public function register_object( $object ) { | |
| 1184 | + public function register_object( $object ) { // phpcs:ignore | |
| 861 | 1185 | charitable_get_deprecated()->deprecated_function( |
| 862 | 1186 | __METHOD__, |
| 863 | 1187 | '1.5.0', |
| 864 | 1188 | 'charitable()->registry()->register_object()' |
| @@ -948,8 +1272,214 @@ | ||
| 948 | 1272 | */ |
| 949 | 1273 | public function get_location_helper() { |
| 950 | 1274 | charitable_get_deprecated()->deprecated_function( __METHOD__, '1.2.0', 'charitable_get_location_helper' ); |
| 951 | 1275 | return charitable_get_location_helper(); |
| 1276 | + } | |
| 1277 | + | |
| 1278 | + /** | |
| 1279 | + * Determine if we use Stripe core files or use an addon if that's installed and active. Checks for USE_NEW_STRIPE first. | |
| 1280 | + * | |
| 1281 | + * @since 1.7.0 | |
| 1282 | + * | |
| 1283 | + * @return boolean | |
| 1284 | + */ | |
| 1285 | + public function load_core_stripe() { | |
| 1286 | + | |
| 1287 | + if ( false !== ( defined( 'USE_NEW_STRIPE' ) && USE_NEW_STRIPE ) ) { | |
| 1288 | + return true; | |
| 1289 | + } | |
| 1290 | + | |
| 1291 | + // 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. | |
| 1292 | + 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() ) ) { | |
| 1293 | + return false; | |
| 1294 | + } | |
| 1295 | + | |
| 1296 | + return true; | |
| 1297 | + } | |
| 1298 | + | |
| 1299 | + /** | |
| 1300 | + * Determine Stripe Connect is active. | |
| 1301 | + * | |
| 1302 | + * @since 1.7.0 | |
| 1303 | + * | |
| 1304 | + * @return boolean | |
| 1305 | + */ | |
| 1306 | + public function is_stripe_connect_addon() { | |
| 1307 | + | |
| 1308 | + if ( in_array( 'charitable-stripe/charitable-stripe.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) { // phpcs:ignore | |
| 1309 | + return true; | |
| 1310 | + } | |
| 1311 | + | |
| 1312 | + return false; | |
| 1313 | + } | |
| 1314 | + | |
| 1315 | + /** | |
| 1316 | + * Action links for the plugins page. | |
| 1317 | + * | |
| 1318 | + * @since 1.7.0 | |
| 1319 | + * | |
| 1320 | + * @param array $actions An array of existing actions. | |
| 1321 | + * @param string $plugin_file The plugin file we are modifying. | |
| 1322 | + * @param boolean $action_links An array of action links to add. | |
| 1323 | + * @return array An array of action links. | |
| 1324 | + */ | |
| 1325 | + public function plugin_action_links( $actions, $plugin_file, $action_links = false ) { | |
| 1326 | + | |
| 1327 | + if ( ! charitable_is_pro() ) : | |
| 1328 | + | |
| 1329 | + // if this isn't pro, add the upgrade link which is visible on the plugins page until the plugin name. | |
| 1330 | + | |
| 1331 | + $action_links = array( | |
| 1332 | + 'proupgrade' => array( | |
| 1333 | + // Translators: This is an action link users can click to purchase a license for All in One SEO Pro. | |
| 1334 | + 'label' => __( 'Upgrade to Pro', 'charitable' ), | |
| 1335 | + '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', | |
| 1336 | + ), | |
| 1337 | + ); | |
| 1338 | + | |
| 1339 | + endif; | |
| 1340 | + | |
| 1341 | + if ( isset( $actions['edit'] ) ) { | |
| 1342 | + unset( $actions['edit'] ); | |
| 1343 | + } | |
| 1344 | + | |
| 1345 | + return $this->parse_action_links( $actions, $plugin_file, $action_links, 'before' ); | |
| 1346 | + } | |
| 1347 | + | |
| 1348 | + /** | |
| 1349 | + * Parse the action links. | |
| 1350 | + * | |
| 1351 | + * @since 1.7.0 | |
| 1352 | + * | |
| 1353 | + * @param array $actions An array of existing actions. | |
| 1354 | + * @param string $plugin_file The plugin file we are modifying. | |
| 1355 | + * @param array $action_links An array of action links to add. | |
| 1356 | + * @param string $position The position to add the action links. | |
| 1357 | + * @return array | |
| 1358 | + */ | |
| 1359 | + protected function parse_action_links( $actions, $plugin_file, $action_links = array(), $position = 'after' ) { | |
| 1360 | + if ( empty( $this->plugin ) ) { | |
| 1361 | + $this->plugin = CHARITABLE_PLUGIN_BASENAME; | |
| 1362 | + } | |
| 1363 | + | |
| 1364 | + if ( $this->plugin === $plugin_file && ! empty( $action_links ) ) { | |
| 1365 | + foreach ( $action_links as $key => $value ) { | |
| 1366 | + $link = array( | |
| 1367 | + $key => '<a href="' . $value['url'] . '">' . $value['label'] . '</a>', | |
| 1368 | + ); | |
| 1369 | + | |
| 1370 | + $actions = 'after' === $position ? array_merge( $actions, $link ) : array_merge( $link, $actions ); | |
| 1371 | + } | |
| 1372 | + } | |
| 1373 | + | |
| 1374 | + return $actions; | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + /** | |
| 1378 | + * Set up licensing for pro. | |
| 1379 | + * | |
| 1380 | + * @since 1.7.0 | |
| 1381 | + * | |
| 1382 | + * @return void | |
| 1383 | + */ | |
| 1384 | + public function setup_licensing() { | |
| 1385 | + charitable_get_helper( 'licenses' )->register_licensed_product( | |
| 1386 | + self::NAME, | |
| 1387 | + self::AUTHOR, | |
| 1388 | + self::VERSION, | |
| 1389 | + __FILE__ | |
| 1390 | + ); | |
| 1391 | + } | |
| 1392 | + | |
| 1393 | + /** | |
| 1394 | + * Deativates and/or warnings about any Charitable verison conflicts. | |
| 1395 | + * | |
| 1396 | + * @since 1.7.0 | |
| 1397 | + */ | |
| 1398 | + public function check_for_version_conflicts() { | |
| 1399 | + | |
| 1400 | + // Check for Charitable Stripe < 1.5.0. | |
| 1401 | + if ( in_array( 'charitable-stripe/charitable-stripe.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) { // phpcs:ignore | |
| 1402 | + if ( class_exists( 'Charitable_Stripe' ) && version_compare( Charitable_Stripe::VERSION, '1.5.0', '<' ) ) { // phpcs:ignore | |
| 1403 | + // manually deactivate plugin. | |
| 1404 | + $found = false; | |
| 1405 | + $current = get_option( 'active_plugins', array() ); | |
| 1406 | + $key = array_search( 'charitable-stripe/charitable-stripe.php', $current, true ); | |
| 1407 | + if ( false !== $key ) { | |
| 1408 | + $found = true; | |
| 1409 | + | |
| 1410 | + unset( $current[ $key ] ); | |
| 1411 | + update_option( 'active_plugins', $current ); | |
| 1412 | + | |
| 1413 | + // translators: %s is the version number. | |
| 1414 | + $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 ); | |
| 1415 | + | |
| 1416 | + wp_die( $message . ' <a href="' . admin_url( 'plugins.php' ) . '">Click here to return to the plugins screen.</a>' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 1417 | + } | |
| 1418 | + add_option( 'charitable_version_warning', $message ); | |
| 1419 | + } else { | |
| 1420 | + delete_option( 'charitable_version_warning' ); | |
| 1421 | + } | |
| 1422 | + } | |
| 1423 | + } | |
| 1424 | + | |
| 1425 | + /** | |
| 1426 | + * Set initial timestamps for rotating menu items if they're already installed. | |
| 1427 | + * This ensures the 7-day countdown starts immediately for already-installed plugins. | |
| 1428 | + * | |
| 1429 | + * @since 1.8.8 | |
| 1430 | + * | |
| 1431 | + * @return void | |
| 1432 | + */ | |
| 1433 | + private function set_initial_rotating_menu_timestamps() { | |
| 1434 | + // Get the rotating menu items configuration | |
| 1435 | + $admin_pages = Charitable_Admin_Pages::get_instance(); | |
| 1436 | + | |
| 1437 | + try { | |
| 1438 | + $reflection = new ReflectionClass( $admin_pages ); | |
| 1439 | + $method = $reflection->getMethod( 'get_marketing_rotation_items' ); | |
| 1440 | + $method->setAccessible( true ); | |
| 1441 | + $items = $method->invoke( $admin_pages ); | |
| 1442 | + } catch ( ReflectionException $e ) { | |
| 1443 | + // Fallback if reflection fails in future PHP versions | |
| 1444 | + $items = array(); | |
| 1445 | + } | |
| 1446 | + | |
| 1447 | + $current_time = time(); | |
| 1448 | + | |
| 1449 | + foreach ( $items as $item ) { | |
| 1450 | + $option_name = $item['option_name'] ?? ''; | |
| 1451 | + $option_key = $item['option_key'] ?? ''; | |
| 1452 | + $plugin_file = $item['plugin_file'] ?? ''; | |
| 1453 | + | |
| 1454 | + if ( empty( $option_name ) || empty( $plugin_file ) ) { | |
| 1455 | + continue; | |
| 1456 | + } | |
| 1457 | + | |
| 1458 | + // Check if the plugin is installed (file exists in plugins directory) | |
| 1459 | + $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file; | |
| 1460 | + if ( file_exists( $plugin_path ) ) { | |
| 1461 | + // Plugin is installed, check if we already have a timestamp | |
| 1462 | + $existing_option = get_option( $option_name ); | |
| 1463 | + $has_timestamp = false; | |
| 1464 | + | |
| 1465 | + if ( is_array( $existing_option ) ) { | |
| 1466 | + $has_timestamp = isset( $existing_option[ $option_key ] ) && is_numeric( $existing_option[ $option_key ] ); | |
| 1467 | + } elseif ( is_numeric( $existing_option ) ) { | |
| 1468 | + $has_timestamp = true; | |
| 1469 | + } | |
| 1470 | + | |
| 1471 | + // Only set timestamp if one doesn't already exist | |
| 1472 | + if ( ! $has_timestamp ) { | |
| 1473 | + if ( is_array( $existing_option ) ) { | |
| 1474 | + $existing_option[ $option_key ] = $current_time; | |
| 1475 | + update_option( $option_name, $existing_option ); | |
| 1476 | + } else { | |
| 1477 | + update_option( $option_name, array( $option_key => $current_time ) ); | |
| 1478 | + } | |
| 1479 | + } | |
| 1480 | + } | |
| 1481 | + } | |
| 952 | 1482 | } |
| 953 | 1483 | } |
| 954 | 1484 | |
| 955 | 1485 | $charitable = new Charitable(); |