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 +136 -40 1.7.0 → 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,14 +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 - error_log( 'gateway_is_130_compatible' );
263 - error_log( print_r( $gateway, true ) );
264 - error_log( print_r( $this->donation_id, true ) );
265 - error_log( print_r( $processor, true ) );
266 - 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 + }
267 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 +
268 316 } else {
269 317 /**
270 318 * Send donation processing to the payment gateway.
271 319 *
@@ -304,30 +352,28 @@
304 352
305 353 /**
306 354 * Add a donation with AJAX.
307 355 *
308 - * @since 1.3.0
356 + * @since 1.3.0
357 + * @version 1.8.7
309 358 *
310 359 * @return void
311 360 */
312 361 public static function ajax_process_donation_form_submission() {
313 362 /* Prevent any displayed errors from messing with the AJAX response. */
314 - 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 + }
315 368
316 - if ( ! isset( $_POST['campaign_id'] ) ) {
369 + if ( ! isset( $_POST['campaign_id'] ) ) { // @codingStandardsIgnoreLine
317 370 wp_send_json_error( new WP_Error( 'missing_campaign_id', __( 'Campaign ID was not found. Unable to create donation.', 'charitable' ) ) );
318 371 }
319 372
320 373 $processor = self::get_instance();
321 - $result = $processor->process_donation();
374 + $result = $processor->process_donation();
322 375
323 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
324 - error_log( '(inside?) ajax_process_donation_form_submission - processor' );
325 - error_log( print_r( $processor, true ) );
326 - error_log( 'ajax_process_donation_form_submission - result' );
327 - error_log( print_r( $result, true ) );
328 - }
329 -
330 376 $response = is_array( $result ) ? $result : array();
331 377
332 378 if ( $processor->donation_processed_successfully( $result ) ) {
333 379 $response['success'] = true;
@@ -332,24 +378,70 @@
332 378 if ( $processor->donation_processed_successfully( $result ) ) {
333 379 $response['success'] = true;
334 380 $response['redirect_to'] = $processor->get_redirection_after_gateway_processing( $result );
335 381 } else {
382 +
383 + // Start with getting errors from the notices class.
336 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 + }
337 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 +
338 395 if ( empty( $errors ) ) {
339 396 $errors = array( __( 'Unable to process donation.', 'charitable' ) );
340 397 }
341 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 +
342 408 $response['success'] = false;
343 409 $response['errors'] = $errors;
344 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 + }
345 429 }
346 430
347 - if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
431 + if ( charitable_is_debug() ) {
432 + // phpcs:disable
348 433 error_log( 'ajax_process_donation_form_submission - response' );
349 434 error_log( print_r( $response, true ) );
435 + // phpcs:enable
350 436 }
351 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 + }
352 444 wp_send_json( $response );
353 445
354 446 exit();
355 447 }
@@ -372,8 +464,10 @@
372 464 /* Validate the form submission and retrieve the values. */
373 465 $form = new Charitable_Donation_Amount_Form( $campaign );
374 466
375 467 /**
468 + * Do something before the donation amount form is processed.
469 + *
376 470 * @hook charitable_before_process_donation_amount_form
377 471 */
378 472 do_action( 'charitable_before_process_donation_amount_form', $processor, $form );
379 473
@@ -386,8 +480,10 @@
386 480
387 481 charitable_get_session()->add_donation( $submitted['campaign_id'], $submitted['amount'], $period );
388 482
389 483 /**
484 + * Do something after the donation amount form is processed.
485 + *
390 486 * @hook charitable_after_process_donation_amount_form
391 487 */
392 488 do_action( 'charitable_after_process_donation_amount_form', $processor, $submitted );
393 489 }
@@ -393,9 +489,9 @@
393 489 }
394 490
395 491 $redirect_url = charitable_get_permalink( 'campaign_donation_page', array( 'campaign_id' => $campaign->ID ) );
396 492
397 - 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
398 494 $redirect_url .= '#charitable-donation-form';
399 495 }
400 496
401 497 wp_safe_redirect( $redirect_url );
@@ -476,9 +572,9 @@
476 572 charitable_get_notices()->add_errors_from_wp_error( $donation_id );
477 573 return 0;
478 574 }
479 575
480 - if ( 0 == $donation_id ) {
576 + if ( 0 == $donation_id ) { // phpcs:ignore
481 577 charitable_get_notices()->add_error( __( 'We were unable to save the donation. Please try again.', 'charitable' ) );
482 578 return 0;
483 579 }
484 580
@@ -552,9 +648,9 @@
552 648
553 649 if ( array_key_exists( 'campaign_donation_id', $campaign ) ) {
554 650 $campaign_donation_id = $campaign['campaign_donation_id'];
555 651 } else {
556 - $campaign_donation_id = array_search( $campaign['campaign_id'], $campaign_donations );
652 + $campaign_donation_id = array_search( $campaign['campaign_id'], $campaign_donations ); // phpcs:ignore
557 653 }
558 654
559 655 /* Avoid adding duplicate campaign donations when re-submitting a campaign. */
560 656 if ( false !== $campaign_donation_id ) {
@@ -577,9 +673,9 @@
577 673 $campaign['donor_id'] = $donor_id;
578 674 $campaign['donation_id'] = $donation_id;
579 675 $campaign_donation_id = charitable_get_table( 'campaign_donations' )->insert( $campaign );
580 676
581 - if ( 0 == $campaign_donation_id ) {
677 + if ( 0 == $campaign_donation_id ) { // phpcs:ignore
582 678 return 0;
583 679 }
584 680 }
585 681 }//end foreach
@@ -693,9 +789,9 @@
693 789 * @param string $key The key to search for.
694 790 * @param mixed $default Fallback value to return if the data is not set.
695 791 * @return mixed
696 792 */
697 - public function get_donation_data_value( $key, $default = false ) {
793 + public function get_donation_data_value( $key, $default = false ) { // phpcs:ignore
698 794 $data = $this->get_donation_data();
699 795 return isset( $data[ $key ] ) ? $data[ $key ] : $default;
700 796 }
701 797
@@ -767,9 +863,9 @@
767 863 $this->donor_id = charitable_get_table( 'donors' )->get_donor_id_by_email( $user_data['email'] );
768 864 }
769 865
770 866 /* If we still do not have a donor ID, it means that this is a first-time donor */
771 - if ( 0 == $this->donor_id ) {
867 + if ( 0 == $this->donor_id ) { // phpcs:ignore
772 868 $user = new Charitable_User( $this->get_donation_data_value( 'user_id', get_current_user_id() ) );
773 869 $this->donor_id = $user->add_donor( $user_data );
774 870 }
775 871 }//end if
@@ -836,9 +932,9 @@
836 932 private function redirect_after_gateway_processing( $gateway_processing ) {
837 933 $redirect_url = $this->get_redirection_after_gateway_processing( $gateway_processing );
838 934
839 935 /* If the gateway processing failed, add the error notices to the session. */
840 - if ( false == $gateway_processing ) {
936 + if ( false == $gateway_processing ) { // phpcs:ignore
841 937
842 938 /* Log the failed payment. */
843 939 $this->update_donation_log(
844 940 $this->donation_id,
@@ -858,10 +954,10 @@
858 954 /**
859 955 * If the gateway processing returned an array with a directive to NOT
860 956 * use wp_safe_redirect, use wp_redirect instead.
861 957 */
862 - if ( isset( $gateway_processing['safe'] ) && false == $gateway_processing['safe'] ) {
863 - wp_redirect( $redirect_url, $status );
958 + if ( isset( $gateway_processing['safe'] ) && false == $gateway_processing['safe'] ) { // phpcs:ignore
959 + wp_safe_redirect( $redirect_url, $status );
864 960 die();
865 961 }
866 962
867 963 wp_safe_redirect( $redirect_url, $status );
@@ -877,9 +973,9 @@
877 973 * @param mixed $gateway_processing The result of the gateway processing.
878 974 * @return string
879 975 */
880 976 private function get_redirection_after_gateway_processing( $gateway_processing ) {
881 - if ( false == $gateway_processing ) {
977 + if ( false == $gateway_processing ) { // phpcs:ignore
882 978 $redirect_url = esc_url( add_query_arg( array( 'donation_id' => $this->donation_id ), wp_get_referer() ) );
883 979 } elseif ( is_array( $gateway_processing ) && isset( $gateway_processing['redirect'] ) ) {
884 980 $redirect_url = $gateway_processing['redirect'];
885 981 } else {
@@ -886,9 +982,9 @@
886 982 /* Fall back to returning the donation receipt URL. */
887 983 $redirect_url = charitable_get_permalink( 'donation_receipt_page', array( 'donation_id' => $this->donation_id ) );
888 984 }
889 985
890 - return $redirect_url;
986 + return apply_filters( 'charitable_redirection_after_gateway_processing', $redirect_url, $gateway_processing, $this );
891 987 }
892 988
893 989 /**
894 990 * Validate user data passed to insert.