PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.6
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.6
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 / campaigns / class-charitable-campaign-processor.php

class-charitable-campaign-processor.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.7.0.6, at includes/campaigns/class-charitable-campaign-processor.php

711 lines 17.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class that is responsible for creating campaigns.
4 *
5 * @package Charitable/Classes/Charitable_Campaign_Processor
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.5.9
10 * @version 1.6.54
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Campaign_Processor' ) ) :
19
20 /**
21 * Charitable_Campaign_Processor
22 *
23 * @since 1.5.9
24 */
25 class Charitable_Campaign_Processor {
26
27 /**
28 * Raw input args.
29 *
30 * @since 1.5.9
31 *
32 * @var array
33 */
34 protected $input;
35
36 /**
37 * Campaign values.
38 *
39 * @since 1.5.9
40 *
41 * @var array
42 */
43 protected $args;
44
45 /**
46 * Core post keys.
47 *
48 * @since 1.5.9
49 *
50 * @var array
51 */
52 protected $core_keys;
53
54 /**
55 * Campaign meta keys.
56 *
57 * @since 1.5.9
58 *
59 * @var array
60 */
61 protected $meta_keys;
62
63 /**
64 * Create class object.
65 *
66 * @since 1.5.9
67 *
68 * @param array $args Values for the campaign.
69 * @param array $meta_keys Meta keys to be saved as campaign meta.
70 */
71 public function __construct( array $args = array(), $meta_keys = null ) {
72 $this->input = $args;
73 $this->core_keys = array(
74 'ID' => 'ID',
75 'post_title' => 'title',
76 'post_content' => 'content',
77 'post_author' => 'creator',
78 'post_status' => 'status',
79 'post_parent' => 'parent',
80 );
81
82 $this->meta_keys = is_array( $meta_keys ) ? $meta_keys : array(
83 'goal',
84 'end_date',
85 'suggested_donations',
86 'suggested_donations_default',
87 'allow_custom_donations',
88 'description',
89 'minimum_donation_amount',
90 );
91
92 $this->parse_args();
93 }
94
95 /**
96 * Return the query argument value for the given key.
97 *
98 * @since 1.5.9
99 *
100 * @param string $key The key of the argument.
101 * @param mixed $fallback Default value to fall back to.
102 * @return mixed|false Returns fallback if the argument is not found.
103 */
104 public function get( $key, $fallback = false ) {
105 return isset( $this->args[ $key ] ) ? $this->args[ $key ] : $fallback;
106 }
107
108 /**
109 * Set the query argument for the given key.
110 *
111 * @since 1.5.9
112 *
113 * @param string $key Key of argument to set.
114 * @param mixed $value Value to be set.
115 * @return void
116 */
117 public function set( $key, $value ) {
118 $this->input[ $key ] = $value;
119 $this->args[ $key ] = $this->sanitize( $key, $value );
120 }
121
122 /**
123 * Sanitize arguments.
124 *
125 * @since 1.5.9
126 *
127 * @param string $key Key of argument to set.
128 * @param mixed $value Value to be set.
129 * @return mixed
130 */
131 public function sanitize( $key, $value ) {
132 $key = $this->truncated_key( $key );
133
134 /**
135 * If a class sanitization method exists for this key, call it.
136 */
137 if ( $this->use_sanitizer( $key ) ) {
138 $value = call_user_func( array( $this, 'sanitize_' . $key ), $value );
139 }
140
141 /**
142 * Filter a campaign argument when it is set.
143 *
144 * @since 1.5.9
145 *
146 * @param mixed $value The value.
147 * @param Charitable_Campaign_Processor $processor This processor object.
148 */
149 return apply_filters( 'charitable_campaign_processor_sanitize_' . $key, $value, $this );
150 }
151
152 /**
153 * Save the campaign to the database.
154 *
155 * @since 1.5.9
156 *
157 * @return int The campaign ID, or 0 if the campaign was not created.
158 */
159 public function save() {
160 $this->campaign_id = $this->save_core();
161
162 if ( ! $this->campaign_id || is_wp_error( $this->campaign_id ) ) {
163 return 0;
164 }
165
166 $this->save_meta();
167 $this->save_taxonomies();
168
169 return $this->campaign_id;
170 }
171
172 /**
173 * Save the core data.
174 *
175 * @since 1.5.9
176 *
177 * @return int|WP_Error The donation ID if succesful. The value 0 or WP_Error on failure.
178 */
179 public function save_core() {
180 $data = array_reduce( $this->core_keys, array( $this, 'get_core_data_value' ) );
181 $data['post_type'] = Charitable::CAMPAIGN_POST_TYPE;
182
183 /**
184 * Filter the core campaign data.
185 *
186 * @since 1.5.9
187 *
188 * @param array $data Core data.
189 * @param Charitable_Campaign_Processor $processor This processor object.
190 */
191 $data = apply_filters( 'charitable_campaign_processor_core_data', $data, $this );
192
193 /**
194 * Update or insert the campaign.
195 */
196 if ( $data['ID'] ) {
197 return wp_update_post( $data );
198 }
199
200 return wp_insert_post( $data );
201 }
202
203 /**
204 * Save the campaign meta data.
205 *
206 * @since 1.5.9
207 * @since 1.6.54 Return an array, instead of true.
208 *
209 * @return array The meta data saved, in key=>value format.
210 */
211 public function save_meta() {
212 /**
213 * Filter the campaign meta.
214 *
215 * @since 1.5.9
216 *
217 * @param array $meta Meta data.
218 * @param Charitable_Campaign_Processor $processor This processor object.
219 */
220
221 $meta = apply_filters( 'charitable_campaign_processor_meta_data', charitable_array_subset( $this->args, $this->meta_keys ), $this );
222
223 array_walk( $meta, array( $this, 'save_meta_field' ) );
224
225 return $meta;
226 }
227
228 /**
229 * Returns a truncated key.
230 *
231 * @since 1.5.9
232 *
233 * @param string $key The key to be truncated.
234 * @return string
235 */
236 public function truncated_key( $key ) {
237 return strpos( $key, '_campaign_' ) === 0 ? str_replace( '_campaign_', '', $key ) : $key;
238 }
239
240 /**
241 * Save the campaign meta data.
242 *
243 * @since 1.5.9
244 * @since 1.6.54 Return an array, instead of void.
245 *
246 * @return array Taxonomy data that was saved.
247 */
248 public function save_taxonomies() {
249 /**
250 * Filter the campaign taxonomy data.
251 *
252 * @since 1.5.9
253 *
254 * @param array $data Taxonomy data.
255 * @param Charitable_Campaign_Processor $processor This processor object.
256 */
257 $data = apply_filters(
258 'charitable_campaign_processor_taxonomy_data',
259 array(
260 'campaign_category' => $this->get( 'categories' ),
261 'campaign_tag' => $this->get( 'tags' ),
262 ),
263 $this
264 );
265
266 foreach ( $data as $taxonomy => $terms ) {
267 if ( false !== $terms ) {
268 wp_set_object_terms( $this->campaign_id, $terms, $taxonomy, false );
269 }
270 }
271
272 return $data;
273 }
274
275 /**
276 * Checks whether this is a new campaign being created,
277 * or an update to an existing campaign.
278 *
279 * @since 1.5.9
280 *
281 * @return boolean
282 */
283 public function is_new_campaign() {
284 return ! array_key_exists( 'ID', $this->input ) || 0 == $this->input['ID'];
285 }
286
287 /**
288 * Return the default arguments.
289 *
290 * @since 1.5.9
291 *
292 * @return boolean
293 */
294 protected function get_default_args() {
295 /**
296 * Set the default campaign arguments.
297 *
298 * @since 1.5.9
299 *
300 * @param array $args The list of default arguments.
301 */
302 return apply_filters(
303 'charitable_campaign_processor_default_args',
304 array(
305 'ID' => 0,
306 'title' => '',
307 'content' => '',
308 'creator' => get_current_user_id(),
309 'status' => 'publish',
310 'parent' => 0,
311 'image' => 0,
312 'description' => '',
313 'goal' => 0,
314 'end_date' => 0,
315 'suggested_donations' => array(),
316 'suggested_donations_default' => 0,
317 'allow_custom_donations' => 1,
318 'categories' => array(),
319 'tags' => array(),
320 'minimum_donation_amount' => 0,
321 )
322 );
323 }
324
325 /**
326 * Parse submitted values with the default values.
327 *
328 * @since 1.5.9
329 *
330 * @return array
331 */
332 protected function parse_args() {
333 if ( $this->is_new_campaign() ) {
334 $this->args = $this->get_default_args();
335 }
336
337 /**
338 * Set each passed argument.
339 */
340 array_walk( $this->input, array( $this, 'set_initial_arg' ) );
341
342 /**
343 * Set the campaign ID.
344 */
345 $this->campaign_id = $this->args['ID'];
346
347 return $this->args;
348 }
349
350 /**
351 * Set an arg that was passed when instantiating the object.
352 *
353 * @since 1.5.9
354 *
355 * @param mixed $value The arg value.
356 * @param string $key The arg key.
357 * @return void
358 */
359 protected function set_initial_arg( $value, $key ) {
360 $this->set( $key, $value );
361 }
362
363 /**
364 * Sanitize the campaign status.
365 *
366 * @since 1.5.9
367 *
368 * @param mixed $value The submitted end date.
369 * @return string
370 */
371 protected function sanitize_status( $value ) {
372 if ( ! in_array( $value, get_post_stati() ) ) {
373 $value = 'publish';
374 }
375
376 return $value;
377 }
378
379 /**
380 * Sanitize the campaign creator.
381 *
382 * This checks to ensure that a user actually exists for the given ID.
383 *
384 * @since 1.5.9
385 *
386 * @param mixed $value The submitted creator ID.
387 * @return string
388 */
389 protected function sanitize_creator( $value ) {
390 $user = get_user_by( 'id', $value );
391
392 if ( false === $user ) {
393 $value = 0;
394 }
395
396 return $value;
397 }
398
399 /**
400 * Sanitize the goal.
401 *
402 * @since 1.5.9
403 *
404 * @param string $value Current value of goal.
405 * @return float
406 */
407 protected function sanitize_goal( $value ) {
408 if ( $this->should_skip_sanitizer_for_key( 'goal', array( 'Charitable_Campaign', 'sanitize_campaign_goal' ) ) ) {
409 return $value;
410 }
411
412 return Charitable_Campaign::sanitize_campaign_goal( (string) $value );
413 }
414
415 /**
416 * Sanitize the suggested donations.
417 *
418 * @since 1.5.9
419 *
420 * @param arrat $value Current value of suggested_donations.
421 * @return array
422 */
423 protected function sanitize_suggested_donations( $value ) {
424 if ( $this->should_skip_sanitizer_for_key( 'suggested_donations', array( 'Charitable_Campaign', 'sanitize_campaign_suggested_donations' ) ) ) {
425 return $value;
426 }
427
428 return Charitable_Campaign::sanitize_campaign_suggested_donations( $value );
429 }
430
431 /**
432 * Sanitize the suggested donations default
433 *
434 * @since 1.5.9
435 *
436 * @param arrat $value Current value of suggested_donations.
437 * @return array
438 */
439 protected function sanitize_suggested_donations_default( $value ) {
440 if ( $this->should_skip_sanitizer_for_key( 'suggested_donations_default', array( 'Charitable_Campaign', 'sanitize_campaign_suggested_donations' ) ) ) {
441 return $value;
442 }
443
444 return Charitable_Campaign::sanitize_campaign_suggested_donations_default( $value );
445 }
446
447 /**
448 * Sanitize the custom donations checkbox.
449 *
450 * @since 1.5.9
451 *
452 * @param int $value Current value of custom donations.
453 * @return int
454 */
455 protected function sanitize_allow_custom_donations( $value ) {
456 if ( $this->should_skip_sanitizer_for_key( 'allow_custom_donations', array( 'Charitable_Campaign', 'sanitize_custom_donations' ) ) ) {
457 return $value;
458 }
459
460 return Charitable_Campaign::sanitize_custom_donations( $value, $this->input );
461 }
462
463 /**
464 * Return the input value of the suggested donations, or the existing suggested
465 * donations for the campaign if this is an update.
466 *
467 * @since 1.5.9
468 *
469 * @return array
470 */
471 public function get_suggested_donations_value() {
472 if ( array_key_exists( 'suggested_donations', $this->input ) ) {
473 return $this->input['suggested_donations'];
474 }
475
476 if ( $this->is_new_campaign() ) {
477 return array();
478 }
479
480 return charitable_get_campaign( $this->args['ID'] )->get_suggested_donations();
481 }
482
483 /**
484 * Sanitize the description.
485 *
486 * @since 1.5.9
487 *
488 * @param arrat $value Current value of description.
489 * @return array
490 */
491 protected function sanitize_description( $value ) {
492 if ( $this->should_skip_sanitizer_for_key( 'description', array( 'Charitable_Campaign', 'sanitize_campaign_description' ) ) ) {
493 return $value;
494 }
495
496 return Charitable_Campaign::sanitize_campaign_description( $value );
497 }
498
499 /**
500 * Sanitize the end date.
501 *
502 * @since 1.5.9
503 *
504 * @param mixed $value The submitted end date.
505 * @return string
506 */
507 protected function sanitize_end_date( $value ) {
508 if ( 0 == $value ) {
509 return 0;
510 }
511
512 if ( ! $this->is_mysql_date_format( $value ) ) {
513 charitable_get_deprecated()->doing_it_wrong(
514 __METHOD__,
515 sprintf( __( 'Campaign processor requires date in YYYY-MM-DD format. Date passed as %s. This message was added in Charitable version 1.5.9.', 'charitable' ), $value ),
516 null
517 );
518
519 return 0;
520 }
521
522 if ( false === strpos( $value, ' ' ) ) {
523 $value .= ' 23:59:59';
524 }
525
526 return $value;
527 }
528
529 /**
530 * Checks whether the passed date is in MySQL date format.
531 *
532 * @since 1.5.9
533 *
534 * @param string $date The date.
535 * @return boolean
536 */
537 protected function is_mysql_date_format( $date ) {
538 return preg_match( '/^\d{4}-\d{2}-\d{2}/', $date );
539 }
540
541 /**
542 * After saving the thumbnail ID, maybe attach its attachment post
543 * to the current campaign.
544 *
545 * @since 1.5.9
546 *
547 * @param int|string $value The thumbnail ID.
548 * @return void
549 */
550 protected function post_process_image( $value ) {
551 if ( empty( $value ) ) {
552 return;
553 }
554
555 $parent = get_post_field( 'post_parent', $value );
556
557 /* If the image is unattached to any post, attach it to the campaign. */
558 if ( 0 === $parent ) {
559 wp_update_post(
560 array(
561 'ID' => $value,
562 'post_parent' => $this->campaign_id,
563 )
564 );
565 }
566 }
567
568 /**
569 * Given a key, checks whether the key is set and if it is,
570 * gets the correct core key (i.e. post_content vs content)
571 * and the value.
572 *
573 * @since 1.5.9
574 *
575 * @return mixed
576 */
577 public function get_core_data_value( $ret, $key ) {
578 if ( is_null( $ret ) ) {
579 $ret = array();
580 }
581
582 if ( array_key_exists( $key, $this->args ) ) {
583 $ret[ array_search( $key, $this->core_keys ) ] = $this->args[ $key ];
584 }
585
586 return $ret;
587 }
588
589 /**
590 * Save a meta field.
591 *
592 * @since 1.5.9
593 *
594 * @param mixed $value The value of the meta field.
595 * @param string $key The key of the meta field.
596 * @return void
597 */
598 protected function save_meta_field( $value, $key ) {
599 update_post_meta( $this->campaign_id, $this->get_meta_key( $key ), $value );
600
601 if ( method_exists( $this, 'post_process_' . $key ) ) {
602 call_user_func( array( $this, 'post_process_' . $key ), $value );
603 }
604 }
605
606 /**
607 * Returns a sanitized meta key.
608 *
609 * @since 1.5.9
610 *
611 * @param string $key The key to be sanitized.
612 * @return string
613 */
614 protected function get_meta_key( $key ) {
615 if ( 'image' == $key ) {
616 return '_thumbnail_id';
617 }
618
619 $sanitized = strpos( $key, '_campaign_' ) === 0 ? $key : '_campaign_' . $key;
620
621 /**
622 * Filter the meta key.
623 *
624 * @since 1.0.0
625 *
626 * @param string $key The meta key.
627 * @param string $original The original passed key.
628 * @param int $campaign_id The campaign ID.
629 */
630 return apply_filters( 'charitable_campaign_meta_key', $sanitized, $key, $this->campaign_id );
631 }
632
633 /**
634 * Checks whether the original callback function which was hooked for a
635 * particular meta field is still hooked.
636 *
637 * We do this for backwards compatibility reasons. If the function is
638 * still hooked, we do nothing. If it is _not_ hooked, that indicates
639 * that the user used remove_filter() to disable the sanitizer, in
640 * which case we should prevent further sanitization. In this case,
641 * we also fire a notice to let users know that this approach is
642 * deprecated, along with a way to fix it.
643 *
644 * @since 1.5.9
645 *
646 * @param string $key The field key.
647 * @param callback $callback The callback function.
648 * @return boolean
649 */
650 protected function should_skip_sanitizer_for_key( $key, $callback ) {
651 $tag = 'charitable_sanitize_campaign_meta_campaign_' . $key;
652
653 /* We already used the sanitizer. Remove this in Charitable 1.6/1.7. */
654 if ( did_action( $tag ) ) {
655 return true;
656 }
657
658 /* It is still hooked, we do not want to skip the sanitizer. */
659 if ( has_filter( $tag, $callback ) ) {
660 return false;
661 }
662
663 /**
664 * If we get here, the user has disabled the field's default
665 * sanitizer, so we will skip the sanitizer, while firing a
666 * notice to advise that this method of unhooking the sanitizer
667 * is now deprecated.
668 */
669 $method = is_array( $callback ) ? implode( '::', $callback ) : $method;
670
671 charitable_get_deprecated()->doing_it_wrong(
672 $tag,
673 sprintf( __( '%s is deprecated as a sanitizer on the %s hook. To prevent sanitization, use add_filter( \'charitable_campaign_processor_disable_sanitizer_%s\', \'__return_true\' ) instead.', 'charitable' ),
674 $method,
675 $tag,
676 $key
677 ),
678 '1.5.9'
679 );
680
681 return true;
682 }
683
684 /**
685 * Checks whether an internal sanitizer exists for a particular
686 * field, and whether it has been disabled.
687 *
688 * @since 1.5.9
689 *
690 * @param string $key The field key.
691 * @return boolean
692 */
693 protected function use_sanitizer( $key ) {
694 /* If there is no sanitizer, return false. */
695 if ( ! method_exists( $this, 'sanitize_' . $key ) ) {
696 return false;
697 }
698
699 /**
700 * Disable the internal sanitizer for a particular key.
701 *
702 * @since 1.5.9
703 *
704 * @return boolean
705 */
706 return ! apply_filters( 'charitable_campaign_processor_disable_sanitizer_' . $key, false );
707 }
708 }
709
710 endif;
711