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.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 All 211 releases
charitable / includes / admin / forms / class-charitable-admin-donation-form.php

class-charitable-admin-donation-form.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at includes/admin/forms/class-charitable-admin-donation-form.php

797 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin donation form model class.
4 *
5 * @package Charitable/Classes/Charitable_Admin_Donation_Form
6 * @author David Bisset
7 * @copyright Copyright (c) 2023, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.5.0
10 * @version 1.6.55
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Admin_Donation_Form' ) ) :
19
20 /**
21 * Charitable_Admin_Donation_Form
22 *
23 * @since 1.5.0
24 */
25 class Charitable_Admin_Donation_Form extends Charitable_Admin_Form {
26
27 /**
28 * Current Charitable_Donation object, or false if it's a new donation.
29 *
30 * @since 1.5.0
31 *
32 * @var Charitable_Donation|false
33 */
34 protected $donation;
35
36 /**
37 * Form action.
38 *
39 * @since 1.5.0
40 *
41 * @var string
42 */
43 protected $form_action;
44
45 /**
46 * Merged fields.
47 *
48 * @since 1.5.11
49 *
50 * @var array
51 */
52 protected $merged_fields;
53
54 /**
55 * Create a donation form object.
56 *
57 * @since 1.5.0
58 *
59 * @param Charitable_Donation|false $donation For existing donations, the `Charitable_Donation` instance.
60 * False for new donations.
61 */
62 public function __construct( $donation ) {
63 $this->id = uniqid();
64 $this->donation = $donation;
65 $this->form_action = $this->has_donation() ? 'update_donation' : 'add_donation';
66 }
67
68 /**
69 * Return the current Charitable_Donation instance, or false if this is a new donation.
70 *
71 * @since 1.5.0
72 *
73 * @return Charitable_Donation|false
74 */
75 public function get_donation() {
76 return $this->donation;
77 }
78
79 /**
80 * Whether there is a current active donation we are editing.
81 *
82 * @since 1.5.0
83 *
84 * @return boolean
85 */
86 public function has_donation() {
87 return $this->donation && ! in_array( $this->donation->get_status(), array( 'auto-draft', 'draft' ) );
88 }
89
90 /**
91 * Return the donation form fields.
92 *
93 * @since 1.5.0
94 *
95 * @return array[]
96 */
97 public function get_fields() {
98 $fields = array(
99 'donation_fields' => array(
100 'type' => 'fieldset',
101 'fields' => $this->get_donation_fields(),
102 'priority' => 21,
103 'tabindex' => 1,
104 ),
105 'donor_header' => array(
106 'type' => 'heading',
107 'level' => 'h3',
108 'title' => __( 'Donor', 'charitable' ),
109 'priority' => 40,
110 ),
111 'user_fields' => array(
112 'type' => 'fieldset',
113 'fields' => $this->get_user_fields(),
114 'priority' => 50,
115 'tabindex' => 100,
116 ),
117 'meta_fields' => array(
118 'type' => 'fieldset',
119 'fields' => $this->get_meta_fields(),
120 'priority' => 60,
121 'tabindex' => 200,
122 ),
123 );
124
125 if ( $this->has_donation() ) {
126 if ( 'manual' !== $this->get_donation()->get_gateway() ) {
127 $fields['meta_fields']['fields']['date']['type'] = 'hidden';
128 $fields['meta_fields']['fields']['date']['value'] = Charitable_Data_Processor::sanitize_datepicker( $fields['meta_fields']['fields']['date']['value'] );
129 }
130
131 $fields['meta_fields']['fields']['time'] = array(
132 'type' => 'hidden',
133 'priority' => 2,
134 'value' => date( 'H:i:s', strtotime( $this->get_donation()->post_date_gmt ) ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
135 );
136 } else {
137 $fields['donor_id'] = array(
138 'type' => 'select',
139 'options' => $this->get_all_donors(),
140 'priority' => 41,
141 'value' => '',
142 'description' => __( 'Select an existing donor or choose "Add a New Donor" to create a new donor.', 'charitable' ),
143 'wrapper_class' => array( 'select2' ),
144 'attrs' => array(
145 'data-nonce' => wp_create_nonce( 'donor-select' ),
146 ),
147 );
148 }
149
150 /* User can only create a donation for themselves. */
151 if ( ! current_user_can( 'edit_others_donations' ) ) {
152 $user = charitable_get_user( get_current_user_id() );
153
154 if ( array_key_exists( 'donor_id', $fields ) ) {
155 $fields['donor_id']['type'] = 'hidden';
156 $fields['donor_id']['value'] = $user->get_donor_id();
157 }
158
159 foreach ( $fields['user_fields']['fields'] as $key => $details ) {
160 $fields['user_fields']['fields'][ $key ]['value'] = $user->$key;
161
162 if ( $key === 'email' ) {
163 $fields['user_fields']['fields'][ $key ]['field_attrs'] = array(
164 'attrs' => array( 'disabled' => 'disabled' ),
165 );
166 }
167 }
168 }
169
170 /**
171 * Filter the admin donation form fields.
172 *
173 * Note that the recommended way to add fields to the form is
174 * with the Donation Fields API. This filter provides the ability
175 * to re-organize the sections within the form and change fields
176 * in the form that do not come from the Donation Fields API
177 * (headers, campaign/amount field, resend receipt).
178 *
179 * @since 1.5.0
180 *
181 * @param array $fields Array of fields.
182 * @param Charitable_Admin_Donation_Form $form This instance of `Charitable_Admin_Donation_Form`.
183 */
184 $fields = apply_filters( 'charitable_admin_donation_form_fields', $fields, $this );
185
186 uasort( $fields, 'charitable_priority_sort' );
187
188 return $fields;
189 }
190
191 /**
192 * Get donation fields.
193 *
194 * @since 1.5.0
195 *
196 * @return array
197 */
198 public function get_donation_fields() {
199 if ( ! $this->donation ) {
200 $value = array();
201 } else {
202 $value = (array) $this->donation->get_campaign_donations();
203 }
204
205 return array(
206 'campaign_donations' => array(
207 'type' => 'campaign-donations',
208 'value' => $value,
209 ),
210 );
211 }
212
213 /**
214 * Return all the fields in a particular section.
215 *
216 * @since 1.5.0
217 *
218 * @param string $section The section we're fetching fields for.
219 * @return array
220 */
221 public function get_section_fields( $section ) {
222 $fields = charitable()->donation_fields()->get_admin_form_fields( $section );
223 $keys = array_keys( $fields );
224 $fields = array_combine(
225 $keys,
226 array_map( array( $this, 'maybe_set_field_value' ), wp_list_pluck( $fields, 'admin_form' ), $keys )
227 );
228
229 uasort( $fields, 'charitable_priority_sort' );
230
231 return $fields;
232 }
233
234 /**
235 * Return the fields for the user section.
236 *
237 * @since 1.6.28
238 *
239 * @return array
240 */
241 public function get_user_fields() {
242 $fields = $this->get_section_fields( 'user' );
243 $loading_icon = charitable()->get_path( 'assets', false ) . 'images/charitable-loading.gif';
244 $fields['overlay'] = array(
245 'type' => 'content',
246 'priority' => 1,
247 'content' => '<div class="charitable-overlay" style="display: none;"><img src="' . $loading_icon . '" width=60 height=60 alt="' . __( 'Loading icon', 'charitable' ) . '" /></div>',
248 );
249
250 uasort( $fields, 'charitable_priority_sort' );
251
252 return $fields;
253 }
254
255 /**
256 * Return the fields for the meta section.
257 *
258 * @since 1.6.28
259 * @since 1.8.1.8 Added the `charitable_admin_donation_form_meta_fields` filter.
260 *
261 * @return array
262 */
263 public function get_meta_fields() {
264 $fields = $this->get_section_fields( 'meta' );
265 $fields['log_note'] = array(
266 'label' => __( 'Donation Note', 'charitable' ),
267 'type' => 'textarea',
268 'priority' => 12,
269 'required' => false,
270 );
271
272 if ( $this->should_add_donation_receipt_checkbox() ) {
273 $fields['send_donation_receipt'] = array(
274 'type' => 'checkbox',
275 'label' => __( 'Send an email receipt to the donor.', 'charitable' ),
276 'value' => 1,
277 'default' => 1,
278 'priority' => 16,
279 );
280 }
281
282 uasort( $fields, 'charitable_priority_sort' );
283
284 return apply_filters( 'charitable_admin_donation_form_meta_fields', $fields, $this );
285 }
286
287 /**
288 * Get the value submitted for a particular field.
289 *
290 * @since 1.5.0
291 *
292 * @param string $field The field.
293 * @param mixed $default The default value to return if the value was not submitted.
294 * @return mixed
295 */
296 public function get_submitted_value( $field, $default = false ) {
297 $data = $this->get_submitted_values();
298 return isset( $data[ $field ] ) ? $data[ $field ] : $default;
299 }
300
301 /**
302 * Filter a campaign donation array, making sure both a campaign
303 * and amount are provided.
304 *
305 * @since 1.5.0
306 *
307 * @param object $campaign_donation A particular campaign donation.
308 * @return boolean
309 */
310 public function filter_campaign_donation( $campaign_donation ) {
311 $campaign_donation = (array) $campaign_donation;
312
313 return array_key_exists( 'campaign_id', $campaign_donation )
314 && array_key_exists( 'amount', $campaign_donation )
315 && ! empty( $campaign_donation['campaign_id'] )
316 && ! empty( $campaign_donation['amount'] );
317 }
318
319 /**
320 * Validate the form submission.
321 *
322 * @since 1.5.0
323 *
324 * @return boolean
325 */
326 public function validate_submission() {
327 /* If we have already validated the submission, return the value. */
328 if ( isset( $this->validated ) ) {
329 return $this->valid;
330 }
331
332 $this->valid = $this->check_required_fields( $this->get_merged_fields() );
333
334 /**
335 * If required fields are missing, get the error message from the
336 * notices and add them to the admin notices.
337 */
338 if ( ! $this->valid ) {
339 charitable_get_admin_notices()->fill_notices_from_frontend();
340 }
341
342 // phpcs:disable WordPress.Security.NonceVerification.Missing
343 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Array data, sanitized in filter_campaign_donation
344 $campaign_donations = array_key_exists( 'campaign_donations', $_POST ) ? wp_unslash( $_POST['campaign_donations'] ) : array();
345 $campaign_donations = array_filter( $campaign_donations, array( $this, 'filter_campaign_donation' ) );
346 $_POST['campaign_donations'] = $campaign_donations;
347
348 if ( empty( $campaign_donations ) ) {
349 // phpcs:enable WordPress.Security.NonceVerification.Missing
350 charitable_get_admin_notices()->add_error( __( 'You must provide both a campaign and amount.', 'charitable' ) );
351
352 $this->valid = false;
353 }
354
355 if ( $this->donation_needs_email() ) {
356 charitable_get_admin_notices()->add_error( __( 'Please choose an existing donor or provide an email address for a new donor.', 'charitable' ) );
357
358 $this->valid = false;
359 }
360
361 /**
362 * Filter whether the admin donation form passes validation.
363 *
364 * @since 1.5.0
365 *
366 * @param boolean $valid Whether the form submission is valid.
367 * @param Charitable_Admin_Donation_Form $form This instance of `Charitable_Admin_Donation_Form`.
368 */
369 $this->valid = apply_filters( 'charitable_validate_admin_donation_form_submission', $this->valid, $this );
370 $this->validated = true;
371
372 return $this->valid;
373 }
374
375 /**
376 * Return the donation values.
377 *
378 * @since 1.5.0
379 *
380 * @return array
381 */
382 public function get_donation_values() {
383 $values = array(
384 'ID' => $this->get_submitted_value( 'ID' ),
385 'donor_id' => abs( (int) $this->get_submitted_value( 'donor_id' ) ),
386 'status' => $this->get_submitted_value( 'status' ),
387 'log_note' => $this->get_submitted_value( 'log_note' ),
388 'user_id' => 0,
389 );
390
391 if ( 'add_donation' == $this->get_submitted_value( 'charitable_action' ) ) {
392 $values['donation_gateway'] = __( 'Manual', 'charitable' );
393 }
394
395 $values = $this->sanitize_submitted_campaign_donation( $values );
396 $values = $this->sanitize_submitted_date( $values );
397 $values = $this->sanitize_submitted_log_note( $values );
398 $values = $this->sanitize_submitted_donor( $values );
399
400 /* Ensure that the user has not created a donation for someone else. */
401 if ( ! current_user_can( 'edit_others_donations' ) ) {
402 $user = charitable_get_user( get_current_user_id() );
403
404 $values['donor_id'] = $user->get_donor_id();
405
406 if ( array_key_exists( 'user_id', $values ) ) {
407 $values['user_id'] = $user->ID;
408 }
409
410 if ( array_key_exists( 'user', $values ) && array_key_exists( 'email', $values['user'] ) ) {
411 $values['user']['email'] = $user->email;
412 }
413 }
414
415 foreach ( $this->get_merged_fields() as $key => $field ) {
416 if ( $this->should_field_be_added( $field, $key, $values ) ) {
417 $values[ $field['data_type'] ][ $key ] = $this->get_field_value_from_submission( $field, $key );
418 }
419 }
420
421 /**
422 * Filter the submitted values.
423 *
424 * @since 1.5.0
425 *
426 * @param array $values The submitted values.
427 * @param Charitable_Admin_Donation_Form $form This instance of `Charitable_Admin_Donation_Form`.
428 */
429 return apply_filters( 'charitable_admin_donation_form_submission_values', $values, $this );
430 }
431
432 /**
433 * Return the value for a particular field from the form submission, or return the default.
434 *
435 * @since 1.5.7
436 *
437 * @param array $field The field definition.
438 * @param string $key The key of the field.
439 * @return mixed
440 */
441 protected function get_field_value_from_submission( $field, $key ) {
442 $default = 'checkbox' == $field['type'] ? false : '';
443
444 return $this->get_submitted_value( $key, $default );
445 }
446
447 /**
448 * Checks whether a field should be added to the values to be saved.
449 *
450 * @since 1.5.7
451 *
452 * @param array $field The field definition.
453 * @param string $key The key of the field.
454 * @param array $values The sanitized values so far.
455 * @return boolean
456 */
457 protected function should_field_be_added( $field, $key, $values ) {
458 if ( ! $this->should_data_type_be_added( $field ) || ! array_key_exists( 'type', $field ) ) {
459 return false;
460 }
461
462 if ( isset( $values[ $field['data_type'] ][ $key ] ) ) {
463 return false;
464 }
465
466 return 'user' == $field['data_type'] ? $this->should_user_field_be_added( $values ) : true;
467 }
468
469 /**
470 * Whether the passed data type should be added to the values to be saved.
471 *
472 * @since 1.5.7
473 *
474 * @param array $field The field definition.
475 * @return boolean
476 */
477 protected function should_data_type_be_added( $field ) {
478 return array_key_exists( 'data_type', $field ) && 'core' != $field['data_type'];
479 }
480
481 /**
482 * Returns whether users fields should be added.
483 *
484 * This will return true if no donor_id is set, or if this is an edit
485 * of an existing donation.
486 *
487 * @since 1.5.7
488 *
489 * @param array $values The sanitized values so far.
490 * @return boolean
491 */
492 protected function should_user_field_be_added( $values ) {
493 return ! $values['donor_id'] || $values['ID'];
494 }
495
496 /**
497 * Return donor values.
498 *
499 * @since 1.5.0
500 *
501 * @param array $values The submitted values.
502 * @return array
503 */
504 protected function sanitize_submitted_donor( $values ) {
505 /* Shortcircuit for new donations. */
506 if ( ! $values['donor_id'] ) {
507 if ( $values['ID'] && $this->has_donation() ) {
508 $values['user'] = $this->get_donor_data_to_preserve();
509 }
510
511 return $values;
512 }
513
514 $donor = new Charitable_Donor( $values['donor_id'] );
515
516 /* Populate the user_id' arg, then prepare the 'user' array. */
517 $values['user_id'] = $donor->get_user()->ID;
518 $values['user'] = array(
519 'email' => $this->get_submitted_value( 'email' ),
520 'first_name' => $this->get_submitted_value( 'first_name' ),
521 'last_name' => $this->get_submitted_value( 'last_name' ),
522 'address' => $this->get_submitted_value( 'address' ),
523 'address_2' => $this->get_submitted_value( 'address_2' ),
524 'postcode' => $this->get_submitted_value( 'postcode' ),
525 'state' => $this->get_submitted_value( 'state' ),
526 'country' => $this->get_submitted_value( 'country' ),
527 'phone' => $this->get_submitted_value( 'phone' ),
528 );
529
530 return $values;
531 }
532
533 /**
534 * Returns any of the current donor data that should be preserved
535 * after saving. This is any data that exists that doesn't have a
536 * field in the admin donation form.
537 *
538 * @since 1.5.11
539 *
540 * @return array
541 */
542 protected function get_donor_data_to_preserve() {
543 $data = $this->donation->get_donor_data();
544
545 foreach ( $this->get_merged_fields() as $key => $field ) {
546 if ( ! array_key_exists( 'data_type', $field ) || 'user' != $field['data_type'] ) {
547 continue;
548 }
549
550 if ( ! array_key_exists( $key, $data ) ) {
551 continue;
552 }
553
554 unset( $data[ $key ] );
555
556 /* There is no data left to preserve, so return an empty array. */
557 if ( empty( $data ) ) {
558 return $data;
559 }
560 }
561
562 return $data;
563 }
564
565 /**
566 * Sanitize the log note, or add one if none was included.
567 *
568 * @since 1.5.0
569 *
570 * @param array $values The submitted values.
571 * @return array
572 */
573 protected function sanitize_submitted_log_note( $values ) {
574 if ( ! $values['log_note'] ) {
575 $values['log_note'] = sprintf(
576 /* translators: %1$s: User profile URL, %2$s: User display name */
577 __( 'Donation updated manually by <a href="%1$s">%2$s</a>.', 'charitable' ),
578 admin_url( 'user-edit.php?user_id=' . wp_get_current_user()->ID ),
579 wp_get_current_user()->display_name
580 );
581 } else {
582 $values['log_note'] .= sprintf(
583 ' - <a href="%s">%s</a>',
584 admin_url( 'user-edit.php?user_id=' . wp_get_current_user()->ID ),
585 wp_get_current_user()->display_name
586 );
587 }
588
589 return $values;
590 }
591
592 /**
593 * Sanitize the campaign donation submitted.
594 *
595 * @since 1.5.0
596 *
597 * @param array $values The submitted values.
598 * @return array
599 */
600 protected function sanitize_submitted_campaign_donation( $values ) {
601 $campaigns = array();
602
603 foreach ( $this->get_submitted_value( 'campaign_donations' ) as $key => $campaign_donation ) {
604 $campaign_donation['amount'] = charitable_get_currency_helper()->sanitize_monetary_amount( $campaign_donation['amount'] );
605 $campaigns[ $key ] = $campaign_donation;
606 }
607
608 $values['campaigns'] = $campaigns;
609
610 if ( $this->has_donation() ) {
611 $old_campaign_ids = wp_list_pluck( $this->donation->get_campaign_donations(), 'campaign_id' );
612
613 foreach ( $campaigns as $campaign_donation ) {
614 if ( ! in_array( $campaign_donation['campaign_id'], $old_campaign_ids ) ) {
615 Charitable_Campaign::flush_donations_cache( $campaign_donation['campaign_id'] );
616 }
617 }
618 }
619
620 return $values;
621 }
622
623 /**
624 * Sanitize the date.
625 *
626 * @since 1.5.0
627 * @version 1.8.8.5
628 *
629 * @param array $values The submitted values.
630 * @return array
631 */
632 protected function sanitize_submitted_date( $values ) {
633 $donation = charitable_get_donation( $this->get_submitted_value( 'ID' ) );
634 $is_new = false === $donation || 'Auto Draft' === $donation->post_title;
635 $date = $this->get_submitted_value( 'date' );
636 $time = $this->get_submitted_value( 'time', '00:00:00' );
637
638 /* The date has already been sanitized in Charitable_Date_Processor::sanitize_datepicker */
639 $values['date_gmt'] = $date . ' ' . $time;
640
641 /* If the date matches today's date and it's a new donation, save the time too. */
642 if ( date( 'Y-m-d 00:00:00' ) == $values['date_gmt'] && $is_new ) { // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
643 $values['date_gmt'] = date( 'Y-m-d H:i:s' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
644 }
645
646 /* If the donation date has been changed, preserve the original time from the donation log */
647 if ( $values['date_gmt'] !== $donation->post_date_gmt && ! $is_new ) {
648 // Get the original donation time from the donation log
649 $donation_log = get_post_meta( $donation->ID, '_donation_log', true );
650 $original_time = '00:00:00'; // Default fallback
651
652 if ( is_array( $donation_log ) && ! empty( $donation_log ) ) {
653 // Get the first log entry which contains the original creation time
654 $first_log_entry = $donation_log[0];
655 if ( isset( $first_log_entry['time'] ) ) {
656 // Convert the original timestamp to GMT time format
657 $original_time = gmdate( 'H:i:s', $first_log_entry['time'] );
658 }
659 }
660
661 $values['date_gmt'] = $date . ' ' . $original_time;
662 }
663
664 return $values;
665 }
666
667 /**
668 * Get a key=>value array of all existing donors.
669 *
670 * @since 1.5.0
671 * @version 1.8.8
672 *
673 * @return array
674 */
675 protected function get_all_donors() {
676 $donors = new Charitable_Donor_Query(
677 array(
678 'number' => -1,
679 'orderby' => 'name',
680 'order' => 'ASC',
681 'output' => 'raw',
682 'status' => false, // Return any.
683 'include_erased' => false,
684 )
685 );
686
687 $donor_list = array();
688
689 foreach ( $donors as $donor ) {
690 $name = trim( sprintf( '%s %s', $donor->first_name, $donor->last_name ) );
691
692 if ( charitable_is_valid_email_address( $donor->email ) ) {
693 $name .= ' - ' . $donor->email;
694 }
695
696 $donor_list[ $donor->donor_id ] = $name;
697 }
698
699 // Apply a filter here to allow for the donor list to be modified.
700 $donor_list = apply_filters( 'charitable_admin_donation_form_donor_list', $donor_list );
701
702 $list = array(
703 'new' => __( 'Add a New Donor', 'charitable' ),
704 'existing' => array(
705 'label' => __( 'Existing Donors', 'charitable' ),
706 'options' => $donor_list,
707 ),
708 );
709
710 return $list;
711 }
712
713 /**
714 * Set a field's initial value.
715 *
716 * @since 1.5.0
717 * @version 1.8.9.1
718 *
719 * @param array $field Field definition.
720 * @param string $key The key of the field.
721 * @return array
722 */
723 protected function maybe_set_field_value( $field, $key ) {
724 // phpcs:disable WordPress.Security.NonceVerification.Missing
725 if ( array_key_exists( $key, $_POST ) ) {
726 $field['value'] = sanitize_text_field( wp_unslash( $_POST[ $key ] ) );
727 // phpcs:enable WordPress.Security.NonceVerification.Missing
728 return $field;
729 }
730
731 /* Checkboxes don't need a value set. */
732 if ( 'checkbox' != $field['type'] ) {
733 $field['value'] = array_key_exists( 'default', $field ) ? $field['default'] : '';
734 }
735
736 if ( ! $this->has_donation() ) {
737 return $field;
738 }
739
740 if ( isset( $field['value_callback'] ) ) {
741 $value = call_user_func( $field['value_callback'], $this->get_donation(), $key );
742 } else {
743 $value = $this->donation->get( $key );
744 }
745
746 if ( isset( $field['timestamp_callback'] ) ) {
747 $field['timestamp'] = call_user_func( $field['timestamp_callback'], $this->get_donation(), $key );
748 }
749
750 if ( ! $value ) {
751 return $field;
752 }
753
754 if ( 'checkbox' == $field['type'] ) {
755 $field['checked'] = $value;
756 } else {
757 $field['value'] = $value;
758 }
759
760 return $field;
761 }
762
763 /**
764 * Returns whether a checkbox should be included for sending the donation receipt.
765 *
766 * @since 1.5.9
767 *
768 * @return boolean
769 */
770 protected function should_add_donation_receipt_checkbox() {
771 return ! $this->has_donation() && charitable_get_helper( 'emails' )->is_enabled_email( 'donation_receipt' );
772 }
773
774 /**
775 * Return whether the donation needs an email address.
776 *
777 * @since 1.6.0
778 *
779 * @return boolean
780 */
781 public function donation_needs_email() {
782 if ( charitable_permit_donor_without_email() ) {
783 return false;
784 }
785
786 if ( strlen( $this->get_submitted_value( 'email', '' ) ) ) {
787 return false;
788 }
789
790 $donor_id = $this->get_submitted_value( 'donor_id' );
791
792 return 'new' == $donor_id || '' == $donor_id;
793 }
794 }
795
796 endif;
797