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/donations/class-charitable-donation-processor.php +150 -23 1.6.60 → 1.8.13 View file →
@@ -2,10 +2,10 @@
2 2 /**
3 3 * The class that is responsible for responding to donation events.
4 4 *
5 5 * @package Charitable/Classes/Charitable_Donation_Processor
6 - * @author Eric Daams
7 - * @copyright Copyright (c) 2022, Studio 164a
6 + * @author David Bisset
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.55
11 11 */
@@ -129,8 +129,9 @@
129 129 /**
130 130 * Executed when a user first clicks the Donate button on a campaign.
131 131 *
132 132 * @since 1.0.0
133 + * @version 1.8.3.2
133 134 *
134 135 * @return void
135 136 */
136 137 public static function add_donation_to_session() {
@@ -139,10 +140,14 @@
139 140 if ( ! $processor->get_campaign() ) {
140 141 return;
141 142 }
142 143
143 - $nonce = $_POST['charitable-donate-now'];
144 + if ( ! isset( $_POST['charitable-donate-now'] ) ) {
145 + return;
146 + }
144 147
148 + $nonce = sanitize_text_field( wp_unslash( $_POST['charitable-donate-now'] ) );
149 +
145 150 if ( ! wp_verify_nonce( $nonce, 'charitable-donate' ) ) {
146 151
147 152 /* For backwards compatibility, we also check this nonce. */
148 153 if ( ! wp_verify_nonce( $nonce, 'charitable-donate-' ) ) {
@@ -149,16 +154,21 @@
149 154 return;
150 155 }
151 156 }
152 157
158 + /* Possibly add a donation amount if user clicked on a campaign builder donate button */
159 + $donation_amount = ! empty( $_POST['charitable_donation_amount'] ) && ! empty( $_POST['charitable_builder'] ) ? esc_html( $_POST['charitable_donation_amount'] ) : 0; // phpcs:ignore
160 +
161 + /* Strip any currency symbols and make sure $donation_amount is a float. */
162 + $donation_amount = charitable_sanitize_amount( (string) $donation_amount );
163 +
153 164 /* Save the donation in the session */
154 - charitable_get_session()->add_donation( $processor->get_campaign()->ID, 0 );
165 + charitable_get_session()->add_donation( $processor->get_campaign()->ID, $donation_amount );
155 166
156 167 $donations_url = charitable_get_permalink( 'campaign_donation_page', array( 'campaign_id' => $processor->get_campaign()->ID ) );
157 168
158 - wp_redirect( $donations_url );
159 -
160 - die();
169 + wp_safe_redirect( $donations_url );
170 + exit();
161 171 }
162 172
163 173 /**
164 174 * Process the donation.
@@ -172,15 +182,41 @@
172 182 public function process_donation() {
173 183 $processor = self::get_instance();
174 184 $campaign = $processor->get_campaign();
175 185
186 + if ( charitable_is_debug() ) {
187 + error_log( 'process_donation start' ); // phpcs:ignore
188 + }
189 +
176 190 if ( ! $campaign ) {
177 191 return;
178 192 }
179 193
194 + /* Check to ensure the donation is not going to an inactive campaign post. */
195 + if ( ! $campaign->can_receive_donations() ) {
196 + if ( charitable_is_debug() ) {
197 + error_log( 'Campaign cannot receive donations' ); // phpcs:ignore
198 + }
199 + return;
200 + }
201 +
180 202 /* Validate the form submission and retrieve the values. */
181 203 $form = $campaign->get_donation_form();
204 + if ( charitable_is_debug() ) {
205 + // phpcs:disable
206 + error_log( 'process_donation - form' );
207 + error_log( print_r( $form, true ) );
208 + // phpcs:enable
209 + }
182 210
211 + if ( charitable_is_debug() ) {
212 + // phpcs:disable
213 + error_log( '=== FORM DATA DEBUG ===' );
214 + error_log( 'POST data available to form: ' . print_r( $_POST, true ) );
215 + error_log( 'REQUEST data available to form: ' . print_r( $_REQUEST, true ) );
216 + // phpcs:enable
217 + }
218 +
183 219 /**
184 220 * Do something before any donation form processing takes place.
185 221 *
186 222 * @since 1.0.0
@@ -190,8 +226,13 @@
190 226 */
191 227 do_action( 'charitable_before_process_donation_form', $processor, $form );
192 228
193 229 if ( ! $form->validate_submission() ) {
230 + if ( charitable_is_debug() ) {
231 + // phpcs:disable
232 + error_log( 'Validation form not valid' );
233 + // phpcs:enable
234 + }
194 235 return false;
195 236 }
196 237
197 238 $values = $form->get_donation_values();
@@ -196,8 +237,17 @@
196 237
197 238 $values = $form->get_donation_values();
198 239 $gateway = $values['gateway'];
199 240
241 + if ( charitable_is_debug() ) {
242 + // phpcs:disable
243 + error_log( '=== DONATION PROCESSOR DEBUG ===' );
244 + error_log( 'Gateway from form values: ' . $gateway );
245 + error_log( 'All form values: ' . print_r( $values, true ) );
246 + error_log( 'POST data: ' . print_r( $_POST, true ) );
247 + // phpcs:enable
248 + }
249 +
200 250 /**
201 251 * Validate the gateway values.
202 252 *
203 253 * @since 1.0.0
@@ -206,8 +256,15 @@
206 256 * @param string $gateway The gateway ID.
207 257 * @param array $values The values submitted by the user.
208 258 */
209 259 if ( ! apply_filters( 'charitable_validate_donation_form_submission_gateway', true, $gateway, $values ) ) {
260 + if ( charitable_is_debug() ) {
261 + // phpcs:disable
262 + error_log( 'process_donation not valid' );
263 + error_log( print_r( $gateway, true ) );
264 + error_log( print_r( $values, true ) );
265 + // phpcs:enable
266 + }
210 267 return false;
211 268 }
212 269
213 270 $this->donation_id = $processor->save_donation( $values );
@@ -243,10 +300,20 @@
243 300 * @param int $donation_id The donation ID.
244 301 * @param Charitable_Donation_Processor $processor The Donation Processor object.
245 302 * @return mixed
246 303 */
247 - return apply_filters( 'charitable_process_donation_' . $gateway, true, $this->donation_id, $processor );
304 + if ( charitable_is_debug() ) {
305 + // phpcs:disable
306 + error_log( 'This Gateway is Charitable version 1.3.0 compatible... The gateway is ' . $gateway );
307 + error_log( 'The donation id is ' . $this->donation_id );
308 + error_log( 'Charitable_Donation_Processor Object is: [commented out] ' );
309 + // phpcs:enable
310 + }
248 311
312 + $hook_name = 'charitable_process_donation_' . $gateway;
313 +
314 + return apply_filters( $hook_name, true, $this->donation_id, $processor ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook name is dynamically constructed with the plugin prefix 'charitable_process_donation_'.
315 +
249 316 } else {
250 317 /**
251 318 * Send donation processing to the payment gateway.
252 319 *
@@ -285,23 +352,28 @@
285 352
286 353 /**
287 354 * Add a donation with AJAX.
288 355 *
289 - * @since 1.3.0
356 + * @since 1.3.0
357 + * @version 1.8.7
290 358 *
291 359 * @return void
292 360 */
293 361 public static function ajax_process_donation_form_submission() {
294 362 /* Prevent any displayed errors from messing with the AJAX response. */
295 - ini_set( 'display_errors', false );
363 + if ( charitable_is_debug() ) { // phpcs:ignore
364 + // do nothing, allow php/server settings to determine php logging.
365 + } else {
366 + ini_set( 'display_errors', 0 ); // phpcs:ignore
367 + }
296 368
297 - if ( ! isset( $_POST['campaign_id'] ) ) {
369 + if ( ! isset( $_POST['campaign_id'] ) ) { // @codingStandardsIgnoreLine
298 370 wp_send_json_error( new WP_Error( 'missing_campaign_id', __( 'Campaign ID was not found. Unable to create donation.', 'charitable' ) ) );
299 371 }
300 372
301 373 $processor = self::get_instance();
374 + $result = $processor->process_donation();
302 375
303 - $result = $processor->process_donation();
304 376 $response = is_array( $result ) ? $result : array();
305 377
306 378 if ( $processor->donation_processed_successfully( $result ) ) {
307 379 $response['success'] = true;
@@ -306,19 +378,70 @@
306 378 if ( $processor->donation_processed_successfully( $result ) ) {
307 379 $response['success'] = true;
308 380 $response['redirect_to'] = $processor->get_redirection_after_gateway_processing( $result );
309 381 } else {
382 +
383 + // Start with getting errors from the notices class.
310 384 $errors = charitable_get_notices()->get_errors();
385 + // If there is no errors, set the errors to an empty array.
386 + if ( empty( $errors ) || ! is_array( $errors ) ) {
387 + $errors = array();
388 + }
311 389
390 + // Check and see if there are errors in the response too.
391 + if ( ! empty( $response['errors'] ) ) {
392 + $errors = array_merge( $errors, $response['errors'] );
393 + }
394 +
312 395 if ( empty( $errors ) ) {
313 396 $errors = array( __( 'Unable to process donation.', 'charitable' ) );
314 397 }
315 398
399 + // Log the AJAX processing failure
400 + $context = array(
401 + 'campaign_id' => $processor->get_donation_data_value( 'campaign_id' ),
402 + 'amount' => $processor->get_donation_data_value( 'donation_amount' ),
403 + 'gateway' => $processor->get_donation_data_value( 'gateway' ),
404 + 'donation_id' => (int) $processor->get_donation_id(),
405 + );
406 + charitable_log_form_error( 'ajax_failure', 'donation_processing_failed', $context );
407 +
316 408 $response['success'] = false;
317 409 $response['errors'] = $errors;
318 410 $response['donation_id'] = (int) $processor->get_donation_id();
411 +
412 + // get the gateway from the processor.
413 + $gateway = $processor->get_donation_data_value( 'gateway' );
414 +
415 + // If the gateway is square, we need to add to add errors to the donation log.
416 + if ( 'square' === $gateway ) {
417 + // If we are in test mode, remove the first error because that reads "Test mode is enabled".
418 + if ( charitable_get_option( 'test_mode' ) ) {
419 + // If there is at least one element, check the first one for a value that contains "Test mode is enabled".
420 + if ( count( $errors ) > 0 ) {
421 + if ( strpos( $errors[0], 'Test mode is enabled' ) !== false ) {
422 + $errors = array_slice( $errors, 1 );
423 + }
424 + }
425 + }
426 + $errors = implode( ', ', $errors );
427 + $processor->update_donation_log( $processor->get_donation_id(), 'Payment attempt failed.' );
428 + }
319 429 }
320 430
431 + if ( charitable_is_debug() ) {
432 + // phpcs:disable
433 + error_log( 'ajax_process_donation_form_submission - response' );
434 + error_log( print_r( $response, true ) );
435 + // phpcs:enable
436 + }
437 +
438 + // Experimenting with a different response structure.
439 + // These are errors displayed to the user (and hopefully not loggeD).
440 + if ( ! empty( $response['errors'] ) ) {
441 + // Insert an element into the first position of the array.
442 + $response['errors'] = array_merge( array( 'An error occurred while processing your donation.' ), $response['errors'] );
443 + }
321 444 wp_send_json( $response );
322 445
323 446 exit();
324 447 }
@@ -341,8 +464,10 @@
341 464 /* Validate the form submission and retrieve the values. */
342 465 $form = new Charitable_Donation_Amount_Form( $campaign );
343 466
344 467 /**
468 + * Do something before the donation amount form is processed.
469 + *
345 470 * @hook charitable_before_process_donation_amount_form
346 471 */
347 472 do_action( 'charitable_before_process_donation_amount_form', $processor, $form );
348 473
@@ -355,8 +480,10 @@
355 480
356 481 charitable_get_session()->add_donation( $submitted['campaign_id'], $submitted['amount'], $period );
357 482
358 483 /**
484 + * Do something after the donation amount form is processed.
485 + *
359 486 * @hook charitable_after_process_donation_amount_form
360 487 */
361 488 do_action( 'charitable_after_process_donation_amount_form', $processor, $submitted );
362 489 }
@@ -362,9 +489,9 @@
362 489 }
363 490
364 491 $redirect_url = charitable_get_permalink( 'campaign_donation_page', array( 'campaign_id' => $campaign->ID ) );
365 492
366 - if ( 'same_page' == charitable_get_option( 'donation_form_display', 'separate_page' ) ) {
493 + if ( 'same_page' == charitable_get_option( 'donation_form_display', 'separate_page' ) ) { // phpcs:ignore
367 494 $redirect_url .= '#charitable-donation-form';
368 495 }
369 496
370 497 wp_safe_redirect( $redirect_url );
@@ -445,9 +572,9 @@
445 572 charitable_get_notices()->add_errors_from_wp_error( $donation_id );
446 573 return 0;
447 574 }
448 575
449 - if ( 0 == $donation_id ) {
576 + if ( 0 == $donation_id ) { // phpcs:ignore
450 577 charitable_get_notices()->add_error( __( 'We were unable to save the donation. Please try again.', 'charitable' ) );
451 578 return 0;
452 579 }
453 580
@@ -521,9 +648,9 @@
521 648
522 649 if ( array_key_exists( 'campaign_donation_id', $campaign ) ) {
523 650 $campaign_donation_id = $campaign['campaign_donation_id'];
524 651 } else {
525 - $campaign_donation_id = array_search( $campaign['campaign_id'], $campaign_donations );
652 + $campaign_donation_id = array_search( $campaign['campaign_id'], $campaign_donations ); // phpcs:ignore
526 653 }
527 654
528 655 /* Avoid adding duplicate campaign donations when re-submitting a campaign. */
529 656 if ( false !== $campaign_donation_id ) {
@@ -546,9 +673,9 @@
546 673 $campaign['donor_id'] = $donor_id;
547 674 $campaign['donation_id'] = $donation_id;
548 675 $campaign_donation_id = charitable_get_table( 'campaign_donations' )->insert( $campaign );
549 676
550 - if ( 0 == $campaign_donation_id ) {
677 + if ( 0 == $campaign_donation_id ) { // phpcs:ignore
551 678 return 0;
552 679 }
553 680 }
554 681 }//end foreach
@@ -662,9 +789,9 @@
662 789 * @param string $key The key to search for.
663 790 * @param mixed $default Fallback value to return if the data is not set.
664 791 * @return mixed
665 792 */
666 - public function get_donation_data_value( $key, $default = false ) {
793 + public function get_donation_data_value( $key, $default = false ) { // phpcs:ignore
667 794 $data = $this->get_donation_data();
668 795 return isset( $data[ $key ] ) ? $data[ $key ] : $default;
669 796 }
670 797
@@ -736,9 +863,9 @@
736 863 $this->donor_id = charitable_get_table( 'donors' )->get_donor_id_by_email( $user_data['email'] );
737 864 }
738 865
739 866 /* If we still do not have a donor ID, it means that this is a first-time donor */
740 - if ( 0 == $this->donor_id ) {
867 + if ( 0 == $this->donor_id ) { // phpcs:ignore
741 868 $user = new Charitable_User( $this->get_donation_data_value( 'user_id', get_current_user_id() ) );
742 869 $this->donor_id = $user->add_donor( $user_data );
743 870 }
744 871 }//end if
@@ -805,9 +932,9 @@
805 932 private function redirect_after_gateway_processing( $gateway_processing ) {
806 933 $redirect_url = $this->get_redirection_after_gateway_processing( $gateway_processing );
807 934
808 935 /* If the gateway processing failed, add the error notices to the session. */
809 - if ( false == $gateway_processing ) {
936 + if ( false == $gateway_processing ) { // phpcs:ignore
810 937
811 938 /* Log the failed payment. */
812 939 $this->update_donation_log(
813 940 $this->donation_id,
@@ -827,10 +954,10 @@
827 954 /**
828 955 * If the gateway processing returned an array with a directive to NOT
829 956 * use wp_safe_redirect, use wp_redirect instead.
830 957 */
831 - if ( isset( $gateway_processing['safe'] ) && false == $gateway_processing['safe'] ) {
832 - wp_redirect( $redirect_url, $status );
958 + if ( isset( $gateway_processing['safe'] ) && false == $gateway_processing['safe'] ) { // phpcs:ignore
959 + wp_safe_redirect( $redirect_url, $status );
833 960 die();
834 961 }
835 962
836 963 wp_safe_redirect( $redirect_url, $status );
@@ -846,9 +973,9 @@
846 973 * @param mixed $gateway_processing The result of the gateway processing.
847 974 * @return string
848 975 */
849 976 private function get_redirection_after_gateway_processing( $gateway_processing ) {
850 - if ( false == $gateway_processing ) {
977 + if ( false == $gateway_processing ) { // phpcs:ignore
851 978 $redirect_url = esc_url( add_query_arg( array( 'donation_id' => $this->donation_id ), wp_get_referer() ) );
852 979 } elseif ( is_array( $gateway_processing ) && isset( $gateway_processing['redirect'] ) ) {
853 980 $redirect_url = $gateway_processing['redirect'];
854 981 } else {
@@ -855,9 +982,9 @@
855 982 /* Fall back to returning the donation receipt URL. */
856 983 $redirect_url = charitable_get_permalink( 'donation_receipt_page', array( 'donation_id' => $this->donation_id ) );
857 984 }
858 985
859 - return $redirect_url;
986 + return apply_filters( 'charitable_redirection_after_gateway_processing', $redirect_url, $gateway_processing, $this );
860 987 }
861 988
862 989 /**
863 990 * Validate user data passed to insert.