PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.6.8
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.6.8
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 1.7.0.9 1.8.0 All 210 releases
charitable / includes / donations / class-charitable-donation-processor.php

class-charitable-donation-processor.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.6.8, at includes/donations/class-charitable-donation-processor.php

938 lines 26.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The class that is responsible for responding to donation events.
4 *
5 * @version 1.0.0
6 * @package Charitable/Classes/Charitable_Donation_Processor
7 * @author Eric Daams
8 * @copyright Copyright (c) 2019, Studio 164a
9 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) { exit; }
14
15 if ( ! class_exists( 'Charitable_Donation_Processor' ) ) :
16
17 /**
18 * Charitable Donation Processor.
19 *
20 * @since 1.0.0
21 */
22 class Charitable_Donation_Processor {
23
24 /**
25 * The single instance of this class.
26 *
27 * @var Charitable_Donation_Processor|null
28 */
29 private static $instance = null;
30
31 /**
32 * The campaign receiving a donation.
33 *
34 * @var Charitable_Campaign|false
35 */
36 protected $campaign;
37
38 /**
39 * The donation data.
40 *
41 * @var mixed[]
42 */
43 protected $donation_data;
44
45 /**
46 * The campaign donations array.
47 *
48 * @var array
49 */
50 protected $campaign_donations_data;
51
52 /**
53 * The donor ID for the current donation.
54 *
55 * @var int
56 */
57 protected $donor_id;
58
59 /**
60 * The donoration ID for the current donation.
61 *
62 * @var int
63 */
64 protected $donation_id;
65
66 /**
67 * Create class object. A protected constructor, so this is used in a singleton context.
68 *
69 * @since 1.0.0
70 */
71 protected function __construct() {
72 $this->campaign = charitable_get_current_campaign();
73 }
74
75 /**
76 * Returns and/or create the single instance of this class.
77 *
78 * @since 1.0.0
79 *
80 * @return Charitable_Donation_Processor
81 */
82 public static function get_instance() {
83 if ( is_null( self::$instance ) ) {
84 self::$instance = new self();
85 }
86
87 return self::$instance;
88 }
89
90 /**
91 * Destroy the Charitable_Donation_Processor instance.
92 *
93 * This is primarily useful for testing purposes, as it allows you to
94 * create multiple donations in a single request.
95 *
96 * @since 1.3.0
97 *
98 * @return void
99 */
100 public static function destroy() {
101 self::$instance = null;
102 }
103
104 /**
105 * Return the current campaign.
106 *
107 * @since 1.0.0
108 *
109 * @return Charitable_Campaign|false False if no campaign is set. Campaign object otherwise.
110 */
111 public function get_campaign() {
112 return $this->campaign;
113 }
114
115 /**
116 * Return the donation ID.
117 *
118 * @since 1.4.0
119 *
120 * @return int
121 */
122 public function get_donation_id() {
123 return $this->donation_id;
124 }
125
126 /**
127 * Executed when a user first clicks the Donate button on a campaign.
128 *
129 * @since 1.0.0
130 *
131 * @return void
132 */
133 public static function add_donation_to_session() {
134 $processor = self::get_instance();
135
136 if ( ! $processor->get_campaign() ) {
137 return;
138 }
139
140 $nonce = $_POST['charitable-donate-now'];
141
142 if ( ! wp_verify_nonce( $nonce, 'charitable-donate' ) ) {
143
144 /* For backwards compatibility, we also check this nonce. */
145 if ( ! wp_verify_nonce( $nonce, 'charitable-donate-' ) ) {
146 return;
147 }
148 }
149
150 /* Save the donation in the session */
151 charitable_get_session()->add_donation( $processor->get_campaign()->ID, 0 );
152
153 $donations_url = charitable_get_permalink( 'campaign_donation_page', array( 'campaign_id' => $processor->get_campaign()->ID ) );
154
155 wp_redirect( $donations_url );
156
157 die();
158 }
159
160 /**
161 * Process the donation.
162 *
163 * This is used by all donation form submissions, AJAX or not.
164 *
165 * @since 1.3.0
166 *
167 * @return mixed
168 */
169 public function process_donation() {
170 $processor = self::get_instance();
171 $campaign = $processor->get_campaign();
172
173 if ( ! $campaign ) {
174 return;
175 }
176
177 /* Validate the form submission and retrieve the values. */
178 $form = $campaign->get_donation_form();
179
180 /**
181 * Do something before any donation form processing takes place.
182 *
183 * @since 1.0.0
184 *
185 * @param Charitable_Donation_Processor $processor The Donation Processor object.
186 * @param Charitable_Donation_Form $form The Donation Form object.
187 */
188 do_action( 'charitable_before_process_donation_form', $processor, $form );
189
190 if ( ! $form->validate_submission() ) {
191 return false;
192 }
193
194 $values = $form->get_donation_values();
195 $gateway = $values['gateway'];
196
197 /**
198 * Validate the gateway values.
199 *
200 * @since 1.0.0
201 *
202 * @param boolean $valid Whether the submission passes validation.
203 * @param string $gateway The gateway ID.
204 * @param array $values The values submitted by the user.
205 */
206 if ( ! apply_filters( 'charitable_validate_donation_form_submission_gateway', true, $gateway, $values ) ) {
207 return false;
208 }
209
210 $this->donation_id = $processor->save_donation( $values );
211
212 /**
213 * Set a transient to allow plugins to act on this donation on the next page load.
214 */
215 set_transient( 'charitable_donation_' . charitable_get_session()->get_session_id(), $this );
216
217 /**
218 * We check whether the gateway is compatible with version 1.3, since Charitable 1.3
219 * change the hook into a filter (instead of an action).
220 */
221 if ( $this->gateway_is_130_compatible( $gateway ) ) {
222
223 /**
224 * Pass donation processing to the payment gateway and return the results.
225 *
226 * Clients should return one of three results:
227 *
228 * - TRUE : If the donation was processed successfully and the user should
229 * be redirected to the donation receipt.
230 * - FALSE : If the donation could not be processed successfully and the user
231 * should be redirected back to the donation form.
232 * - ARRAY : If the user needs to be redirected somewhere other than the donation
233 * receipt or donation form. Array should contain two values:
234 * `redirect` : The url to be redirected to.
235 * `safe` : Whether to use wp_safe_redirect. If unset, will default to true.
236 *
237 * @since 1.3.0
238 *
239 * @param mixed $result The result of gateway processing.
240 * @param int $donation_id The donation ID.
241 * @param Charitable_Donation_Processor $processor The Donation Processor object.
242 * @return mixed
243 */
244 return apply_filters( 'charitable_process_donation_' . $gateway, true, $this->donation_id, $processor );
245
246 } else {
247 /**
248 * Send donation processing to the payment gateway.
249 *
250 * This is a fallback for payment gateways that have not been updated to the filter method above.
251 *
252 * @since 1.0.0
253 *
254 * @param int $donation_id The donation ID.
255 * @param Charitable_Donation_Processor $processor The Donation Processor object.
256 */
257 do_action( 'charitable_process_donation_' . $gateway, $this->donation_id, $processor );
258
259 /**
260 * If we get this far, forward the user through to the receipt page.
261 */
262 wp_safe_redirect( charitable_get_permalink( 'donation_receipt_page', array( 'donation_id' => $this->donation_id ) ) );
263
264 die();
265
266 }//end if
267 }
268
269 /**
270 * Save a donation submitted through a page reload (i.e. not AJAX).
271 *
272 * @since 1.0.0
273 *
274 * @return void
275 */
276 public static function process_donation_form_submission() {
277
278 $processor = self::get_instance();
279 $result = $processor->process_donation();
280
281 $processor->redirect_after_gateway_processing( $result );
282
283 }
284
285 /**
286 * Add a donation with AJAX.
287 *
288 * @since 1.3.0
289 *
290 * @return void
291 */
292 public static function ajax_process_donation_form_submission() {
293 if ( ! isset( $_POST['campaign_id'] ) ) {
294 wp_send_json_error( new WP_Error( 'missing_campaign_id', __( 'Campaign ID was not found. Unable to create donation.', 'charitable' ) ) );
295 }
296
297 $processor = self::get_instance();
298
299 $result = $processor->process_donation();
300
301 if ( $result ) {
302 $response = array(
303 'success' => true,
304 'redirect_to' => $processor->get_redirection_after_gateway_processing( $result ),
305 );
306 } else {
307 $errors = charitable_get_notices()->get_errors();
308
309 if ( empty( $errors ) ) {
310 $errors = array( __( 'Unable to process donation.', 'charitable' ) );
311 }
312
313 $response = array(
314 'success' => false,
315 'errors' => $errors,
316 'donation_id' => (int) $processor->get_donation_id(),
317 );
318 }
319
320 wp_send_json( $response );
321
322 exit();
323 }
324
325 /**
326 * Save a donation.
327 *
328 * @since 1.0.0
329 *
330 * @return void
331 */
332 public static function make_donation_streamlined() {
333 $processor = self::get_instance();
334 $campaign = $processor->get_campaign();
335
336 if ( ! $campaign ) {
337 return;
338 }
339
340 /* Validate the form submission and retrieve the values. */
341 $form = new Charitable_Donation_Amount_Form( $campaign );
342
343 /**
344 * @hook charitable_before_process_donation_amount_form
345 */
346 do_action( 'charitable_before_process_donation_amount_form', $processor, $form );
347
348 /**
349 * Form validated, so add the donation to session.
350 */
351 if ( $form->validate_submission() ) {
352
353 $submitted = $form->get_donation_values();
354
355 charitable_get_session()->add_donation( $submitted['campaign_id'], $submitted['amount'] );
356
357 /**
358 * @hook charitable_after_process_donation_amount_form
359 */
360 do_action( 'charitable_after_process_donation_amount_form', $processor, $submitted );
361 }
362
363 $redirect_url = charitable_get_permalink( 'campaign_donation_page', array( 'campaign_id' => $campaign->ID ) );
364
365 if ( 'same_page' == charitable_get_option( 'donation_form_display', 'separate_page' ) ) {
366 $redirect_url .= '#charitable-donation-form';
367 }
368
369 wp_safe_redirect( $redirect_url );
370 die();
371 }
372
373 /**
374 * Inserts a new donation.
375 *
376 * This method is designed to be completely form agnostic.
377 *
378 * We use this when integrating third-party systems like Easy Digital Downloads and
379 * WooCommerce.
380 *
381 * @since 1.0.0
382 *
383 * @param mixed[] $values Submitted donation values.
384 * @return int $donation_id Returns 0 in case of failure. Positive donation ID otherwise.
385 */
386 public function save_donation( array $values ) {
387 /**
388 * Filter the donation values to be saved.
389 *
390 * @since 1.0.0
391 *
392 * @param array $values The donation values to be saved.
393 */
394 $this->donation_data = apply_filters( 'charitable_donation_values', $values );
395
396 if ( ! $this->get_campaign_donations_data() ) {
397 charitable_get_deprecated()->doing_it_wrong(
398 __METHOD__,
399 __( 'A donation cannot be inserted without an array of campaigns being donated to.', 'charitable' ),
400 '1.0.0'
401 );
402 return 0;
403 }
404
405 if ( ! $this->is_valid_user_data() ) {
406 charitable_get_deprecated()->doing_it_wrong(
407 __METHOD__,
408 __( 'A donation cannot be inserted without valid user data.', 'charitable' ),
409 '1.0.0'
410 );
411 return 0;
412 }
413
414 /**
415 * Do something right before the donation is inserted into the database.
416 *
417 * @since 1.0.0
418 *
419 * @param Charitable_Donation_Processor $this The Processor instance.
420 */
421 do_action( 'charitable_before_save_donation', $this );
422
423 $donation_id = wp_insert_post( $this->parse_donation_data() );
424
425 $this->set_donation_key();
426
427 if ( is_wp_error( $donation_id ) ) {
428 charitable_get_notices()->add_errors_from_wp_error( $donation_id );
429 return 0;
430 }
431
432 if ( 0 == $donation_id ) {
433 charitable_get_notices()->add_error( __( 'We were unable to save the donation. Please try again.', 'charitable' ) );
434 return 0;
435 }
436
437 $this->save_campaign_donations( $donation_id );
438
439 $this->save_donation_meta( $donation_id );
440
441 $this->save_donor_contact_consent();
442
443 $log_note = array_key_exists( 'log_note', $values ) ? $values['log_note'] : '';
444
445 if ( empty( $log_note ) ) {
446 $log_note = isset( $values['ID'] ) && 0 !== $values['ID'] ? __( 'Payment attempted.', 'charitable' ) : __( 'Donation created.', 'charitable' );
447 }
448
449 $this->update_donation_log( $donation_id, $log_note );
450
451 /**
452 * Update the user session if we're on the public site or in an AJAX request.
453 *
454 * 1. Write the donation key to the session.
455 * 2. Write the campaign donation amounts to the session. This is required in
456 * case the donor gets sent back to the donation form (cancellation, failure).
457 */
458 if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
459
460 $session = charitable_get_session();
461
462 /* Required for the donation receipt to load for logged out donors. */
463 $session->add_donation_key( $this->get_donation_data_value( 'donation_key' ) );
464
465 /* Required in case the donor is redirected back to the donation form. */
466 foreach ( $this->get_campaign_donations_data() as $campaign ) {
467 $session->add_donation( $campaign['campaign_id'], $campaign['amount'] );
468 }
469 }
470
471 /**
472 * Do something after the donation has been saved in the database.
473 *
474 * @since 1.0.0
475 *
476 * @param int $donation_id The donation ID.
477 * @param Charitable_Donation_Processor $this The Processor instance.
478 */
479 do_action( 'charitable_after_save_donation', $donation_id, $this );
480
481 return $donation_id;
482 }
483
484 /**
485 * Inserts the campaign donations into the campaign_donations table.
486 *
487 * @since 1.0.0
488 *
489 * @param int $donation_id The donation ID.
490 * @return int The number of donations inserted.
491 */
492 public function save_campaign_donations( $donation_id ) {
493 $donor_id = $this->get_donor_id();
494 $campaigns = $this->get_campaign_donations_data();
495
496 if ( false !== $this->get_donation_data_value( 'ID', false ) ) {
497 $records = charitable_get_table( 'campaign_donations' )->get_donation_records( $donation_id );
498 $campaign_donations = wp_list_pluck( $records, 'campaign_id', 'campaign_donation_id' );
499 } else {
500 $campaign_donations = array();
501 }
502
503 foreach ( $campaigns as $campaign ) {
504
505 if ( array_key_exists( 'campaign_donation_id', $campaign ) ) {
506 $campaign_donation_id = $campaign['campaign_donation_id'];
507 } else {
508 $campaign_donation_id = array_search( $campaign['campaign_id'], $campaign_donations );
509 }
510
511 /* Avoid adding duplicate campaign donations when re-submitting a campaign. */
512 if ( false !== $campaign_donation_id ) {
513
514 /* Cast the existing campaign_donation record to an array and sanitize the amount. */
515 $campaign_donation = (array) $records[ $campaign_donation_id ];
516 $campaign_donation['amount'] = charitable_sanitize_amount( $campaign_donation['amount'], true );
517
518 /* Get our updated campaign donation values. */
519 $args = charitable_array_subset( $campaign, array( 'campaign_id', 'campaign_name', 'amount' ) );
520 $args['donor_id'] = $donor_id;
521
522 /* If any values have changed, update the record. */
523 if ( count( array_diff( $args, $campaign_donation ) ) ) {
524 charitable_get_table( 'campaign_donations' )->update( $campaign_donation_id, $args, 'campaign_donation_id' );
525 }
526 } else {
527
528 /* Add a new donation */
529 $campaign['donor_id'] = $donor_id;
530 $campaign['donation_id'] = $donation_id;
531 $campaign_donation_id = charitable_get_table( 'campaign_donations' )->insert( $campaign );
532
533 if ( 0 == $campaign_donation_id ) {
534 return 0;
535 }
536 }
537 }//end foreach
538
539 return count( $campaigns );
540 }
541
542 /**
543 * Save the meta for the donation.
544 *
545 * @since 1.0.0
546 *
547 * @param int $donation_id The donation ID.
548 * @return void
549 */
550 public function save_donation_meta( $donation_id ) {
551 $meta = array(
552 'donation_gateway' => $this->get_donation_data_value( 'gateway' ),
553 'donor' => $this->get_donation_data_value( 'user' ),
554 'test_mode' => charitable_get_option( 'test_mode', 0 ),
555 'donation_key' => $this->get_donation_data_value( 'donation_key' ),
556 );
557
558 if ( $this->get_donation_data_value( 'meta' ) ) {
559 $meta = array_merge( $meta, $this->get_donation_data_value( 'meta' ) );
560 }
561
562 /**
563 * Filter the donation meta to be saved.
564 *
565 * @since 1.0.0
566 *
567 * @param array $meta The meta to be saved, in a key=>value array.
568 * @param int $donation_id The donation ID.
569 * @param Charitable_Donation_Processor $processor This instance of `Charitable_Donation_Processor`.
570 */
571 $meta = apply_filters( 'charitable_donation_meta', $meta, $donation_id, $this );
572
573 foreach ( $meta as $meta_key => $value ) {
574 /**
575 * Sanitize a particular meta value.
576 *
577 * @since 1.0.0
578 *
579 * @param mixed $value The value.
580 * @param string $meta_key The meta key.
581 */
582 $value = apply_filters( 'charitable_sanitize_donation_meta', $value, $meta_key );
583 update_post_meta( $donation_id, $meta_key, $value );
584 }
585 }
586
587 /**
588 * Save whether the donor gave consent to be contacted.
589 *
590 * @since 1.6.0
591 *
592 * @return void
593 */
594 public function save_donor_contact_consent() {
595 /* Contact consent requires he database upgrade to have been completed. */
596 if ( ! charitable_is_contact_consent_activated() ) {
597 return;
598 }
599
600 $donor_id = $this->get_donor_id();
601 $meta = $this->get_donation_data_value( 'meta' );
602 $contact_consent = array_key_exists( 'contact_consent', $meta ) ? (bool) $meta['contact_consent'] : false;
603
604 charitable_get_table( 'donors' )->update( $donor_id, array(
605 'contact_consent' => $contact_consent,
606 ) );
607 }
608
609 /**
610 * Add a message to the donation log.
611 *
612 * @since 1.0.0
613 *
614 * @param int $donation_id The donation ID.
615 * @param string $message The message to add to the log.
616 * @return void
617 */
618 public function update_donation_log( $donation_id, $message ) {
619 $donation = charitable_get_donation( $donation_id );
620 if ( $donation ) {
621 $donation->log()->add( $message );
622 }
623 }
624
625 /**
626 * Returns the submitted donation data.
627 *
628 * @since 1.0.0
629 *
630 * @return mixed[]
631 */
632 public function get_donation_data() {
633 return $this->donation_data;
634 }
635
636 /**
637 * Return the submitted value for a particular key.
638 *
639 * @since 1.0.0
640 *
641 * @param string $key The key to search for.
642 * @param mixed $default Fallback value to return if the data is not set.
643 * @return mixed
644 */
645 public function get_donation_data_value( $key, $default = false ) {
646 $data = $this->get_donation_data();
647 return isset( $data[ $key ] ) ? $data[ $key ] : $default;
648 }
649
650 /**
651 * Set a value for a particular key.
652 *
653 * @since 1.4.0
654 *
655 * @param string $key The key to set.
656 * @param mixed $value The value to be set.
657 * @return void
658 */
659 public function set_donation_data_value( $key, $value ) {
660 $this->donation_data[ $key ] = $value;
661 }
662
663 /**
664 * Returns the campaign donations array, or false if the data is invalid.
665 *
666 * @since 1.0.0
667 *
668 * @return string[]|false
669 */
670 public function get_campaign_donations_data() {
671 if ( ! isset( $this->campaign_donations_data ) ) {
672
673 if ( ! is_array( $this->get_donation_data_value( 'campaigns' ) ) ) {
674 return false;
675 }
676
677 $this->campaign_donations_data = array();
678
679 foreach ( $this->get_donation_data_value( 'campaigns' ) as $campaign ) {
680
681 /* If the amount or campaign_id are missing, this donation won't work. */
682 if ( ! isset( $campaign['campaign_id'] ) || ! isset( $campaign['amount'] ) ) {
683 return false;
684 }
685
686 if ( ! isset( $campaign['campaign_name'] ) ) {
687 $campaign['campaign_name'] = get_the_title( $campaign['campaign_id'] );
688 }
689
690 $this->campaign_donations_data[] = $campaign;
691 }
692 }//end if
693
694 return $this->campaign_donations_data;
695 }
696
697 /**
698 * Returns the donor_id for the current donation.
699 *
700 * @since 1.0.0
701 *
702 * @return int
703 */
704 public function get_donor_id() {
705 if ( ! isset( $this->donor_id ) ) {
706 $this->donor_id = $this->get_donation_data_value( 'donor_id', 0 );
707
708 if ( $this->donor_id ) {
709 return $this->donor_id;
710 }
711
712 $user_data = $this->get_donation_data_value( 'user', array() );
713
714 if ( array_key_exists( 'email', $user_data ) ) {
715 $this->donor_id = charitable_get_table( 'donors' )->get_donor_id_by_email( $user_data['email'] );
716 }
717
718 /* If we still do not have a donor ID, it means that this is a first-time donor */
719 if ( 0 == $this->donor_id ) {
720 $user = new Charitable_User( $this->get_donation_data_value( 'user_id', get_current_user_id() ) );
721 $this->donor_id = $user->add_donor( $user_data );
722 }
723 }//end if
724
725 return $this->donor_id;
726 }
727
728 /**
729 * Redirect the user after the gateway has processed the donation.
730 *
731 * @uses Charitable_Donation_Processor::get_redirection_after_gateway_processing()
732 *
733 * @since 1.3.0
734 *
735 * @param mixed $gateway_processing The result of the gateway processing.
736 * @return void
737 */
738 private function redirect_after_gateway_processing( $gateway_processing ) {
739 $redirect_url = $this->get_redirection_after_gateway_processing( $gateway_processing );
740
741 /* If the gateway processing failed, add the error notices to the session. */
742 if ( false == $gateway_processing ) {
743
744 /* Log the failed payment. */
745 $this->update_donation_log(
746 $this->donation_id,
747 sprintf(
748 /* translators: %s: error message */
749 __( 'Payment failed with errors: %s', 'charitable' ),
750 PHP_EOL . implode( PHP_EOL, charitable_get_notices()->get_errors() )
751 )
752 );
753
754 charitable_get_session()->add_notices();
755 }
756
757 /* Set the redirect status to use. */
758 $status = isset( $gateway_processing['status'] ) ? $gateway_processing['status'] : 302;
759
760 /**
761 * If the gateway processing returned an array with a directive to NOT
762 * use wp_safe_redirect, use wp_redirect instead.
763 */
764 if ( isset( $gateway_processing['safe'] ) && false == $gateway_processing['safe'] ) {
765 wp_redirect( $redirect_url, $status );
766 die();
767 }
768
769 wp_safe_redirect( $redirect_url, $status );
770
771 die();
772 }
773
774 /**
775 * Return the URL that the donor should be redirected to.
776 *
777 * @since 1.3.0
778 *
779 * @param mixed $gateway_processing The result of the gateway processing.
780 * @return string
781 */
782 private function get_redirection_after_gateway_processing( $gateway_processing ) {
783 if ( false == $gateway_processing ) {
784
785 $redirect_url = esc_url( add_query_arg( array( 'donation_id' => $this->donation_id ), wp_get_referer() ) );
786
787 } elseif ( is_array( $gateway_processing ) && isset( $gateway_processing['redirect'] ) ) {
788
789 $redirect_url = $gateway_processing['redirect'];
790
791 } else {
792
793 /* Fall back to returning the donation receipt URL. */
794 $redirect_url = charitable_get_permalink( 'donation_receipt_page', array( 'donation_id' => $this->donation_id ) );
795
796 }
797
798 return $redirect_url;
799 }
800
801 /**
802 * Validate user data passed to insert.
803 *
804 * @since 1.0.0
805 *
806 * @return boolean
807 */
808 protected function is_valid_user_data() {
809 if ( charitable_permit_donor_without_email() ) {
810 return true;
811 }
812
813 $ret = $this->get_donation_data_value( 'user_id' ) || $this->get_donation_data_value( 'donor_id' );
814
815 if ( ! $ret ) {
816 $user = $this->get_donation_data_value( 'user', array() );
817 $ret = array_key_exists( 'email', $user ) && strlen( $user['email'] );
818 }
819
820 return $ret;
821 }
822
823 /**
824 * Parse the donation data, based on the passed $values array.
825 *
826 * @since 1.0.0
827 *
828 * @return array
829 */
830 protected function parse_donation_data() {
831 $core_values = array(
832 'ID' => $this->get_donation_data_value( 'ID', 0 ),
833 'post_type' => Charitable::DONATION_POST_TYPE,
834 'post_author' => $this->get_donation_data_value( 'user_id', get_current_user_id() ),
835 'post_status' => $this->get_donation_status(),
836 'post_content' => $this->get_donation_data_value( 'note', '' ),
837 'post_parent' => $this->get_donation_data_value( 'donation_plan', 0 ),
838 'post_date_gmt' => $this->get_donation_data_value( 'date_gmt', current_time( 'mysql', true ) ),
839 'post_title' => sprintf( '%s &ndash; %s', $this->get_donor_name(), $this->get_campaign_names() ),
840 );
841
842 $core_values['post_date'] = get_date_from_gmt( $core_values['post_date_gmt'] );
843
844 return apply_filters( 'charitable_donation_values_core', $core_values, $this );
845 }
846
847 /**
848 * Returns the donation status. Defaults to charitable-pending.
849 *
850 * @since 1.0.0
851 *
852 * @return string
853 */
854 protected function get_donation_status() {
855 $status = $this->get_donation_data_value( 'status', 'charitable-pending' );
856
857 if ( ! charitable_is_valid_donation_status( $status ) ) {
858 $status = 'charitable-pending';
859 }
860
861 return $status;
862 }
863
864 /**
865 * Returns the name of the donor.
866 *
867 * @since 1.0.0
868 *
869 * @return string
870 */
871 protected function get_donor_name() {
872 $user = new WP_User( $this->get_donation_data_value( 'user_id', 0 ) );
873 $user_data = $this->get_donation_data_value( 'user' );
874 $first_name = isset( $user_data['first_name'] ) ? $user_data['first_name'] : $user->get( 'first_name' );
875 $last_name = isset( $user_data['last_name'] ) ? $user_data['last_name'] : $user->get( 'last_name' );
876 return trim( sprintf( '%s %s', $first_name, $last_name ) );
877 }
878
879 /**
880 * Returns a comma separated list of the campaigns that are being donated to.
881 *
882 * @since 1.0.0
883 *
884 * @return string
885 */
886 protected function get_campaign_names() {
887 $campaigns = wp_list_pluck( $this->get_campaign_donations_data(), 'campaign_name' );
888 return implode( ', ', $campaigns );
889 }
890
891 /**
892 * Set a unique key for the donation.
893 *
894 * @since 1.0.0
895 *
896 * @return void
897 */
898 protected function set_donation_key() {
899 if ( array_key_exists( 'donation_key', $this->donation_data ) ) {
900 return;
901 }
902
903 $this->donation_data['donation_key'] = strtolower( md5( uniqid() ) );
904 }
905
906 /**
907 * Checks whether the given gateway has been updated for compatibility with 1.3.
908 *
909 * @since 1.3.0
910 *
911 * @param string $gateway The gateway for the donation.
912 * @return boolean
913 */
914 private function gateway_is_130_compatible( $gateway ) {
915 return Charitable_Gateways::get_instance()->get_gateway_object( $gateway )->supports( '1.3.0' );
916 }
917
918 /**
919 * Return the IPN url.
920 *
921 * IPNs in Charitable are structured in this way: charitable-listener=gateway
922 *
923 * @deprecated
924 *
925 * @since 1.0.0
926 *
927 * @param string $gateway The gateway for the donation.
928 * @return string
929 */
930 public function get_ipn_url( $gateway ) {
931 charitable_get_deprecated()->deprecated_function( __METHOD__, '1.4.0', 'charitable_get_ipn_url()' );
932
933 return charitable_get_ipn_url( $gateway );
934 }
935 }
936
937 endif;
938