PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13.1 1.8.13 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 All 212 releases
← All changes | includes/gateways/class-charitable-gateways.php +1157 -82 1.7.0 → 1.8.13 View file →
@@ -3,12 +3,13 @@
3 3 * Class that sets up the gateways.
4 4 *
5 5 * @package Charitable/Classes/Charitable_Gateways
6 6 * @author David Bisset
7 - * @copyright Copyright (c) 2022, WP Charitable LLC
7 + * @copyright Copyright (c) 2023, WP Charitable LLC
8 8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 9 * @since 1.0.0
10 10 * @version 1.6.57
11 + * @version 1.8.7 - Added Square.
11 12 */
12 13
13 14 // Exit if accessed directly.
14 15 if ( ! defined( 'ABSPATH' ) ) {
@@ -51,12 +52,13 @@
51 52 *
52 53 * @since 1.0.0
53 54 */
54 55 protected function __construct() {
55 - add_action( 'init', array( $this, 'check_settings' ) );
56 - add_action( 'init', array( $this, 'register_gateways' ) );
57 - add_action( 'init', array( $this, 'connect_gateways' ), 99 );
58 - add_action( 'init', array( $this, 'disconnect_gateways' ), 99 );
56 + add_action( 'init', array( $this, 'check_settings' ), 10 );
57 + add_action( 'init', array( $this, 'register_gateways' ), 1 );
58 + add_action( 'init', array( $this, 'connect_gateways' ), 99 ); // Stripe.
59 + add_action( 'init', array( $this, 'disconnect_gateways' ), 99 ); // Stripe.
60 +
59 61 add_action( 'charitable_make_default_gateway', array( $this, 'handle_gateway_settings_request' ) );
60 62 add_action( 'charitable_enable_gateway', array( $this, 'handle_gateway_settings_request' ) );
61 63 add_action( 'charitable_disable_gateway', array( $this, 'handle_gateway_settings_request' ) );
62 64 add_filter( 'charitable_settings_fields_gateways_gateway', array( $this, 'register_gateway_settings' ), 10, 2 );
@@ -62,14 +64,32 @@
62 64 add_filter( 'charitable_settings_fields_gateways_gateway', array( $this, 'register_gateway_settings' ), 10, 2 );
63 65
64 66 add_action( 'charitable_disable_gateway', array( $this, 'handle_gateway_settings_request' ) );
65 67
68 + /**
69 + * Square Connect
70 + */
71 + add_action( 'init', array( $this, 'disconnect_gateways_square' ), 99 ); // Square.
72 + add_action( 'init', array( $this, 'refresh_square_token' ), 99 ); // Square.
73 +
74 + add_action( 'init', array( $this, 'get_gateway_error_message' ), 99 );
75 +
66 76 do_action( 'charitable_gateway_start', $this );
67 77
68 - add_action( 'wp_ajax_charitable-show-stripe-keys', array( $this, 'show_stripe_manual_keys_ajax'), 10 );
78 + add_action( 'wp_ajax_charitable-show-stripe-keys', array( $this, 'show_stripe_manual_keys_ajax' ), 10 );
79 + add_action( 'wp_ajax_charitable_switch_square_gateways', array( $this, 'handle_square_gateway_switch' ) );
80 + add_action( 'wp_ajax_charitable_switch_square_core_to_legacy', array( $this, 'handle_square_core_to_legacy_switch' ) );
69 81
82 + // Dequeue Square Legacy scripts if Square Legacy is not active.
83 + add_action( 'wp_enqueue_scripts', array( $this, 'maybe_dequeue_square_legacy_scripts' ), 999 );
84 +
85 + // PayPal Hard Fork (1.8.11): last-word defense against third-party
86 + // callbacks that re-inject the hidden PayPal gateway. Mirrors the
87 + // register_gateways + get_active_gateways strips.
88 + add_filter( 'charitable_active_gateways', array( $this, 'apply_paypal_tier_visibility' ), PHP_INT_MAX );
70 89 }
71 90
91 +
72 92 /**
73 93 * Returns and/or create the single instance of this class.
74 94 *
75 95 * @since 1.2.0
@@ -97,25 +117,90 @@
97 117 public function register_gateways() {
98 118 /**
99 119 * Filter the list of payment gateways.
100 120 *
101 - * @since 1.2.0
121 + * @since 1.2.0
122 + * @version 1.8.7
102 123 *
103 124 * @param array $gateways The list of gateways in gateway ID => gateway class format.
104 125 */
126 +
127 + $gateways = array(
128 + 'stripe' => 'Charitable_Gateway_Stripe_AM',
129 + 'paypal' => 'Charitable_Gateway_Paypal',
130 + 'paypal_commerce' => 'Charitable_Gateway_Paypal_Commerce',
131 + 'offline' => 'Charitable_Gateway_Offline',
132 + );
133 +
134 + // Always add Square Core to the available gateways.
135 + $gateways['square_core'] = 'Charitable_Gateway_Square';
136 +
105 137 $this->gateways = apply_filters(
106 138 'charitable_payment_gateways',
107 - array(
108 - 'stripe' => 'Charitable_Gateway_Stripe_AM',
109 - 'paypal' => 'Charitable_Gateway_Paypal',
110 - 'offline' => 'Charitable_Gateway_Offline',
111 - )
139 + $gateways
112 140 );
113 - $this->gateways['stripe'] = 'Charitable_Gateway_Stripe_AM';
114 141
142 + // PayPal Hard Fork (1.8.11): hide the off-tier PayPal gateway entirely so it
143 + // cannot be enabled, listed in admin, or referenced in active_gateways.
144 + $this->gateways = $this->apply_paypal_tier_visibility( $this->gateways );
145 +
146 + // If Legacy mode is active and Square Legacy gateway is active, deactivate Square Core.
147 + if ( charitable_square_legacy_mode() && $this->is_active_gateway( 'square' ) ) {
148 + $this->disable_gateway( 'square_core' );
149 +
150 + if ( charitable_is_debug( 'square' ) ) {
151 + error_log( '[Charitable Square Core] Deactivated Square Core because Square Legacy is active' ); // phpcs:ignore
152 + }
153 + }
115 154 }
116 155
117 156 /**
157 + * Read the locked PayPal user tier set by the 1.8.11 detection upgrade.
158 + *
159 + * The result is escapable at runtime via the standard `pre_option_*` filter
160 + * (`pre_option_charitable_paypal_user_tier`) since this is a vanilla `get_option`
161 + * read. See `Charitable_Upgrade::detect_paypal_user_tier()` for how the value
162 + * is computed and persisted.
163 + *
164 + * @since 1.8.11
165 + *
166 + * @return string `legacy` or `commerce`. Defaults to `commerce` when unset.
167 + */
168 + public function get_paypal_tier() {
169 + $tier = get_option( 'charitable_paypal_user_tier', 'commerce' );
170 + return ( 'legacy' === $tier ) ? 'legacy' : 'commerce';
171 + }
172 +
173 + /**
174 + * Strip the off-tier PayPal gateway from a gateways map.
175 + *
176 + * `legacy` tier hides `paypal_commerce`. `commerce` tier hides `paypal`.
177 + * Used in three places to layer defense:
178 + * 1. `register_gateways()` — strips before `$this->gateways` is exposed.
179 + * 2. `get_active_gateways()` — inline cleanup mirroring the Square pattern.
180 + * 3. `charitable_active_gateways` filter (PHP_INT_MAX priority) — last word
181 + * against third-party callbacks that re-inject the hidden gateway.
182 + *
183 + * @since 1.8.11
184 + *
185 + * @param array $gateways Map of gateway_id => class_name (or anything keyed by id).
186 + * @return array Same shape, with the off-tier PayPal key removed when present.
187 + */
188 + public function apply_paypal_tier_visibility( $gateways ) {
189 + if ( ! is_array( $gateways ) ) {
190 + return $gateways;
191 + }
192 +
193 + if ( 'legacy' === $this->get_paypal_tier() ) {
194 + unset( $gateways['paypal_commerce'] );
195 + } else {
196 + unset( $gateways['paypal'] );
197 + }
198 +
199 + return $gateways;
200 + }
201 +
202 + /**
118 203 * Receives a request to enable or disable a payment gateway and validates it before passing it off.
119 204 *
120 205 * @since 1.0.0
121 206 *
@@ -121,25 +206,29 @@
121 206 *
122 207 * @return void
123 208 */
124 209 public function handle_gateway_settings_request() {
125 - if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'gateway' ) ) {
126 - wp_die( __( 'Cheatin\' eh?!', 'charitable' ) );
210 + // phpcs:disable WordPress.Security.NonceVerification.Missing
211 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- wp_verify_nonce handles validation
212 + if ( ! isset( $_REQUEST['_nonce'] ) || ! wp_verify_nonce( wp_unslash( $_REQUEST['_nonce'] ), 'gateway' ) ) {
213 + wp_die( __( 'Cheatin\' eh?!', 'charitable' ) ); // phpcs:ignore
127 214 }
128 215
129 - $gateway = isset( $_REQUEST['gateway_id'] ) ? $_REQUEST['gateway_id'] : false;
216 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Gateway ID, sanitized below
217 + $gateway = isset( $_REQUEST['gateway_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['gateway_id'] ) ) : false;
218 + // phpcs:enable WordPress.Security.NonceVerification.Missing
130 219
131 220 /* Gateway must be set */
132 221 if ( false === $gateway ) {
133 - wp_die( __( 'Missing gateway.', 'charitable' ) );
222 + wp_die( __( 'Missing gateway.', 'charitable' ) ); // phpcs:ignore
134 223 }
135 224
136 225 /* Validate gateway. */
137 226 if ( ! isset( $this->gateways[ $gateway ] ) ) {
138 - wp_die( __( 'Invalid gateway.', 'charitable' ) );
227 + wp_die( __( 'Invalid gateway.', 'charitable' ) ); // phpcs:ignore
139 228 }
140 229
141 - switch ( $_REQUEST['charitable_action'] ) {
230 + switch ( $_REQUEST['charitable_action'] ) { // phpcs:ignore
142 231 case 'disable_gateway':
143 232 $this->disable_gateway( $gateway );
144 233 break;
145 234 case 'enable_gateway':
@@ -157,11 +246,10 @@
157 246 *
158 247 * @param string $action The action taking place.
159 248 * @param string $gateway_id The gateway ID.
160 249 */
161 - do_action( 'charitable_gateway_settings_request', $_REQUEST['charitable_action'], $gateway );
250 + do_action( 'charitable_gateway_settings_request', $_REQUEST['charitable_action'], $gateway ); // phpcs:ignore
162 251 }
163 -
164 252 }
165 253
166 254 /**
167 255 * Returns all available payment gateways.
@@ -186,8 +274,11 @@
186 274 */
187 275 public function get_active_gateways() {
188 276 $active_gateways = charitable_get_option( 'active_gateways', array() );
189 277
278 + // Force cleanup of 'square' gateway if charitable-square plugin is not active (runs once per 24 hours).
279 + $this->maybe_force_cleanup_square_gateway( $active_gateways );
280 +
190 281 foreach ( $active_gateways as $gateway_id => $gateway_class ) {
191 282 if ( ! class_exists( $gateway_class ) ) {
192 283 unset( $active_gateways[ $gateway_id ] );
193 284 }
@@ -192,12 +283,23 @@
192 283 unset( $active_gateways[ $gateway_id ] );
193 284 }
194 285 }
195 286
287 + // Remove 'square' gateway if charitable-square plugin is not active.
288 + if ( isset( $active_gateways['square'] ) && ! $this->is_square_addon_active() ) {
289 + unset( $active_gateways['square'] );
290 + }
291 +
292 + // PayPal Hard Fork (1.8.11): strip the off-tier PayPal gateway in case both
293 + // were saved into active_gateways (direct DB edit, multisite weirdness, etc.).
294 + $active_gateways = $this->apply_paypal_tier_visibility( $active_gateways );
295 +
196 296 uksort( $active_gateways, array( $this, 'sort_by_default' ) );
197 297
198 298 // force the strip active gateway normally for stripe addon to point to the stripe built into core.
199 - $active_gateways['stripe'] = 'Charitable_Gateway_Stripe_AM';
299 + if ( isset( $active_gateways['stripe'] ) ) {
300 + $active_gateways['stripe'] = 'Charitable_Gateway_Stripe_AM';
301 + }
200 302
201 303 /**
202 304 * Filter the list of active gateways.
203 305 *
@@ -220,9 +322,9 @@
220 322 public function get_gateway_choices() {
221 323 $gateways = array();
222 324
223 325 foreach ( $this->get_active_gateways() as $id => $class ) {
224 - $gateway = new $class;
326 + $gateway = new $class();
225 327 $gateways[ $id ] = $gateway->get_label();
226 328 }
227 329
228 330 return $gateways;
@@ -238,9 +340,9 @@
238 340 public function get_active_gateways_names() {
239 341 $gateways = array();
240 342
241 343 foreach ( $this->get_active_gateways() as $id => $class ) {
242 - $gateway = new $class;
344 + $gateway = new $class();
243 345 $gateways[] = $gateway->get_name();
244 346 }
245 347
246 348 return $gateways;
@@ -267,9 +369,9 @@
267 369 * @return Charitable_Gateway|null
268 370 */
269 371 public function get_gateway_object( $gateway ) {
270 372 $class = $this->get_gateway( $gateway );
271 - $object = $class ? new $class : null;
373 + $object = $class ? new $class() : null;
272 374
273 375 /**
274 376 * Filter the gateway object.
275 377 *
@@ -309,12 +411,14 @@
309 411 * @param boolean $valid Whether a gateway is valid.
310 412 * @param string $gateway The gateway ID.
311 413 */
312 414
313 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
415 + if ( charitable_is_debug( 'webhook' ) ) {
416 + // phpcs:disable
314 417 error_log( 'is_valid_gateway' );
315 418 error_log( print_r( $gateway, true ) );
316 419 error_log( print_r( $this->gateways, true ) );
420 + // phpcs:enable
317 421 }
318 422
319 423 return apply_filters( 'charitable_is_valid_gateway', array_key_exists( $gateway, $this->gateways ), $gateway );
320 424 }
@@ -385,9 +489,9 @@
385 489 */
386 490 public function all_gateways_support( $feature ) {
387 491 foreach ( $this->get_active_gateways() as $gateway_id => $gateway_class ) {
388 492
389 - $gateway_object = new $gateway_class;
493 + $gateway_object = new $gateway_class();
390 494
391 495 if ( false === $gateway_object->supports( $feature ) ) {
392 496 return false;
393 497 }
@@ -408,9 +512,9 @@
408 512 */
409 513 public function any_gateway_supports( $feature ) {
410 514 foreach ( $this->get_active_gateways() as $gateway_id => $gateway_class ) {
411 515
412 - $gateway_object = new $gateway_class;
516 + $gateway_object = new $gateway_class();
413 517
414 518 if ( true === $gateway_object->supports( $feature ) ) {
415 519 return true;
416 520 }
@@ -523,15 +627,26 @@
523 627 *
524 628 * @since 1.0.0
525 629 *
526 630 * @param string $gateway Gateway ID.
631 + * @param bool $show_update_message Whether to show the update message.
527 632 * @return void
528 633 */
529 - protected function enable_gateway( $gateway ) {
634 + protected function enable_gateway( $gateway, $show_update_message = true ) {
530 635 $settings = get_option( 'charitable_settings' );
531 636
637 + if ( false === $settings || ! is_array( $settings ) ) {
638 + echo 'settings is false';
639 + $settings = array();
640 + }
641 +
532 642 $active_gateways = isset( $settings['active_gateways'] ) ? $settings['active_gateways'] : array();
533 643 $active_gateways[ $gateway ] = $this->gateways[ $gateway ];
644 +
645 + if ( ! isset( $settings['active_gateways'] ) ) {
646 + $settings['active_gateways'] = array();
647 + }
648 +
534 649 $settings['active_gateways'] = $active_gateways;
535 650
536 651 /* If this is the only gateway, make it the default gateway */
537 652 if ( 1 == count( $settings['active_gateways'] ) ) {
@@ -539,9 +654,11 @@
539 654 }
540 655
541 656 update_option( 'charitable_settings', $settings );
542 657
543 - Charitable_Settings::get_instance()->add_update_message( __( 'Gateway enabled', 'charitable' ), 'success' );
658 + if ( $show_update_message ) {
659 + Charitable_Settings::get_instance()->add_update_message( __( 'Gateway enabled', 'charitable' ), 'success' );
660 + }
544 661
545 662 /**
546 663 * Do something when a payment gateway is enabled.
547 664 *
@@ -592,9 +709,10 @@
592 709
593 710 /**
594 711 * Connects to Stripe by saving account information passed back to the plugin.
595 712 *
596 - * @since 4.2.2
713 + * @since 4.2.2
714 + * @version 1.8.9
597 715 *
598 716 * @return void
599 717 */
600 718 public function connect_gateways() {
@@ -604,11 +722,11 @@
604 722 }
605 723
606 724 // Do not need to handle this request, bail.
607 725 if (
608 - ! isset( $_GET['wpcharitable_gateway_connect_completion'] ) ||
609 - 'stripe_connect' !== $_GET['wpcharitable_gateway_connect_completion'] ||
610 - ! isset( $_GET['state'] )
726 + ! isset( $_GET['wpcharitable_gateway_connect_completion'] ) || // phpcs:ignore
727 + 'stripe_connect' !== $_GET['wpcharitable_gateway_connect_completion'] || // phpcs:ignore
728 + ! isset( $_GET['state'] ) // phpcs:ignore
611 729 ) {
612 730 return;
613 731 }
614 732
@@ -616,10 +734,11 @@
616 734 if ( headers_sent() ) {
617 735 return;
618 736 }
619 737
620 - if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
621 - $current_url = ( is_ssl() ? 'https' : 'http' ) . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
738 + if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Server variables for URL construction
739 + $current_url = ( is_ssl() ? 'https' : 'http' ) . '://' . wp_unslash( $_SERVER['HTTP_HOST'] ) . wp_unslash( $_SERVER['REQUEST_URI'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Server variables are unslashed and then sanitized via esc_url_raw()
740 + $current_url = esc_url_raw( $current_url ); // phpcs:ignore
622 741 } else {
623 742 $current_url = '';
624 743 }
625 744
@@ -625,9 +744,9 @@
625 744
626 745 $customer_site_url = remove_query_arg(
627 746 array(
628 747 'state',
629 - 'wpcharitable_gateway_connect_completion'
748 + 'wpcharitable_gateway_connect_completion',
630 749 ),
631 750 $current_url
632 751 );
633 752
@@ -632,16 +751,17 @@
632 751 );
633 752
634 753 $wpcharitable_credentials_url = add_query_arg(
635 754 array(
636 - 'live_mode' => (int) ! charitable_get_option( 'test_mode' ), // (int) ! $this->is_test_mode(),
637 - 'state' => sanitize_text_field( $_GET['state'] ),
755 + 'live_mode' => (int) ! charitable_get_option( 'test_mode' ),
756 + 'state' => sanitize_text_field( $_GET['state'] ), // phpcs:ignore
638 757 'customer_site_url' => urlencode( $customer_site_url ),
639 758 ),
640 - 'https://wpcharitable.com/stripe-connect/?wpcharitable_gateway_connect_credentials=stripe_connect' // todo: filter market site url
759 + 'https://wpcharitable.com/stripe-connect/?wpcharitable_gateway_connect_credentials=stripe_connect'
641 760 );
642 761
643 - $response = wp_remote_get( esc_url_raw( $wpcharitable_credentials_url ) ); // add add_filter('https_ssl_verify', '__return_false'); here if testing local
762 + // You might need to add add_filter('https_ssl_verify', '__return_false'); here if testing locally.
763 + $response = wp_remote_get( esc_url_raw( $wpcharitable_credentials_url ) );
644 764
645 765 if (
646 766 is_wp_error( $response ) ||
647 767 200 !== wp_remote_retrieve_response_code( $response )
@@ -646,8 +766,21 @@
646 766 is_wp_error( $response ) ||
647 767 200 !== wp_remote_retrieve_response_code( $response )
648 768 ) {
649 769
770 + // Log error details for debugging.
771 + if ( is_wp_error( $response ) ) {
772 + if ( charitable_is_debug( 'stripe' ) ) {
773 + error_log( 'Charitable Stripe Connect Error: ' . $response->get_error_message() . ' | URL: ' . $wpcharitable_credentials_url ); // phpcs:ignore
774 + }
775 + } else {
776 + $response_code = wp_remote_retrieve_response_code( $response );
777 + $response_body = wp_remote_retrieve_body( $response );
778 + if ( charitable_is_debug( 'stripe' ) ) {
779 + error_log( 'Charitable Stripe Connect Error: HTTP ' . $response_code . ' | URL: ' . $wpcharitable_credentials_url . ' | Response: ' . substr( $response_body, 0, 500 ) ); // phpcs:ignore
780 + }
781 + }
782 +
650 783 $stripe_account_settings_url = add_query_arg(
651 784 array(
652 785 'tab' => 'gateways',
653 786 'page' => 'charitable-settings',
@@ -660,9 +793,9 @@
660 793 sprintf(
661 794 /* translators: %1$s Opening anchor tag, do not translate. %2$s Closing anchor tag, do not translate. */
662 795 __(
663 796 'There was an error getting your Stripe credentials. Please %1$stry again%2$s. If you continue to have this problem, please contact support.',
664 - 'stripe'
797 + 'charitable'
665 798 ),
666 799 '<a href="' . esc_url( $stripe_account_settings_url ) . '">',
667 800 '</a>'
668 801 )
@@ -667,9 +800,9 @@
667 800 '</a>'
668 801 )
669 802 );
670 803
671 - wp_die( $message );
804 + wp_die( $message ); // phpcs:ignore
672 805 }
673 806
674 807 $body = wp_remote_retrieve_body( $response );
675 808
@@ -690,25 +823,322 @@
690 823 * @since 3.6.0
691 824 *
692 825 * @param array $data Stripe response data.
693 826 */
694 - do_action( 'wpcharitable_stripe_account_connected', $account_data );
827 + do_action( 'wpcharitable_stripe_account_connected', $account_data ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- This is a legacy hook used by other Charitable code. Changing it would break existing functionality.
695 828
696 - // If you configure Stripe and the offline gateway is the default gateway, after you have connected successfully with Stripe, it should automatically be set as the default gateway.
697 - if ( false === $this->get_default_gateway() || 'offline' === $this->get_default_gateway() ) {
698 - $this->set_default_gateway( 'stripe' );
829 + wp_safe_redirect( esc_url_raw( $customer_site_url ) );
830 + exit;
831 + }
832 +
833 + /**
834 + * Refreshes the Square token.
835 + *
836 + * @since 1.8.7
837 + *
838 + * @return void
839 + */
840 + public function refresh_square_token() {
841 + // Current user cannot handle this request.
842 + if ( ! current_user_can( 'manage_options' ) || charitable_square_legacy_mode() ) {
843 + return;
699 844 }
700 845
701 - wp_redirect( esc_url_raw( $customer_site_url ) );
846 + // Do not need to handle this request, bail.
847 + if (
848 + ! isset( $_GET['wpcharitable_gateway_refresh_token_completion'] ) || // phpcs:ignore
849 + 'square_connect' !== $_GET['wpcharitable_gateway_refresh_token_completion'] || // phpcs:ignore
850 + ! isset( $_GET['state'] ) // phpcs:ignore
851 + ) {
852 + return;
853 + }
854 +
855 + // Unable to redirect, bail.
856 + if ( headers_sent() ) {
857 + return;
858 + }
859 +
860 + if ( charitable_is_debug( 'square' ) ) {
861 + error_log( 'checking for use: refresh_square_token' ); // phpcs:ignore
862 + }
863 +
864 + if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
865 + $current_url = ( is_ssl() ? 'https' : 'http' ) . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; // phpcs:ignore
866 + } else {
867 + $current_url = '';
868 + }
869 +
870 + $customer_site_url = remove_query_arg(
871 + array(
872 + 'state',
873 + 'wpcharitable_gateway_refresh_token_completion',
874 + 'message',
875 + ),
876 + $current_url
877 + );
878 +
879 + $wpcharitable_credentials_url = add_query_arg(
880 + array(
881 + 'live_mode' => (int) ! charitable_get_option( 'test_mode' ),
882 + 'state' => sanitize_text_field( $_GET['state'] ), // phpcs:ignore
883 + 'code' => 'request_credentials',
884 + 'customer_site_url' => urlencode( $customer_site_url ),
885 + ),
886 + 'https://connect.wpcharitable.com/square-connect/'
887 + );
888 +
889 + $response = wp_remote_get( esc_url_raw( $wpcharitable_credentials_url ) );
890 +
891 + if (
892 + is_wp_error( $response ) ||
893 + 200 !== wp_remote_retrieve_response_code( $response )
894 + ) {
895 +
896 + $square_account_settings_url = add_query_arg(
897 + array(
898 + 'tab' => 'gateways',
899 + 'page' => 'charitable-settings',
900 + 'group' => 'gateways_square_core',
901 + ),
902 + admin_url( 'admin.php' )
903 + );
904 +
905 + $message = wpautop(
906 + sprintf(
907 + /* translators: %1$s Opening anchor tag, do not translate. %2$s Closing anchor tag, do not translate. */
908 + __(
909 + 'There was an error getting your Square credentials. Please %1$stry again%2$s. If you continue to have this problem, please contact support.',
910 + 'charitable'
911 + ),
912 + '<a href="' . esc_url( $square_account_settings_url ) . '">',
913 + '</a>'
914 + )
915 + );
916 +
917 + wp_die( $message ); // phpcs:ignore
918 + }
919 +
920 + $body = wp_remote_retrieve_body( $response );
921 +
922 + $body = json_decode( $body, true );
923 +
924 + $account_data = $body['data'];
925 +
926 + $this->save_account_information_square( $account_data );
927 +
928 + // Don't show the success message if we are on the welcome / getting started page (otherwise it's fine).
929 + if ( ! isset( $_GET['page'] ) || 'charitable-getting-started' !== $_GET['page'] ) { // phpcs:ignore
930 + // translators: %s is the mode of the connection.
931 + charitable_get_admin_notices()->add_success( sprintf( __( 'You have reconnected and updated your access token for Square in %s mode.', 'charitable' ), charitable_get_option( 'test_mode' ) ? 'test' : 'live' ) );
932 + }
933 +
934 + // update the option to track that we are using square connect.
935 + // Get the value and update it.
936 + $charitable_using_square_connect = get_option( 'charitable_using_square_connect', array() );
937 + if ( ! is_array( $charitable_using_square_connect ) ) {
938 + $charitable_using_square_connect = array();
939 + }
940 + $charitable_using_square_connect['test'] = time();
941 + update_option( 'charitable_using_square_connect', $charitable_using_square_connect );
942 +
943 + /**
944 + * Allow further processing after reconnecting a Square account.
945 + *
946 + * @since 3.6.0
947 + *
948 + * @param array $data Square response data.
949 + */
950 + do_action( 'wpcharitable_square_token_refreshed', $account_data ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- This is a legacy hook used by other Charitable code. Changing it would break existing functionality.
951 +
952 + wp_safe_redirect( esc_url_raw( $customer_site_url ) );
702 953 exit;
703 954 }
704 955
705 956 /**
957 + * Schedule the Square token renewal cron job.
958 + *
959 + * @since 1.8.7
960 + *
961 + * @param string $mode The mode to schedule the cron for (test/live).
962 + * @return void
963 + */
964 + private function schedule_square_token_renewal_cron( $mode ) {
965 + // Clear any existing cron jobs for this mode.
966 + wp_clear_scheduled_hook( 'charitable_square_token_renewal', array( $mode ) );
967 +
968 + // Schedule the cron job to run every 14 days.
969 + wp_schedule_event( time() + ( 14 * DAY_IN_SECONDS ), '14days', 'charitable_square_token_renewal', array( $mode ) );
970 + }
971 +
972 + /**
973 + * Renew the Square token via cron job.
974 + *
975 + * @since 1.8.7
976 + *
977 + * @param string $mode The mode to renew the token for (test/live).
978 + * @return void
979 + */
980 + public function renew_square_token_cron( $mode ) {
981 + if ( charitable_is_debug( 'square' ) ) {
982 + // phpcs:disable
983 + error_log( 'renew_square_token_cron for test mode: ' . $mode );
984 + // phpcs:enable
985 + }
986 +
987 + // Get the URL to renew the token.
988 + $url = Charitable_Gateway_Square::get_instance()->get_square_renew_token_url( '', true );
989 +
990 + if ( charitable_is_debug( 'square' ) ) {
991 + // phpcs:disable
992 + error_log( 'url: ' . $url );
993 + // phpcs:enable
994 + }
995 +
996 + // Clear both failed and success options.
997 + delete_option( 'wpcharitable_square_failed_token_renewal_' . $mode );
998 + delete_option( 'wpcharitable_square_token_refreshed_' . $mode );
999 +
1000 + if ( empty( $url ) ) {
1001 + update_option( 'wpcharitable_square_failed_token_renewal_' . $mode, time() );
1002 + return;
1003 + }
1004 +
1005 + // Add SSL verification argsget_square_renew_token_url.
1006 + $args = array(
1007 + 'timeout' => 30,
1008 + 'sslverify' => false, // Temporarily disable SSL verification.
1009 + 'headers' => array(
1010 + 'Content-Type' => 'application/json',
1011 + ),
1012 + );
1013 +
1014 + // Make the request to the proxy server.
1015 + $response = wp_remote_get( esc_url_raw( $url ), $args );
1016 +
1017 + if ( charitable_is_debug( 'square' ) ) {
1018 + // phpcs:disable
1019 + error_log( 'response: ' . print_r( $response, true ) );
1020 + // phpcs:enable
1021 + }
1022 +
1023 + if ( is_wp_error( $response ) ) {
1024 + if ( charitable_is_debug( 'square' ) ) {
1025 + // phpcs:disable
1026 + error_log( 'The cron job url has failed with a wp_error: ' . $response->get_error_message() );
1027 + // phpcs:enable
1028 + }
1029 + update_option( 'wpcharitable_square_failed_token_renewal_' . $mode, time() );
1030 + return;
1031 + }
1032 +
1033 + $response_code = wp_remote_retrieve_response_code( $response );
1034 + if ( 200 !== $response_code ) {
1035 + if ( charitable_is_debug( 'square' ) ) {
1036 + // phpcs:disable
1037 + error_log( 'The cron job url has failed with response code: ' . $response_code );
1038 + // phpcs:enable
1039 + }
1040 + update_option( 'wpcharitable_square_failed_token_renewal_' . $mode, time() );
1041 + return;
1042 + }
1043 +
1044 + $body = wp_remote_retrieve_body( $response );
1045 + $data = json_decode( $body, true );
1046 +
1047 + if ( charitable_is_debug( 'square' ) ) {
1048 + // phpcs:disable
1049 + error_log( 'data: ' . print_r( $data, true ) );
1050 + error_log( 'body: ' . print_r( $body, true ) );
1051 + // phpcs:enable
1052 + }
1053 +
1054 + if ( empty( $data ) || ! isset( $data['data'] ) ) {
1055 + if ( charitable_is_debug( 'square' ) ) {
1056 + // phpcs:disable
1057 + error_log( 'The cron job url has failed - no data returned.' );
1058 + // phpcs:enable
1059 + }
1060 + update_option( 'wpcharitable_square_failed_token_renewal_' . $mode, time() );
1061 + return;
1062 + }
1063 +
1064 + // Update the stored tokens.
1065 + $settings = get_option( 'charitable_settings' );
1066 + $settings['gateways_square'][ $mode ]['access_token'] = isset( $data['data']['access_token'] ) ? sanitize_text_field( $data['data']['access_token'] ) : false;
1067 + $settings['gateways_square'][ $mode ]['refresh_token'] = isset( $data['data']['refresh_token'] ) ? sanitize_text_field( $data['data']['refresh_token'] ) : false;
1068 + $settings['gateways_square'][ $mode ]['token_refresh_date'] = time();
1069 +
1070 + update_option( 'charitable_settings', $settings );
1071 +
1072 + // Clear any failure notices.
1073 + delete_option( 'wpcharitable_square_failed_token_renewal_' . $mode );
1074 +
1075 + // Add a success notice.
1076 + update_option( 'wpcharitable_square_token_refreshed_' . $mode, time() );
1077 +
1078 + if ( charitable_is_debug( 'square' ) ) {
1079 + // phpcs:disable
1080 + error_log( 'wpcharitable_square_token_refreshed_' . $mode . ' updated to: ' . time() );
1081 + // phpcs:enable
1082 + }
1083 + }
1084 +
1085 + /**
1086 + * Saves the account information sent back from Square, alongside other, to identify the connected account.
1087 + *
1088 + * @since 1.8.7
1089 + *
1090 + * @param array<string> $data Square oAuth account data.
1091 + * @param string $gateway_id The gateway ID.
1092 + * @return void
1093 + */
1094 + private function save_account_information_square( $data, $gateway_id = 'square' ) {
1095 + if ( charitable_is_debug( 'square' ) ) {
1096 + // phpcs:disable
1097 + error_log( 'save_account_information_square' );
1098 + error_log( print_r( $data, true ) );
1099 + // phpcs:enable
1100 + }
1101 +
1102 + $mode = $this->in_test_mode()
1103 + ? 'test'
1104 + : 'live';
1105 +
1106 + $settings = get_option( 'charitable_settings' );
1107 +
1108 + $settings[ 'gateways_' . $gateway_id ][ $mode ]['access_token'] = isset( $data['access_token'] ) ? sanitize_text_field( $data['access_token'] ) : false;
1109 + $settings[ 'gateways_' . $gateway_id ][ $mode ]['refresh_token'] = isset( $data['refresh_token'] ) ? sanitize_text_field( $data['refresh_token'] ) : false;
1110 + $settings[ 'gateways_' . $gateway_id ][ $mode ]['merchant_id'] = isset( $data['merchant_id'] ) ? sanitize_text_field( $data['merchant_id'] ) : false;
1111 + $settings[ 'gateways_' . $gateway_id ][ $mode ]['location_id'] = isset( $data['location_id'] ) ? sanitize_text_field( $data['location_id'] ) : false;
1112 + $settings[ 'gateways_' . $gateway_id ][ $mode ]['token_refresh_date'] = time();
1113 +
1114 + update_option( 'charitable_settings', $settings );
1115 +
1116 + // We save the AES key in it's own WordPress options field, marked as 'charitable_square_aes_key_test' or 'charitable_square_aes_key_live'.
1117 + $aes_key = isset( $data['aes_key'] ) ? sanitize_text_field( $data['aes_key'] ) : false;
1118 +
1119 + if ( charitable_is_debug( 'square' ) ) {
1120 + // phpcs:disable
1121 + error_log( 'aes_key: ' . $aes_key );
1122 + // phpcs:enable
1123 + }
1124 +
1125 + update_option( 'charitable_square_aes_key_' . $mode, $aes_key );
1126 +
1127 + // Schedule the token renewal cron job.
1128 + $this->schedule_square_token_renewal_cron( $mode );
1129 +
1130 + do_action( 'charitable_save_account_information_gateway_' . $gateway_id, $settings, $data, $gateway_id );
1131 + }
1132 +
1133 + /**
706 1134 * Saves the account information sent back from Stripe, alongside other, to identify the connected account.
707 1135 *
708 1136 * @since 4.4.2
1137 + * @version 1.8.1.12
709 1138 *
710 1139 * @param array<string> $data Stripe oAuth account data.
1140 + * @param string $gateway_id The gateway ID.
711 1141 * @return void
712 1142 */
713 1143 private function save_account_information( $data, $gateway_id = 'stripe' ) {
714 1144
@@ -717,27 +1147,31 @@
717 1147 : 'live';
718 1148
719 1149 $settings = get_option( 'charitable_settings' );
720 1150
721 - $settings['gateways_' . $gateway_id ]['live_secret_key'] = '';
722 - $settings['gateways_' . $gateway_id ]['live_public_key'] = '';
723 - $settings['gateways_' . $gateway_id ]['test_secret_key'] = '';
724 - $settings['gateways_' . $gateway_id ]['test_public_key'] = '';
1151 + $settings[ 'gateways_' . $gateway_id ]['live_secret_key'] = '';
1152 + $settings[ 'gateways_' . $gateway_id ]['live_public_key'] = '';
1153 + $settings[ 'gateways_' . $gateway_id ]['test_secret_key'] = '';
1154 + $settings[ 'gateways_' . $gateway_id ]['test_public_key'] = '';
725 1155
726 - $settings['gateways_' . $gateway_id ][ $prefix . '_secret_key' ] = isset( $data['secret_key'] ) ? sanitize_text_field( $data['secret_key'] ) : false;
727 - $settings['gateways_' . $gateway_id ][ $prefix . '_public_key' ] = isset( $data['publishable_key'] ) ? sanitize_text_field( $data['publishable_key'] ) : false;
1156 + $settings[ 'gateways_' . $gateway_id ][ $prefix . '_secret_key' ] = isset( $data['secret_key'] ) ? sanitize_text_field( $data['secret_key'] ) : false;
1157 + $settings[ 'gateways_' . $gateway_id ][ $prefix . '_public_key' ] = isset( $data['publishable_key'] ) ? sanitize_text_field( $data['publishable_key'] ) : false;
728 1158
729 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
1159 + if ( charitable_is_debug( 'webhook' ) ) {
1160 + // phpcs:disable
730 1161 error_log( 'save_account_information' );
731 1162 error_log( print_r( $settings, true ) );
1163 + // phpcs:enable
732 1164 }
733 1165
734 1166 update_option( 'charitable_settings', $settings );
735 1167
736 - charitable_get_admin_notices()->add_success( __( 'Stripe Information Updated', 'charitable' ) );
1168 + // Don't show the success message if we are on the welcome / getting started page (otherwise it's fine).
1169 + if ( ! isset( $_GET['page'] ) || 'charitable-getting-started' !== $_GET['page'] ) { // phpcs:ignore
1170 + charitable_get_admin_notices()->add_success( __( 'Stripe Information Updated', 'charitable' ) );
1171 + }
737 1172
738 1173 do_action( 'charitable_save_account_information_gateway_' . $gateway_id, $settings, $data, $gateway_id );
739 -
740 1174 }
741 1175
742 1176 /**
743 1177 * Disconnects from Stripe by removing associated account information.
@@ -762,23 +1196,25 @@
762 1196 if ( ! current_user_can( 'manage_options' ) ) {
763 1197 return;
764 1198 }
765 1199
1200 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display/routing parameter
766 1201 if ( ! isset( $_GET['_wpnonce'] ) ) {
767 1202 return;
768 1203 }
769 1204
770 1205 // Invalid nonce, bail.
771 - if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'wpcharitable-stripe-connect-disconnect' ) ) {
1206 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- wp_verify_nonce handles validation
1207 + if ( ! wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'wpcharitable-stripe-connect-disconnect' ) ) {
772 1208 return;
773 1209 }
774 1210
775 1211 $settings = get_option( 'charitable_settings' );
776 1212
777 - unset( $settings['gateways_stripe'][ 'live_secret_key' ] );
778 - unset( $settings['gateways_stripe'][ 'live_public_key' ] );
779 - unset( $settings['gateways_stripe'][ 'test_secret_key' ] );
780 - unset( $settings['gateways_stripe'][ 'test_public_key' ] );
1213 + unset( $settings['gateways_stripe']['live_secret_key'] );
1214 + unset( $settings['gateways_stripe']['live_public_key'] );
1215 + unset( $settings['gateways_stripe']['test_secret_key'] );
1216 + unset( $settings['gateways_stripe']['test_public_key'] );
781 1217
782 1218 update_option( 'charitable_settings', $settings );
783 1219
784 1220 // update the option to track that we are using stripe connect.
@@ -798,9 +1234,84 @@
798 1234 );
799 1235
800 1236 wp_safe_redirect( $redirect_url );
801 1237 exit;
1238 + }
802 1239
1240 + /**
1241 + * Disconnects from Square by removing associated account information.
1242 + * Also remove webhooks from the Square account.
1243 + *
1244 + * This does not deauthorize the application within the Square account.
1245 + * LEGIT BEING CALLED.
1246 + *
1247 + * @since 1.8.7
1248 + *
1249 + * @return void
1250 + */
1251 + public function disconnect_gateways_square() {
1252 +
1253 + // Do not need to handle this request, bail.
1254 + if (
1255 + ! ( isset( $_GET['page'] ) && 'charitable-settings' === $_GET['page'] ) ||
1256 + ! isset( $_GET['wpcharitable-square-disconnect'] ) ||
1257 + charitable_square_legacy_mode()
1258 + ) {
1259 + return;
1260 + }
1261 +
1262 + // We need to know if this is a sandbox or live disconnect.
1263 + if ( ! isset( $_GET['mode'] ) ) {
1264 + return;
1265 + }
1266 +
1267 + $mode = sanitize_text_field( wp_unslash( $_GET['mode'] ) );
1268 + $mode = 'sandbox' === $mode ? 'test' : 'live';
1269 +
1270 + // Current user cannot handle this request or nonce is invalid.
1271 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- wp_verify_nonce handles validation
1272 + if ( ! current_user_can( 'manage_options' ) || ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'wpcharitable-square-connect-disconnect' ) ) {
1273 + if ( charitable_is_debug( 'webhook' ) ) {
1274 + error_log( 'disconnect_gateways_square - user cannot manage options or nonce is invalid' ); // phpcs:ignore
1275 + }
1276 + return;
1277 + }
1278 +
1279 + $settings = get_option( 'charitable_settings' );
1280 +
1281 + // Delete the Square connection error notice.
1282 + delete_option( 'charitable_square_connection_error_notice' );
1283 +
1284 + // Attempt to disconnect / remove webhooks from the Square account.
1285 + $this->remove_webhooks_from_square_account( $mode, $settings );
1286 +
1287 + $settings['gateways_square'][ $mode ] = array();
1288 +
1289 + update_option( 'charitable_settings', $settings );
1290 +
1291 + // remove the option to track that we are using square connect (test or live).
1292 + $charitable_using_square_connect = get_option( 'charitable_using_square_connect', array() );
1293 + if ( isset( $charitable_using_square_connect[ $mode ] ) ) {
1294 + unset( $charitable_using_square_connect[ $mode ] );
1295 + update_option( 'charitable_using_square_connect', $charitable_using_square_connect );
1296 + }
1297 +
1298 + // translators: %s is the mode of the connection.
1299 + charitable_get_admin_notices()->add_success( sprintf( __( 'Your connection to Square in %s mode has been removed.', 'charitable' ), $mode ) );
1300 +
1301 + do_action( 'charitable_remove_connection_gateway_square', $settings );
1302 +
1303 + $redirect_url = add_query_arg(
1304 + array(
1305 + 'tab' => 'gateways',
1306 + 'page' => 'charitable-settings',
1307 + 'group' => 'gateways_square_core',
1308 + ),
1309 + admin_url( 'admin.php' )
1310 + );
1311 +
1312 + wp_safe_redirect( $redirect_url );
1313 + exit;
803 1314 }
804 1315
805 1316 /**
806 1317 * Redirects to the gateway settings page once a gateway has been activated.
@@ -811,11 +1322,14 @@
811 1322 * @return void
812 1323 */
813 1324 public function redirect_gateway_settings( $gateway ) {
814 1325
815 - $settings_url = add_query_arg( array(
816 - 'group' => 'gateways_' . $gateway,
817 - ), admin_url( 'admin.php?page=charitable-settings&tab=gateways' ) );
1326 + $settings_url = add_query_arg(
1327 + array(
1328 + 'group' => 'gateways_' . $gateway,
1329 + ),
1330 + admin_url( 'admin.php?page=charitable-settings&tab=gateways' )
1331 + );
818 1332
819 1333 wp_safe_redirect( $settings_url );
820 1334 exit;
821 1335 }
@@ -831,13 +1345,13 @@
831 1345 */
832 1346 protected function sort_by_default( $a, $b ) {
833 1347 $default = $this->get_default_gateway();
834 1348
835 - if ( $a == $default ) {
1349 + if ( $a == $default ) { // phpcs:ignore
836 1350 return -1;
837 1351 }
838 1352
839 - if ( $b == $default ) {
1353 + if ( $b == $default ) { // phpcs:ignore
840 1354 return 1;
841 1355 }
842 1356
843 1357 return 0;
@@ -843,16 +1357,67 @@
843 1357 return 0;
844 1358 }
845 1359
846 1360 /**
1361 + * Remove webhooks from the Square account.
1362 + *
1363 + * @since 1.8.7
1364 + *
1365 + * @param string $mode The mode to remove the webhooks from.
1366 + * @param array $settings The settings array.
1367 + * @param bool $force_remove Whether to force remove the webhooks.
1368 + * @return void
1369 + */
1370 + public function remove_webhooks_from_square_account( $mode, $settings = array(), $force_remove = true ) {
1371 +
1372 + if ( charitable_is_debug( 'square' ) ) {
1373 + error_log( 'remove_webhooks_from_square_account' ); // phpcs:ignore
1374 + }
1375 +
1376 + // Check if settings are empty and if so, get the settings from the database.
1377 + if ( empty( $settings ) ) {
1378 + $settings = get_option( 'charitable_settings' );
1379 + }
1380 +
1381 + $access_token = $settings['gateways_square'][ $mode ]['access_token'];
1382 +
1383 + // Test to see if we have the access token.
1384 + if ( empty( $access_token ) ) {
1385 + // if force_remove is true, we can remove the webhooks from the Square account in Charitable.
1386 + if ( $force_remove ) {
1387 + if ( charitable_is_debug( 'square' ) ) {
1388 + error_log( 'remove_webhooks_from_square_account:force_remove' ); // phpcs:ignore
1389 + }
1390 + $settings['gateways_square'][ $mode ]['webhooks'] = array();
1391 + update_option( 'charitable_settings', $settings );
1392 + return;
1393 +
1394 + }
1395 + return;
1396 + } elseif ( isset( $settings['gateways_square'][ $mode ]['webhook_id'] ) ) {
1397 + $webhook_manager = new Charitable_Square_WebhooksManager( $mode, $access_token );
1398 + $result = $webhook_manager->remove_webhook( $access_token, $settings['gateways_square'][ $mode ]['webhook_id'] );
1399 +
1400 + }
1401 +
1402 + if ( charitable_is_debug( 'square' ) ) {
1403 + error_log( 'remove_webhooks_from_square_account:deactivate_webhook' ); // phpcs:ignore
1404 + }
1405 +
1406 + return $result;
1407 + }
1408 +
1409 + /**
847 1410 * Ensure there is a settings option when landing on settings pages, even if init blank. Mostly applicable to new installs.
848 1411 *
849 1412 * @since 1.4.0
1413 + * @since 1.8.1.11
850 1414 *
1415 + * @return void
851 1416 */
852 1417 public function check_settings() {
853 1418
854 - if ( isset( $_GET['page'] ) && 'charitable-settings' !== $_GET['page'] ) {
1419 + if ( isset( $_GET['page'] ) && 'charitable-settings' !== $_GET['page'] ) { // phpcs:ignore
855 1420 return;
856 1421 }
857 1422
858 1423 $settings = get_option( 'charitable_settings' );
@@ -857,35 +1422,101 @@
857 1422
858 1423 $settings = get_option( 'charitable_settings' );
859 1424
860 1425 // attach this to CHARITABLE_DEBUG constant.
861 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
862 - error_log( 'checking_settings');
863 - error_log( print_r( $settings, true ) );
1426 + if ( charitable_is_debug() ) {
1427 + // phpcs:disable
1428 + // error_log( 'checking_settings' );
1429 + // error_log( print_r( $settings, true ) );
1430 + // phpcs:enable
864 1431 }
865 1432
866 - if ( false === $settings ||( is_array( $settings ) && empty( $settings ) ) ) {
867 - $settings_blank_slate = array( 'default_gateway' => 'stripe' ); // settings are brand new and include setting the default gateway
868 - update_option( 'charitable_settings', $settings_blank_slate );
1433 + // If there is no settings, or the settings are empty, set the test mode to true and stripe is default gateway.
1434 + if ( false === $settings || ( is_array( $settings ) && empty( $settings ) ) ) {
1435 + $this->enable_gateway( 'stripe', false );
1436 + $settings = (array) get_option( 'charitable_settings' );
1437 + $settings['test_mode'] = true;
1438 + update_option( 'charitable_settings', $settings );
869 1439 }
1440 + }
870 1441
1442 + /**
1443 + * Check the setup stored value of the payment methods.
1444 + *
1445 + * @since 1.8.4
1446 + *
1447 + * @return bool
1448 + */
1449 + public function check_setup_payment_methods() {
1450 +
1451 + $payment_methods = get_option( 'charitable_setup_payment_methods', array() );
1452 +
1453 + if ( ! is_array( $payment_methods ) ) {
1454 + return false;
1455 + }
1456 +
1457 + $payment_methods = array_map( 'sanitize_text_field', $payment_methods );
1458 +
1459 + if ( empty( $payment_methods ) ) {
1460 + return false;
1461 + }
1462 +
1463 + $gateways_enbled = 0;
1464 +
1465 + if ( in_array( 'stripe', $payment_methods, true ) ) {
1466 + // check if this gateway is already enabled.
1467 + if ( ! $this->is_active_gateway( 'stripe' ) ) {
1468 + $this->enable_gateway( 'stripe', false );
1469 + ++$gateways_enbled;
1470 + }
1471 + }
1472 +
1473 + if ( in_array( 'paypal', $payment_methods, true ) ) {
1474 + // check if this gateway is already enabled.
1475 + if ( ! $this->is_active_gateway( 'paypal' ) ) {
1476 + $this->enable_gateway( 'paypal', false );
1477 + ++$gateways_enbled;
1478 + }
1479 + }
1480 +
1481 + if ( in_array( 'offline', $payment_methods, true ) ) {
1482 + // check if this gateway is already enabled.
1483 + if ( ! $this->is_active_gateway( 'offline' ) ) {
1484 + $this->enable_gateway( 'offline', false );
1485 + }
1486 + }
1487 +
1488 + if ( $gateways_enbled > 0 && class_exists( 'Charitable_Checklist' ) ) {
1489 + $checklist_class = Charitable_Checklist::get_instance();
1490 + $checklist_class->mark_step_completed( 'connect-payment' );
1491 + }
1492 +
1493 + return true;
871 1494 }
872 1495
873 -
874 1496 /**
875 1497 * Display the test and live fields that represent the manual keys for Stripe that users might be already using prior to 1.7.0.
876 1498 *
877 1499 * @since 1.7.0
878 - *
879 1500 */
880 1501 public function show_stripe_manual_keys_ajax() {
881 1502
882 - if ( ! isset( $_POST ) || 'charitable-show-stripe-keys' !== $_POST['action'] ) {
1503 + if ( ! isset( $_POST ) || 'charitable-show-stripe-keys' !== $_POST['action'] ) { // phpcs:ignore
883 1504 return;
884 1505 }
885 1506
886 - $settings = get_option( 'charitable_settings' );
1507 + // Invalid nonce, bail.
1508 + if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'charitable-show-stripe-keys' ) ) { // phpcs:ignore
1509 + return;
1510 + }
887 1511
1512 + // Current user cannot handle this request.
1513 + if ( ! current_user_can( 'manage_options' ) ) {
1514 + return;
1515 + }
1516 +
1517 + $settings = get_option( 'charitable_settings' );
1518 +
888 1519 if ( false === $settings ) {
889 1520 return;
890 1521 }
891 1522
@@ -890,12 +1521,12 @@
890 1521 }
891 1522
892 1523 $gateway_id = 'stripe';
893 1524
894 - $live_secret_key = $settings['gateways_' . $gateway_id ][ 'live_secret_key' ];
895 - $live_public_key = $settings['gateways_' . $gateway_id ][ 'live_public_key' ];
896 - $test_secret_key = $settings['gateways_' . $gateway_id ][ 'test_secret_key' ];
897 - $test_public_key = $settings['gateways_' . $gateway_id ][ 'test_public_key' ];
1525 + $live_secret_key = $settings[ 'gateways_' . $gateway_id ]['live_secret_key'];
1526 + $live_public_key = $settings[ 'gateways_' . $gateway_id ]['live_public_key'];
1527 + $test_secret_key = $settings[ 'gateways_' . $gateway_id ]['test_secret_key'];
1528 + $test_public_key = $settings[ 'gateways_' . $gateway_id ]['test_public_key'];
898 1529
899 1530 $html = '<tr><th scope="row">Live Settings</th><td><hr />
900 1531 </td></tr><tr class="wide"><th scope="row">Live Secret Key</th><td><input type="text"
901 1532 id="charitable_settings_gateways_stripe_live_secret_key"
@@ -924,11 +1555,455 @@
924 1555 />
925 1556 </td></tr>';
926 1557
927 1558 wp_send_json_success( $html );
1559 + }
928 1560
1561 + /**
1562 + * Returns the error message for the square connect gateway.
1563 + *
1564 + * @since 1.8.7
1565 + *
1566 + * @return void
1567 + */
1568 + public function get_gateway_error_message() {
1569 +
1570 + if ( ! isset( $_GET['square_connect_error'] ) && ! isset( $_GET['square_connect_error_description'] ) ) { // phpcs:ignore
1571 + return;
1572 + }
1573 +
1574 + $square_connect_error = sanitize_text_field( wp_unslash( $_GET['square_connect_error'] ) ); // phpcs:ignore
1575 + $square_connect_error_description = sanitize_text_field( wp_unslash( $_GET['square_connect_error_description'] ) ); // phpcs:ignore
1576 + $support_link = 'https://wpcharitable.com/support';
1577 +
1578 + switch ( $square_connect_error ) {
1579 + case 'access_denied':
1580 + switch ( $square_connect_error_description ) {
1581 + case 'user_denied':
1582 + $message = __( 'You have denied access to Square Connect.', 'charitable' );
1583 + break;
1584 + case 'missing_state_or_code':
1585 + $message = sprintf(
1586 + /* translators: %s: Support link URL */
1587 + __( 'There has been an issue with your request. Please try again or <a href="%s">contact support</a>.', 'charitable' ),
1588 + $support_link
1589 + );
1590 + break;
1591 + case 'missing_init_request':
1592 + $message = sprintf(
1593 + /* translators: %s: Support link URL */
1594 + __( 'There has been an issue confirming your request. Please try again or <a href="%s">contact support</a>.', 'charitable' ),
1595 + $support_link
1596 + );
1597 + break;
1598 + default:
1599 + $message = sprintf(
1600 + /* translators: %s: Support link URL */
1601 + __( 'Your connect to Square has been canceled for an unknown reason. Please try again or <a href="%s">contact support</a>.', 'charitable' ),
1602 + $support_link
1603 + );
1604 + break;
1605 + }
1606 + break;
1607 + case 'connect_error':
1608 + switch ( $square_connect_error_description ) {
1609 + case 'error_refreshing_token':
1610 + $refresh_by_date = Charitable_Gateway_Square::get_instance()->get_personal_access_token_should_refresh( 'test' );
1611 + $message = sprintf(
1612 + /* translators: %s: Refresh by date */
1613 + __( 'There has been an issue refreshing your Square token. Token should be refreshed by: %1$s. Please try again or <a href="%2$s">contact support</a>.', 'charitable' ),
1614 + $refresh_by_date,
1615 + $support_link
1616 + );
1617 + break;
1618 + case 'missing_response_fields':
1619 + case 'credentials_not_saved':
1620 + $message = sprintf(
1621 + /* translators: %s: Support link URL */
1622 + __( 'There has been an issue confirming your Square token. Please try again or <a href="%s">contact support</a>.', 'charitable' ),
1623 + $support_link
1624 + );
1625 + break;
1626 + case 'response_error':
1627 + case 'merchant_id_not_found':
1628 + case 'save_credentials_error':
1629 + case 'missing_state_or_code':
1630 + case 'invalid_request':
1631 + case 'error_getting_credentials':
1632 + case 'missing_state_or_site_url':
1633 + case 'error_getting_credentials':
1634 + case 'missing_information_for_gateway_connect':
1635 + case 'error_saving_init_request':
1636 + $message = sprintf(
1637 + /* translators: %s: Support link URL */
1638 + __( 'There has been an issue communicating with Square. Please try again or <a href="%s">contact support</a>.', 'charitable' ),
1639 + $support_link
1640 + );
1641 + break;
1642 + default:
1643 + $message = sprintf(
1644 + /* translators: %s: Support link URL */
1645 + __( 'There has been an issue with your request. Please try again or <a href="%s">contact support</a>.', 'charitable' ),
1646 + $support_link
1647 + );
1648 + break;
1649 + }
1650 + break;
1651 + default:
1652 + $message = sprintf(
1653 + /* translators: %s: Support link URL */
1654 + __( 'There has been an issue with your request. Please try again or <a href="%s">contact support</a>.', 'charitable' ),
1655 + $support_link
1656 + );
1657 + }
1658 +
1659 + charitable_get_admin_notices()->add_notice( $message, 'error', false, true );
929 1660 }
930 1661
1662 + /**
1663 + * Get the personal access refresh token.
1664 + *
1665 + * @since 1.8.7
1666 + *
1667 + * @param string $mode The mode to get the personal access refresh token for.
1668 + * @return string
1669 + */
1670 + private function get_personal_access_refresh_token( $mode = 'test' ) {
1671 + $square_settings = charitable_get_option( 'gateways_square', array() );
931 1672
1673 + if ( ! empty( $square_settings[ $mode ]['refresh_token'] ) ) {
1674 + return $square_settings[ $mode ]['refresh_token'];
1675 + }
1676 +
1677 + return '';
1678 + }
1679 +
1680 + /**
1681 + * Add custom cron schedules.
1682 + *
1683 + * @since 1.8.7
1684 + *
1685 + * @param array $schedules Existing cron schedules.
1686 + * @return array
1687 + */
1688 + public function add_cron_schedules( $schedules ) {
1689 + $schedules['14days'] = array(
1690 + 'interval' => 14 * DAY_IN_SECONDS,
1691 + 'display' => __( 'Every 14 days', 'charitable' ),
1692 + );
1693 + return $schedules;
1694 + }
1695 +
1696 + /**
1697 + * Handle Square gateway switch.
1698 + *
1699 + * @since 1.8.7
1700 + * @version 1.8.9.1
1701 + *
1702 + * @return void
1703 + */
1704 + public function handle_square_gateway_switch() {
1705 + // phpcs:disable WordPress.Security.NonceVerification.Missing
1706 + // Verify nonce.
1707 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- wp_verify_nonce handles validation
1708 + if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( wp_unslash( $_POST['nonce'] ), 'charitable_admin_nonce' ) ) {
1709 + wp_send_json_error( array( 'message' => __( 'Security check failed.', 'charitable' ) ) );
1710 + }
1711 + // phpcs:enable WordPress.Security.NonceVerification.Missing
1712 +
1713 + // Check user permissions.
1714 + if ( ! current_user_can( 'manage_options' ) ) {
1715 + wp_send_json_error( array( 'message' => __( 'You do not have permission to perform this action.', 'charitable' ) ) );
1716 + }
1717 +
1718 + // Check if Square Legacy is active and Square Core is not active.
1719 + if ( ! $this->is_active_gateway( 'square' ) || $this->is_active_gateway( 'square_core' ) ) {
1720 + wp_send_json_error( array( 'message' => __( 'Invalid gateway state for switching.', 'charitable' ) ) );
1721 + }
1722 +
1723 + // Disable Square Legacy.
1724 + $this->disable_gateway( 'square' );
1725 +
1726 + // Enable Square Core.
1727 + $this->enable_gateway( 'square_core', false );
1728 +
1729 + // Get the redirect URL for Square Core settings.
1730 + $redirect_url = add_query_arg(
1731 + array(
1732 + 'page' => 'charitable-settings',
1733 + 'tab' => 'gateways',
1734 + 'group' => 'gateways_square_core',
1735 + ),
1736 + admin_url( 'admin.php' )
1737 + );
1738 +
1739 + wp_send_json_success( array( 'redirect_url' => $redirect_url ) );
1740 + }
1741 +
1742 + /**
1743 + * Handle Square core to legacy switch.
1744 + *
1745 + * @since 1.8.7
1746 + * @version 1.8.9.1
1747 + *
1748 + * @return void
1749 + */
1750 + public function handle_square_core_to_legacy_switch() {
1751 + // phpcs:disable WordPress.Security.NonceVerification.Missing
1752 + // Verify nonce.
1753 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- wp_verify_nonce handles validation
1754 + if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( wp_unslash( $_POST['nonce'] ), 'charitable_admin_nonce' ) ) {
1755 + wp_send_json_error( array( 'message' => __( 'Security check failed.', 'charitable' ) ) );
1756 + }
1757 + // phpcs:enable WordPress.Security.NonceVerification.Missing
1758 +
1759 + // Check user permissions.
1760 + if ( ! current_user_can( 'manage_options' ) ) {
1761 + wp_send_json_error( array( 'message' => __( 'You do not have permission to perform this action.', 'charitable' ) ) );
1762 + }
1763 +
1764 + // Check if Square Core is active and Square Legacy is not active.
1765 + if ( ! $this->is_active_gateway( 'square_core' ) || $this->is_active_gateway( 'square' ) ) {
1766 + wp_send_json_error( array( 'message' => __( 'Invalid gateway state for switching.', 'charitable' ) ) );
1767 + }
1768 +
1769 + if ( charitable_is_debug() ) {
1770 + error_log( 'Charitable: Starting Square Core to Legacy gateway switch process.' ); // phpcs:ignore
1771 + }
1772 +
1773 + // Disconnect Square Core connections for both live and test modes.
1774 + $this->disconnect_square_core_connections();
1775 +
1776 + // Disable Square Core.
1777 + $this->disable_gateway( 'square_core' );
1778 +
1779 + // Enable Square Legacy.
1780 + $this->enable_gateway( 'square', false );
1781 +
1782 + if ( charitable_is_debug() ) {
1783 + error_log( 'Charitable: Successfully switched from Square Core to Square Legacy gateway.' ); // phpcs:ignore
1784 + }
1785 +
1786 + // Get the redirect URL for Square Legacy settings.
1787 + $redirect_url = add_query_arg(
1788 + array(
1789 + 'page' => 'charitable-settings',
1790 + 'tab' => 'gateways',
1791 + 'group' => 'gateways_square',
1792 + ),
1793 + admin_url( 'admin.php' )
1794 + );
1795 +
1796 + wp_send_json_success( array( 'redirect_url' => $redirect_url ) );
1797 + }
1798 +
1799 + /**
1800 + * Disconnect Square Core connections for both live and test modes.
1801 + *
1802 + * @since 1.8.7
1803 + *
1804 + * @return void
1805 + */
1806 + private function disconnect_square_core_connections() {
1807 +
1808 + if ( charitable_is_debug() ) {
1809 + error_log( 'Charitable: Starting Square Core connection disconnection process.' ); // phpcs:ignore
1810 + }
1811 +
1812 + // Check if Charitable_Square_Connection class exists.
1813 + if ( ! class_exists( 'Charitable_Square_Connection' ) ) {
1814 + if ( charitable_is_debug() ) {
1815 + error_log( 'Charitable: Charitable_Square_Connection class not found. Skipping disconnect process.' ); // phpcs:ignore
1816 + }
1817 + return;
1818 + }
1819 +
1820 + // Check and disconnect live mode connection.
1821 + $live_connection = Charitable_Square_Connection::get( 'live' );
1822 + if ( $live_connection && $live_connection->is_configured() ) {
1823 + if ( charitable_is_debug() ) {
1824 + error_log( 'Charitable: Found active Square Core live connection. Attempting to disconnect.' ); // phpcs:ignore
1825 + }
1826 + $this->disconnect_square_core_mode( $live_connection, 'live' );
1827 + } elseif ( charitable_is_debug() ) {
1828 + error_log( 'Charitable: No active Square Core live connection found.' ); // phpcs:ignore
1829 +
1830 + }
1831 +
1832 + // Check and disconnect test mode connection.
1833 + $test_connection = Charitable_Square_Connection::get( 'test' );
1834 + if ( $test_connection && $test_connection->is_configured() ) {
1835 + if ( charitable_is_debug() ) {
1836 + error_log( 'Charitable: Found active Square Core test connection. Attempting to disconnect.' ); // phpcs:ignore
1837 + }
1838 + $this->disconnect_square_core_mode( $test_connection, 'test' );
1839 + } elseif ( charitable_is_debug() ) {
1840 + error_log( 'Charitable: No active Square Core test connection found.' ); // phpcs:ignore
1841 +
1842 + }
1843 +
1844 + if ( charitable_is_debug() ) {
1845 + error_log( 'Charitable: Completed Square Core connection disconnection process.' ); // phpcs:ignore
1846 + }
1847 + }
1848 +
1849 + /**
1850 + * Disconnect Square Core connection for a specific mode.
1851 + *
1852 + * @since 1.8.7
1853 + *
1854 + * @param Charitable_Square_Connection $connection The connection object.
1855 + * @param string $mode The mode (live/test).
1856 + * @return void
1857 + */
1858 + private function disconnect_square_core_mode( $connection, $mode ) {
1859 +
1860 + if ( charitable_is_debug() ) {
1861 + error_log( 'Charitable: Disconnecting Square Core connection for mode: ' . $mode ); // phpcs:ignore
1862 + }
1863 +
1864 + // Check if Charitable_Square_Connect class exists.
1865 + if ( ! class_exists( 'Charitable_Square_Connect' ) ) {
1866 + if ( charitable_is_debug() ) {
1867 + error_log( 'Charitable: Charitable_Square_Connect class not found. Cannot disconnect mode: ' . $mode ); // phpcs:ignore
1868 + }
1869 + return;
1870 + }
1871 +
1872 + try {
1873 + // Get the Square Connect instance.
1874 + $square_connect = Charitable_Square_Connect::get_instance();
1875 +
1876 + // Use reflection to access the private handle_disconnect method.
1877 + $reflection = new ReflectionClass( $square_connect );
1878 + $method = $reflection->getMethod( 'handle_disconnect' );
1879 + $method->setAccessible( true );
1880 +
1881 + // Set the live_mode parameter for the disconnect process.
1882 + $_GET['live_mode'] = ( $mode === 'live' ) ? 1 : 0;
1883 +
1884 + // Call the disconnect method without redirect.
1885 + $method->invoke( $square_connect, false );
1886 +
1887 + if ( charitable_is_debug() ) {
1888 + error_log( 'Charitable: Successfully disconnected Square Core connection for mode: ' . $mode ); // phpcs:ignore
1889 + }
1890 + } catch ( Exception $e ) {
1891 + if ( charitable_is_debug() ) {
1892 + error_log( 'Charitable: Error disconnecting Square Core connection for mode ' . $mode . ': ' . $e->getMessage() ); // phpcs:ignore
1893 + }
1894 + }
1895 + }
1896 +
1897 + /**
1898 + * Dequeue Square Legacy scripts if Square Legacy is not active.
1899 + *
1900 + * @since 1.8.7
1901 + *
1902 + * @return void
1903 + */
1904 + public function maybe_dequeue_square_legacy_scripts() {
1905 + // Only run on frontend.
1906 + if ( is_admin() ) {
1907 + return;
1908 + }
1909 +
1910 + // Debug: Log the status checks.
1911 + if ( charitable_is_debug( 'square' ) ) {
1912 + error_log( '[Charitable Square] Script dequeue check - Legacy mode: ' . ( charitable_square_legacy_mode() ? 'true' : 'false' ) ); // phpcs:ignore
1913 + error_log( '[Charitable Square] Script dequeue check - Square gateway active: ' . ( $this->is_active_gateway( 'square' ) ? 'true' : 'false' ) ); // phpcs:ignore
1914 + }
1915 +
1916 + // Check if Square Legacy is active.
1917 + if ( ! charitable_square_legacy_mode() || ! $this->is_active_gateway( 'square' ) ) {
1918 + // Dequeue Square Legacy scripts and styles.
1919 + wp_dequeue_script( 'charitable-square' );
1920 + wp_dequeue_script( 'square' );
1921 + wp_dequeue_style( 'charitable-square' );
1922 +
1923 + // Deregister scripts to prevent them from being loaded.
1924 + wp_deregister_script( 'charitable-square' );
1925 + wp_deregister_script( 'square' );
1926 + wp_deregister_style( 'charitable-square' );
1927 +
1928 + if ( charitable_is_debug( 'square' ) ) {
1929 + error_log( '[Charitable Square] Dequeued Square Legacy scripts - Square Legacy is not active' ); // phpcs:ignore
1930 + }
1931 + } elseif ( charitable_is_debug( 'square' ) ) {
1932 + error_log( '[Charitable Square] Square Legacy scripts will remain loaded - Square Legacy is active' ); // phpcs:ignore
1933 +
1934 + }
1935 + }
1936 +
1937 + /**
1938 + * Check if charitable-square plugin is active.
1939 + *
1940 + * @since 1.8.7
1941 + *
1942 + * @return boolean
1943 + */
1944 + private function is_square_addon_active() {
1945 + return is_plugin_active( 'charitable-square/charitable-square.php' );
1946 + }
1947 +
1948 + /**
1949 + * Force cleanup of 'square' gateway if charitable-square plugin is not active.
1950 + * Runs once per 24 hours (adjustable via filter) to avoid constant database checks.
1951 + *
1952 + * @since 1.8.7
1953 + *
1954 + * @param array $active_gateways The current active gateways array.
1955 + * @return void
1956 + */
1957 + private function maybe_force_cleanup_square_gateway( $active_gateways ) {
1958 + // Check if we need to run cleanup (once per 24 hours).
1959 + $transient_name = 'charitable_square_cleanup_last_run';
1960 + $check_interval = apply_filters( 'charitable_square_cleanup_check_interval', 24 * HOUR_IN_SECONDS );
1961 +
1962 + if ( get_transient( $transient_name ) ) {
1963 + return;
1964 + }
1965 +
1966 + // Check if 'square' gateway exists and charitable-square plugin is not active.
1967 + if ( isset( $active_gateways['square'] ) && ! $this->is_square_addon_active() ) {
1968 + try {
1969 + // Get current settings.
1970 + $settings = get_option( 'charitable_settings', array() );
1971 +
1972 + if ( ! empty( $settings['active_gateways']['square'] ) ) {
1973 + // Remove 'square' gateway from active gateways.
1974 + unset( $settings['active_gateways']['square'] );
1975 +
1976 + // Update default gateway if it was set to 'square'.
1977 + if ( isset( $settings['default_gateway'] ) && 'square' === $settings['default_gateway'] ) {
1978 + $settings['default_gateway'] = '';
1979 + }
1980 +
1981 + // Remove the option that warns users about incorrect square settings.
1982 + delete_option( 'charitable_square_mode_connection_warning' );
1983 +
1984 + // Save updated settings.
1985 + $updated = update_option( 'charitable_settings', $settings );
1986 +
1987 + if ( $updated ) {
1988 + if ( charitable_is_debug( 'square' ) ) {
1989 + error_log( '[Charitable Square] Successfully removed legacy square gateway from active gateways' ); // phpcs:ignore
1990 + }
1991 + } else {
1992 + if ( charitable_is_debug( 'square' ) ) {
1993 + error_log( '[Charitable Square] Failed to update settings when removing legacy square gateway' ); // phpcs:ignore
1994 + }
1995 + }
1996 + }
1997 + } catch ( Exception $e ) {
1998 + if ( charitable_is_debug( 'square' ) ) {
1999 + error_log( '[Charitable Square] Error during square gateway cleanup: ' . $e->getMessage() ); // phpcs:ignore
2000 + }
2001 + }
2002 + }
2003 +
2004 + // Set transient to prevent running again for the specified interval.
2005 + set_transient( $transient_name, time(), $check_interval );
2006 + }
932 2007 }
933 2008
934 2009 endif;