PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.3
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
charitable / includes / donations / charitable-donation-functions.php

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

591 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Charitable Donation Functions.
4 *
5 * @package Charitable/Functions/Donation
6 * @author David Bisset
7 * @copyright Copyright (c) 2022, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.0.0
10 * @version 1.6.60
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Returns the given donation.
20 *
21 * This will first attempt to retrieve it from the object cache to prevent duplicate objects.
22 *
23 * @since 1.0.0
24 *
25 * @param int $donation_id The donation ID.
26 * @param boolean $force Whether to force a non-cached donation object to be retrieved.
27 * @return Charitable_Donation|false
28 */
29 function charitable_get_donation( $donation_id, $force = false ) {
30 $donation = wp_cache_get( $donation_id, 'charitable_donation', $force );
31
32 if ( ! $donation ) {
33 $donation = charitable()->registry()->get( 'donation_factory' )->get_donation( $donation_id );
34 wp_cache_set( $donation_id, $donation, 'charitable_donation' );
35 }
36
37 return $donation;
38 }
39
40 /**
41 * Update the donation cache.
42 *
43 * @since 1.6.34
44 *
45 * @param Charitable_Donation|Charitable_Recurring_Donation $donation The donation object.
46 * @return mixed
47 */
48 function charitable_update_cached_donation( Charitable_Abstract_Donation $donation ) {
49 wp_cache_set( $donation->ID, $donation, 'charitable_donation' );
50 }
51
52 /**
53 * Given a donation ID and a key, return the submitted value.
54 *
55 * @since 1.5.0
56 *
57 * @param Charitable_Abstract_Donation $donation The donation ID.
58 * @param string $key The meta key.
59 * @return mixed
60 */
61 function charitable_get_donor_meta_value( Charitable_Abstract_Donation $donation, $key ) {
62 return $donation->get_donor()->get_donor_meta( $key );
63 }
64
65 /**
66 * Given a donation ID and a key, return the submitted value.
67 *
68 * @since 1.5.0
69 *
70 * @param Charitable_Abstract_Donation $donation The donation ID.
71 * @param string $key The meta key.
72 * @return mixed
73 */
74 function charitable_get_donation_meta_value( Charitable_Abstract_Donation $donation, $key ) {
75 return get_post_meta( $donation->ID, $key, true );
76 }
77
78 /**
79 * Sanitize a value for a donation field, based on the type of field.
80 *
81 * @since 1.6.7
82 *
83 * @param mixed $value The submitted value.
84 * @param string $key The meta key.
85 * @return mixed
86 */
87 function charitable_get_sanitized_donation_field_value( $value, $key ) {
88 $field = charitable()->donation_fields()->get_field( $key );
89 $form = ( false === $field->admin_form ) ? $field->donation_form : $field->admin_form;
90
91 if ( ! is_array( $form ) ) {
92 return $value;
93 }
94
95 if ( ! array_key_exists( 'options', $form ) ) {
96 return $value;
97 }
98
99 if ( is_array( $value ) ) {
100 $values = array();
101
102 foreach ( $value as $val ) {
103 $values[] = array_key_exists( $val, $form['options'] ) ? $form['options'][ $val ] : $val;
104 }
105
106 $value = implode( ', ', $values );
107 } else {
108 $value = array_key_exists( $value, $form['options'] ) ? $form['options'][ $value ] : $value;
109 }
110
111 return $value;
112 }
113
114 /**
115 * Return the date formatted for a form field value.
116 *
117 * @since 1.5.3
118 *
119 * @param Charitable_Abstract_Donation $donation The donation instance.
120 * @return string
121 */
122 function charitable_get_donation_date_for_form_value( Charitable_Abstract_Donation $donation ) {
123 return $donation->get_date( 'F j, Y' );
124 }
125
126 /**
127 * Get the donation date as a timestamp.
128 *
129 * @since 1.6.52
130 *
131 * @param Charitable_Abstract_Donation $donation The donation instance.
132 * @return int
133 */
134 function charitable_get_donation_date_as_timestamp( Charitable_Abstract_Donation $donation ) {
135 return strtotime( $donation->post_date );
136 }
137
138 /**
139 * Returns the donation for the current request.
140 *
141 * @since 1.0.0
142 *
143 * @return Charitable_Donation|false
144 */
145 function charitable_get_current_donation() {
146 return charitable_get_helper( 'request' )->get_current_donation();
147 }
148
149 /**
150 * Create a donation.
151 *
152 * @since 1.4.0
153 *
154 * @param array $args Values for the donation.
155 * @return int
156 */
157 function charitable_create_donation( array $args ) {
158 $donation_id = Charitable_Donation_Processor::get_instance()->save_donation( $args );
159
160 Charitable_Donation_Processor::destroy();
161
162 return $donation_id;
163 }
164
165 /**
166 * Find and return a donation based on the given donation key.
167 *
168 * @since 1.4.0
169 *
170 * @param string $donation_key The donation key to query by.
171 * @return int|null
172 */
173 function charitable_get_donation_by_key( $donation_key ) {
174 global $wpdb;
175
176 $sql = "SELECT post_id
177 FROM $wpdb->postmeta
178 WHERE meta_key = 'donation_key'
179 AND meta_value = %s";
180
181 return $wpdb->get_var( $wpdb->prepare( $sql, $donation_key ) );
182 }
183
184 /**
185 * Find and return a donation using a gateway transaction ID.
186 *
187 * @since 1.4.7
188 *
189 * @param string $transaction_id The transaction id to query by.
190 * @return int|null
191 */
192 function charitable_get_donation_by_transaction_id( $transaction_id ) {
193 global $wpdb;
194
195 $sql = "SELECT post_id
196 FROM $wpdb->postmeta
197 WHERE meta_key = '_gateway_transaction_id'
198 AND meta_value = %s";
199
200 return $wpdb->get_var( $wpdb->prepare( $sql, $transaction_id ) );
201 }
202
203 /**
204 * Return the IPN url for this gateway.
205 *
206 * IPNs in Charitable are structured in this way: charitable-listener=gateway
207 *
208 * @since 1.4.0
209 *
210 * @param string $gateway The gateway to get the ipn URL for.
211 * @return string
212 */
213 function charitable_get_ipn_url( $gateway ) {
214 return charitable_get_permalink( 'webhook_listener', array( 'gateway' => $gateway ) );
215 }
216
217 /**
218 * Checks for calls to our IPN.
219 *
220 * This method is called on the init hook.
221 *
222 * IPNs in Charitable are structured in this way: charitable-listener=gateway
223 *
224 * @deprecated 1.9.0
225 *
226 * @since 1.4.0
227 * @since 1.6.14 Deprecated. This is now handled by the webhook listener endpoint.
228 *
229 * @return boolean True if this is a call to our IPN. False otherwise.
230 */
231 function charitable_ipn_listener() {
232 charitable_get_deprecated()->deprecated_function(
233 __FUNCTION__,
234 '1.6.14',
235 "charitable()->endpoints()->get_endpoint( 'webhook_listener' )->process_incoming_webhook()"
236 );
237
238 return charitable()->endpoints()->get_endpoint( 'webhook_listener' )->process_incoming_webhook();
239 }
240
241 /**
242 * Checks if this is happening right after a donation.
243 *
244 * This method is called on the init hook.
245 *
246 * @since 1.4.0
247 *
248 * @return boolean Whether this is after a donation.
249 */
250 function charitable_is_after_donation() {
251 if ( is_admin() ) {
252 return false;
253 }
254
255 $processor = get_transient( 'charitable_donation_' . charitable_get_session()->get_session_id() );
256
257 if ( ! $processor ) {
258 return false;
259 }
260
261 /**
262 * Do something on a user's first page load after a donation has been made.
263 *
264 * @since 1.3.6
265 *
266 * @param Charitable_Donation_Processor $processor The instance of `Charitable_Donation_Processor`.
267 */
268 do_action( 'charitable_after_donation', $processor );
269
270 foreach ( $processor->get_campaign_donations_data() as $campaign_donation ) {
271 charitable_get_session()->remove_donation( $campaign_donation['campaign_id'] );
272 }
273
274 delete_transient( 'charitable_donation_' . charitable_get_session()->get_session_id() );
275
276 return true;
277
278 }
279
280 /**
281 * Returns whether the donation status is valid.
282 *
283 * @since 1.4.0
284 *
285 * @param string $status The status to check.
286 * @return boolean
287 */
288 function charitable_is_valid_donation_status( $status ) {
289 return array_key_exists( $status, charitable_get_valid_donation_statuses() );
290 }
291
292 /**
293 * Returns the donation statuses that signify a donation was complete.
294 *
295 * By default, this is just 'charitable-completed'. However, 'charitable-preapproval'
296 * is also counted.
297 *
298 * @since 1.4.0
299 *
300 * @return string[]
301 */
302 function charitable_get_approval_statuses() {
303 /**
304 * Filter the list of donation statuses that we consider "approved".
305 *
306 * All statuses must already be listed as valid donation statuses.
307 *
308 * @see charitable_get_valid_donation_statuses
309 *
310 * @since 1.0.0
311 *
312 * @param string[] $statuses List of statuses.
313 */
314 $statuses = apply_filters( 'charitable_approval_donation_statuses', array( 'charitable-completed' ) );
315
316 return array_filter( $statuses, 'charitable_is_valid_donation_status' );
317 }
318
319 /**
320 * Returns whether the passed status is an confirmed status.
321 *
322 * @since 1.4.0
323 *
324 * @param string|false $status The status to check.
325 * @return boolean
326 */
327 function charitable_is_approved_status( $status ) {
328 return false !== $status && in_array( $status, charitable_get_approval_statuses() );
329 }
330
331 /**
332 * Return array of valid donations statuses.
333 *
334 * @since 1.4.0
335 *
336 * @return array
337 */
338 function charitable_get_valid_donation_statuses() {
339 /**
340 * Filter the list of possible donation statuses.
341 *
342 * @since 1.0.0
343 *
344 * @param array $statuses The list of status as a key=>value array.
345 */
346 return apply_filters(
347 'charitable_donation_statuses',
348 array(
349 'charitable-completed' => __( 'Paid', 'charitable' ),
350 'charitable-pending' => __( 'Pending', 'charitable' ),
351 'charitable-failed' => __( 'Failed', 'charitable' ),
352 'charitable-cancelled' => __( 'Cancelled', 'charitable' ),
353 'charitable-refunded' => __( 'Refunded', 'charitable' ),
354 )
355 );
356 }
357
358 /**
359 * Cancel a donation.
360 *
361 * @since 1.4.0
362 *
363 * @global WP_Query $wp_query
364 * @return boolean True if the donation was cancelled. False otherwise.
365 */
366 function charitable_cancel_donation() {
367 global $wp_query;
368
369 if ( ! charitable_is_page( 'donation_cancel_page' ) ) {
370 return false;
371 }
372
373 if ( ! isset( $wp_query->query_vars['donation_id'] ) ) {
374 return false;
375 }
376
377 $donation = charitable_get_donation( $wp_query->query_vars['donation_id'] );
378
379 if ( ! $donation ) {
380 return false;
381 }
382
383 /* Donations can only be cancelled if they are currently pending. */
384 if ( 'charitable-pending' != $donation->get_status() ) {
385 return false;
386 }
387
388 if ( ! $donation->is_from_current_user() ) {
389 return false;
390 }
391
392 $donation->update_status( 'charitable-cancelled' );
393
394 return true;
395 }
396
397 /**
398 * Load the donation form script.
399 *
400 * @since 1.4.0
401 *
402 * @return void
403 */
404 function charitable_load_donation_form_script() {
405 wp_enqueue_script( 'charitable-donation-form' );
406 }
407
408 /**
409 * Add a message to a donation's log.
410 *
411 * @since 1.0.0
412 *
413 * @param int $donation_id The donation ID.
414 * @param string $message The message to add to the log.
415 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
416 */
417 function charitable_update_donation_log( $donation_id, $message ) {
418 return charitable_get_donation( $donation_id )->log()->add( $message );
419 }
420
421 /**
422 * Get a donation's log.
423 *
424 * @since 1.0.0
425 *
426 * @param int $donation_id The donation ID.
427 * @return array
428 */
429 function charitable_get_donation_log( $donation_id ) {
430 return charitable_get_donation( $donation_id )->log()->get_meta_log();
431 }
432
433 /**
434 * Get the gateway used for the donation.
435 *
436 * @since 1.0.0
437 *
438 * @param int $donation_id The donation ID.
439 * @return string
440 */
441 function charitable_get_donation_gateway( $donation_id ) {
442 return get_post_meta( $donation_id, 'donation_gateway', true );
443 }
444
445 /**
446 * Sanitize meta values before they are persisted to the database.
447 *
448 * @since 1.0.0
449 *
450 * @param mixed $value The value to sanitize.
451 * @param string $key The key of the meta field to be sanitized.
452 * @return mixed
453 */
454 function charitable_sanitize_donation_meta( $value, $key ) {
455 if ( 'donation_gateway' == $key ) {
456 if ( empty( $value ) || ! $value ) {
457 $value = 'manual';
458 }
459 }
460
461 /**
462 * Deprecated hook for filtering donation meta.
463 *
464 * @since 1.0.0
465 * @since 1.5.0 Deprecated.
466 *
467 * @param mixed $value The value of the donation meta field.
468 */
469 $value = apply_filters( 'charitable_sanitize_donation_meta-' . $key, $value );
470
471 /**
472 * Filter donation meta.
473 *
474 * This hook takes the form of charitable_sanitize_donation_meta_{key}.
475 * For example, to filter the `donation_gateway` meta, the hook would be:
476 *
477 * charitable_sanitize_donation_meta_doantion_gateway
478 *
479 * @since 1.5.0
480 *
481 * @param mixed $value The value of the donation meta field.
482 */
483 return apply_filters( 'charitable_sanitize_donation_meta_' . $key, $value );
484 }
485
486 /**
487 * Flush the donations cache for every campaign receiving a donation.
488 *
489 * @since 1.0.0
490 *
491 * @param int $donation_id The donation ID.
492 * @return void
493 */
494 function charitable_flush_campaigns_donation_cache( $donation_id ) {
495 $campaign_donations = charitable_get_table( 'campaign_donations' )->get_donation_records( $donation_id );
496
497 foreach ( $campaign_donations as $campaign_donation ) {
498 Charitable_Campaign::flush_donations_cache( $campaign_donation->campaign_id );
499 }
500
501 wp_cache_delete( $donation_id, 'charitable_donation' );
502
503 /**
504 * Do something when the donation cache is flushed.
505 *
506 * @since 1.4.18
507 *
508 * @param int $donation_id The donation ID.
509 */
510 do_action( 'charitable_flush_donation_cache', $donation_id );
511 }
512
513 /**
514 * Return the minimum donation amount.
515 *
516 * @since 1.5.0
517 * @since 1.6.60 Added the $campaign_id argument.
518 * @since 1.7.0.3 Added the minimum check.
519 *
520 * @param int $campaign_id Optional campaign ID.
521 * @return float
522 */
523 function charitable_get_minimum_donation_amount( $campaign_id = 0 ) {
524
525 $minimum_amount = 0;
526
527 if ( 0 !== $campaign_id ) {
528
529 $minimum_amount_to_check = get_post_meta( $campaign_id, '_campaign_minimum_donation_amount', true );
530
531 if ( false !== $minimum_amount_to_check && '' !== trim( $minimum_amount_to_check ) ) {
532 $minimum_amount = charitable_sanitize_amount( $minimum_amount_to_check, true ); // converts a format like $1.05 to 1.05, per the dev note below.
533 }
534
535 }
536
537 /**
538 * Filter the minimum donation amount.
539 *
540 * Note, the minimum donation amount should be expressed in a format
541 * where a period (.) is used as the decimal separator. i.e. 2.50 is
542 * two dollars and fifty cents.
543 *
544 * @since 1.5.0
545 * @since 1.6.60 Added the $campaign_id argument.
546 *
547 * @param float $minimum The minimum amount.
548 * @param int $campaign_id Campaign ID. This is 0 by default, meaning the global minimum should be returned.
549 */
550 return apply_filters( 'charitable_minimum_donation_amount', $minimum_amount, $campaign_id );
551 }
552
553 /**
554 * Return the maximum donation amount.
555 *
556 * @since 1.6.60
557 *
558 * @param int $campaign_id Optional campaign ID.
559 * @return float
560 */
561 function charitable_get_maximum_donation_amount( $campaign_id = 0 ) {
562 /**
563 * Filter the maximum donation amount.
564 *
565 * Note, the maximum donation amount should be expressed in a format
566 * where a period (.) is used as the decimal separator and no commas
567 * should be used for thousands. i.e. 9999.90 is nine thousand, nine hundred
568 * ninety-nine dollars and ninety cents.
569 *
570 * @since 1.6.60
571 *
572 * @param float|false $maximum The maximum amount, or false if there is no maximum.
573 * @param int $campaign_id Campaign ID. This is 0 by default, meaning the global maximum should be returned.
574 */
575 return apply_filters( 'charitable_maximum_donation_amount', false, $campaign_id );
576 }
577
578 /**
579 * Check whether the current user has access to a particular donation.
580 *
581 * @since 1.5.14
582 *
583 * @param int $donation_id The donation ID.
584 * @return boolean
585 */
586 function charitable_user_can_access_donation( $donation_id ) {
587 $donation = charitable_get_donation( $donation_id );
588
589 return $donation && $donation->is_from_current_user();
590 }
591