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 +135 -41 1.7.0.3 → 1.8.13 View file →
@@ -3,9 +3,9 @@
3 3 * The class that is responsible for responding to donation events.
4 4 *
5 5 * @package Charitable/Classes/Charitable_Donation_Processor
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.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,10 +182,10 @@
172 182 public function process_donation() {
173 183 $processor = self::get_instance();
174 184 $campaign = $processor->get_campaign();
175 185
176 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
177 - error_log( 'process_donation start' );
186 + if ( charitable_is_debug() ) {
187 + error_log( 'process_donation start' ); // phpcs:ignore
178 188 }
179 189
180 190 if ( ! $campaign ) {
181 191 return;
@@ -180,14 +190,33 @@
180 190 if ( ! $campaign ) {
181 191 return;
182 192 }
183 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 +
184 202 /* Validate the form submission and retrieve the values. */
185 203 $form = $campaign->get_donation_form();
186 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
204 + if ( charitable_is_debug() ) {
205 + // phpcs:disable
206 + error_log( 'process_donation - form' );
187 207 error_log( print_r( $form, true ) );
208 + // phpcs:enable
188 209 }
189 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 +
190 219 /**
191 220 * Do something before any donation form processing takes place.
192 221 *
193 222 * @since 1.0.0
@@ -197,10 +226,12 @@
197 226 */
198 227 do_action( 'charitable_before_process_donation_form', $processor, $form );
199 228
200 229 if ( ! $form->validate_submission() ) {
201 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
202 - error_log( 'validation form not valid' );
230 + if ( charitable_is_debug() ) {
231 + // phpcs:disable
232 + error_log( 'Validation form not valid' );
233 + // phpcs:enable
203 234 }
204 235 return false;
205 236 }
206 237
@@ -206,8 +237,17 @@
206 237
207 238 $values = $form->get_donation_values();
208 239 $gateway = $values['gateway'];
209 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 +
210 250 /**
211 251 * Validate the gateway values.
212 252 *
213 253 * @since 1.0.0
@@ -216,12 +256,14 @@
216 256 * @param string $gateway The gateway ID.
217 257 * @param array $values The values submitted by the user.
218 258 */
219 259 if ( ! apply_filters( 'charitable_validate_donation_form_submission_gateway', true, $gateway, $values ) ) {
220 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
260 + if ( charitable_is_debug() ) {
261 + // phpcs:disable
221 262 error_log( 'process_donation not valid' );
222 263 error_log( print_r( $gateway, true ) );
223 264 error_log( print_r( $values, true ) );
265 + // phpcs:enable
224 266 }
225 267 return false;
226 268 }
227 269
@@ -258,16 +300,20 @@
258 300 * @param int $donation_id The donation ID.
259 301 * @param Charitable_Donation_Processor $processor The Donation Processor object.
260 302 * @return mixed
261 303 */
262 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
263 - error_log( 'gateway_is_130_compatible' );
264 - error_log( print_r( $gateway, true ) );
265 - error_log( print_r( $this->donation_id, true ) );
266 - error_log( print_r( $processor, true ) );
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
267 310 }
268 - return apply_filters( 'charitable_process_donation_' . $gateway, true, $this->donation_id, $processor );
269 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 +
270 316 } else {
271 317 /**
272 318 * Send donation processing to the payment gateway.
273 319 *
@@ -306,30 +352,28 @@
306 352
307 353 /**
308 354 * Add a donation with AJAX.
309 355 *
310 - * @since 1.3.0
356 + * @since 1.3.0
357 + * @version 1.8.7
311 358 *
312 359 * @return void
313 360 */
314 361 public static function ajax_process_donation_form_submission() {
315 362 /* Prevent any displayed errors from messing with the AJAX response. */
316 - ini_set( 'display_errors', true );
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 + }
317 368
318 - if ( ! isset( $_POST['campaign_id'] ) ) {
369 + if ( ! isset( $_POST['campaign_id'] ) ) { // @codingStandardsIgnoreLine
319 370 wp_send_json_error( new WP_Error( 'missing_campaign_id', __( 'Campaign ID was not found. Unable to create donation.', 'charitable' ) ) );
320 371 }
321 372
322 373 $processor = self::get_instance();
323 - $result = $processor->process_donation();
374 + $result = $processor->process_donation();
324 375
325 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
326 - error_log( '(inside?) ajax_process_donation_form_submission - processor' );
327 - error_log( print_r( $processor, true ) );
328 - error_log( 'ajax_process_donation_form_submission - result' );
329 - error_log( print_r( $result, true ) );
330 - }
331 -
332 376 $response = is_array( $result ) ? $result : array();
333 377
334 378 if ( $processor->donation_processed_successfully( $result ) ) {
335 379 $response['success'] = true;
@@ -334,24 +378,70 @@
334 378 if ( $processor->donation_processed_successfully( $result ) ) {
335 379 $response['success'] = true;
336 380 $response['redirect_to'] = $processor->get_redirection_after_gateway_processing( $result );
337 381 } else {
382 +
383 + // Start with getting errors from the notices class.
338 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 + }
339 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 +
340 395 if ( empty( $errors ) ) {
341 396 $errors = array( __( 'Unable to process donation.', 'charitable' ) );
342 397 }
343 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 +
344 408 $response['success'] = false;
345 409 $response['errors'] = $errors;
346 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 + }
347 429 }
348 430
349 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
431 + if ( charitable_is_debug() ) {
432 + // phpcs:disable
350 433 error_log( 'ajax_process_donation_form_submission - response' );
351 434 error_log( print_r( $response, true ) );
435 + // phpcs:enable
352 436 }
353 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 + }
354 444 wp_send_json( $response );
355 445
356 446 exit();
357 447 }
@@ -374,8 +464,10 @@
374 464 /* Validate the form submission and retrieve the values. */
375 465 $form = new Charitable_Donation_Amount_Form( $campaign );
376 466
377 467 /**
468 + * Do something before the donation amount form is processed.
469 + *
378 470 * @hook charitable_before_process_donation_amount_form
379 471 */
380 472 do_action( 'charitable_before_process_donation_amount_form', $processor, $form );
381 473
@@ -388,8 +480,10 @@
388 480
389 481 charitable_get_session()->add_donation( $submitted['campaign_id'], $submitted['amount'], $period );
390 482
391 483 /**
484 + * Do something after the donation amount form is processed.
485 + *
392 486 * @hook charitable_after_process_donation_amount_form
393 487 */
394 488 do_action( 'charitable_after_process_donation_amount_form', $processor, $submitted );
395 489 }
@@ -395,9 +489,9 @@
395 489 }
396 490
397 491 $redirect_url = charitable_get_permalink( 'campaign_donation_page', array( 'campaign_id' => $campaign->ID ) );
398 492
399 - 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
400 494 $redirect_url .= '#charitable-donation-form';
401 495 }
402 496
403 497 wp_safe_redirect( $redirect_url );
@@ -478,9 +572,9 @@
478 572 charitable_get_notices()->add_errors_from_wp_error( $donation_id );
479 573 return 0;
480 574 }
481 575
482 - if ( 0 == $donation_id ) {
576 + if ( 0 == $donation_id ) { // phpcs:ignore
483 577 charitable_get_notices()->add_error( __( 'We were unable to save the donation. Please try again.', 'charitable' ) );
484 578 return 0;
485 579 }
486 580
@@ -554,9 +648,9 @@
554 648
555 649 if ( array_key_exists( 'campaign_donation_id', $campaign ) ) {
556 650 $campaign_donation_id = $campaign['campaign_donation_id'];
557 651 } else {
558 - $campaign_donation_id = array_search( $campaign['campaign_id'], $campaign_donations );
652 + $campaign_donation_id = array_search( $campaign['campaign_id'], $campaign_donations ); // phpcs:ignore
559 653 }
560 654
561 655 /* Avoid adding duplicate campaign donations when re-submitting a campaign. */
562 656 if ( false !== $campaign_donation_id ) {
@@ -579,9 +673,9 @@
579 673 $campaign['donor_id'] = $donor_id;
580 674 $campaign['donation_id'] = $donation_id;
581 675 $campaign_donation_id = charitable_get_table( 'campaign_donations' )->insert( $campaign );
582 676
583 - if ( 0 == $campaign_donation_id ) {
677 + if ( 0 == $campaign_donation_id ) { // phpcs:ignore
584 678 return 0;
585 679 }
586 680 }
587 681 }//end foreach
@@ -695,9 +789,9 @@
695 789 * @param string $key The key to search for.
696 790 * @param mixed $default Fallback value to return if the data is not set.
697 791 * @return mixed
698 792 */
699 - public function get_donation_data_value( $key, $default = false ) {
793 + public function get_donation_data_value( $key, $default = false ) { // phpcs:ignore
700 794 $data = $this->get_donation_data();
701 795 return isset( $data[ $key ] ) ? $data[ $key ] : $default;
702 796 }
703 797
@@ -769,9 +863,9 @@
769 863 $this->donor_id = charitable_get_table( 'donors' )->get_donor_id_by_email( $user_data['email'] );
770 864 }
771 865
772 866 /* If we still do not have a donor ID, it means that this is a first-time donor */
773 - if ( 0 == $this->donor_id ) {
867 + if ( 0 == $this->donor_id ) { // phpcs:ignore
774 868 $user = new Charitable_User( $this->get_donation_data_value( 'user_id', get_current_user_id() ) );
775 869 $this->donor_id = $user->add_donor( $user_data );
776 870 }
777 871 }//end if
@@ -838,9 +932,9 @@
838 932 private function redirect_after_gateway_processing( $gateway_processing ) {
839 933 $redirect_url = $this->get_redirection_after_gateway_processing( $gateway_processing );
840 934
841 935 /* If the gateway processing failed, add the error notices to the session. */
842 - if ( false == $gateway_processing ) {
936 + if ( false == $gateway_processing ) { // phpcs:ignore
843 937
844 938 /* Log the failed payment. */
845 939 $this->update_donation_log(
846 940 $this->donation_id,
@@ -860,10 +954,10 @@
860 954 /**
861 955 * If the gateway processing returned an array with a directive to NOT
862 956 * use wp_safe_redirect, use wp_redirect instead.
863 957 */
864 - if ( isset( $gateway_processing['safe'] ) && false == $gateway_processing['safe'] ) {
865 - wp_redirect( $redirect_url, $status );
958 + if ( isset( $gateway_processing['safe'] ) && false == $gateway_processing['safe'] ) { // phpcs:ignore
959 + wp_safe_redirect( $redirect_url, $status );
866 960 die();
867 961 }
868 962
869 963 wp_safe_redirect( $redirect_url, $status );
@@ -879,9 +973,9 @@
879 973 * @param mixed $gateway_processing The result of the gateway processing.
880 974 * @return string
881 975 */
882 976 private function get_redirection_after_gateway_processing( $gateway_processing ) {
883 - if ( false == $gateway_processing ) {
977 + if ( false == $gateway_processing ) { // phpcs:ignore
884 978 $redirect_url = esc_url( add_query_arg( array( 'donation_id' => $this->donation_id ), wp_get_referer() ) );
885 979 } elseif ( is_array( $gateway_processing ) && isset( $gateway_processing['redirect'] ) ) {
886 980 $redirect_url = $gateway_processing['redirect'];
887 981 } else {
@@ -888,9 +982,9 @@
888 982 /* Fall back to returning the donation receipt URL. */
889 983 $redirect_url = charitable_get_permalink( 'donation_receipt_page', array( 'donation_id' => $this->donation_id ) );
890 984 }
891 985
892 - return $redirect_url;
986 + return apply_filters( 'charitable_redirection_after_gateway_processing', $redirect_url, $gateway_processing, $this );
893 987 }
894 988
895 989 /**
896 990 * Validate user data passed to insert.