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 / donations / class-charitable-donation-meta-boxes.php

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

608 lines 17.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Sets up the donation meta boxes.
4 *
5 * @package Charitable/Classes/Charitable_Donation_Meta_Boxes
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.53
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 if ( ! class_exists( 'Charitable_Donation_Meta_Boxes' ) ) :
18
19 /**
20 * Charitable_Donation_Meta_Boxes class.
21 *
22 * @final
23 * @since 1.5.0
24 */
25 final class Charitable_Donation_Meta_Boxes {
26
27 /**
28 * The single instance of this class.
29 *
30 * @var Charitable_Donation_Meta_Boxes|null
31 */
32 private static $instance = null;
33
34 /**
35 * @var Charitable_Meta_Box_Helper $meta_box_helper
36 */
37 private $meta_box_helper;
38
39 /**
40 * Create object instance.
41 *
42 * @since 1.5.0
43 *
44 * @param Charitable_Meta_Box_Helper $helper The meta box helper class.
45 */
46 public function __construct( Charitable_Meta_Box_Helper $helper ) {
47 $this->meta_box_helper = $helper;
48 }
49
50 /**
51 * Returns and/or create the single instance of this class.
52 *
53 * @since 1.5.0
54 *
55 * @return Charitable_Donation_Meta_Boxes
56 */
57 public static function get_instance() {
58 if ( is_null( self::$instance ) ) {
59 self::$instance = new self(
60 new Charitable_Meta_Box_Helper( 'charitable-donation' )
61 );
62 }
63
64 return self::$instance;
65 }
66
67 /**
68 * Add needed css classes to body HTML tag.
69 *
70 * @since 1.8.1
71 * @version 1.8.9.1
72 *
73 * @param string $classes The body classes.
74 * @return string
75 */
76 public function add_body_class( $classes = '' ) {
77
78 if ( ! function_exists( 'get_current_screen' ) ) {
79 return $classes;
80 }
81
82 $screen = get_current_screen();
83
84 if ( 'donation' !== $screen->post_type ) {
85 return $classes;
86 }
87 // phpcs:disable WordPress.Security.NonceVerification.Recommended
88 if ( ! empty( $_GET['action'] ) ) {
89 $classes .= ' charitable-admin-donation-' . esc_attr( sanitize_text_field( wp_unslash( $_GET['action'] ) ) ) . ' ';
90 }
91 // phpcs:enable WordPress.Security.NonceVerification.Recommended
92
93 return $classes;
94
95 }
96
97 /**
98 * Sets up the meta boxes to display on the donation admin page.
99 *
100 * @since 1.5.0
101 *
102 * @return void
103 */
104 public function add_meta_boxes() {
105 foreach ( $this->get_meta_boxes() as $meta_box_id => $meta_box ) {
106 add_meta_box(
107 $meta_box_id,
108 $meta_box['title'],
109 array( $this->meta_box_helper, 'metabox_display' ),
110 Charitable::DONATION_POST_TYPE,
111 $meta_box['context'],
112 $meta_box['priority'],
113 $meta_box
114 );
115 }
116 }
117
118 /**
119 * Remove default meta boxes.
120 *
121 * @since 1.5.0
122 *
123 * @global array $wp_meta_boxes Registered meta boxes in WP.
124 * @return void
125 */
126 public function remove_meta_boxes() {
127 global $wp_meta_boxes;
128
129 $charitable_meta_boxes = $this->get_meta_boxes();
130
131 foreach ( $wp_meta_boxes[ Charitable::DONATION_POST_TYPE ] as $context => $priorities ) {
132 foreach ( $priorities as $priority => $meta_boxes ) {
133 foreach ( $meta_boxes as $meta_box_id => $meta_box ) {
134 if ( ! isset( $charitable_meta_boxes[ $meta_box_id ] ) ) {
135 remove_meta_box( $meta_box_id, Charitable::DONATION_POST_TYPE, $context );
136 }
137 }
138 }
139 }
140 }
141
142 /**
143 * Returns an array of all meta boxes added to the donation post type screen.
144 *
145 * @since 1.5.0
146 * @version 1.8.9.1
147 *
148 * @return array
149 */
150 private function get_meta_boxes() {
151 $screen = get_current_screen();
152
153 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
154 $show_form = isset( $_GET['show_form'] );
155 if ( 'donation' == $screen->post_type && ( 'add' == $screen->action || $show_form ) ) {
156 $meta_boxes = $this->get_form_meta_box();
157 } else {
158 $meta_boxes = $this->get_view_meta_boxes();
159 }
160
161 /**
162 * Filter the meta boxes to be displayed on a donation overview page.
163 *
164 * @since 1.0.0
165 *
166 * @param array $meta_boxes The array of meta boxes and their details.
167 */
168 return apply_filters( 'charitable_donation_meta_boxes', $meta_boxes );
169 }
170
171 /**
172 * Return the form meta box.
173 *
174 * @since 1.5.0
175 *
176 * @return array
177 */
178 public function get_form_meta_box() {
179 global $post;
180
181 $form = new Charitable_Admin_Donation_Form( charitable_get_donation( $post->ID ) );
182 $meta_boxes = array(
183 'donation-form' => array(
184 'title' => __( 'Donation Form', 'charitable' ),
185 'context' => 'normal',
186 'priority' => 'high',
187 'view' => 'metaboxes/donation/donation-form',
188 'form' => $form,
189 ),
190 'donation-form-meta' => array(
191 'title' => __( 'Additional Details', 'charitable' ),
192 'context' => 'side',
193 'priority' => 'high',
194 'view' => 'metaboxes/donation/donation-form-meta',
195 'form' => $form,
196 ),
197 );
198
199 /**
200 * Filter the meta boxes to be displayed on a donation add/edit page.
201 *
202 * @since 1.0.0
203 *
204 * @param array $meta_boxes The array of meta boxes and their details.
205 */
206 return apply_filters( 'charitable_donation_form_meta_boxes', $meta_boxes );
207 }
208
209 /**
210 * Return the view meta boxes.
211 *
212 * @since 1.5.0
213 * @since 1.7.0.8
214 *
215 * @return array
216 */
217 public function get_view_meta_boxes() {
218 global $post;
219
220 $meta_boxes = array(
221 'donation-overview' => array(
222 'title' => __( 'Donation Overview', 'charitable' ),
223 'context' => 'normal',
224 'priority' => 'high',
225 'view' => 'metaboxes/donation/donation-overview',
226 ),
227 'donation-actions' => array(
228 'title' => __( 'Donation Actions', 'charitable' ),
229 'context' => 'side',
230 'priority' => 'high',
231 'view' => 'metaboxes/actions',
232 'actions' => charitable_get_donation_actions(),
233 ),
234 'donation-details' => array(
235 'title' => __( 'Donation Details', 'charitable' ),
236 'context' => 'side',
237 'priority' => 'high',
238 'view' => 'metaboxes/donation/donation-details',
239 ),
240 'donation-log' => array(
241 'title' => __( 'Donation Log', 'charitable' ),
242 'context' => 'normal',
243 'priority' => 'low',
244 'view' => 'metaboxes/donation/donation-log',
245 ),
246 'donation-donor-history' => array(
247 'title' => __( 'Related Donations <span class="badge beta">Beta</span>', 'charitable' ),
248 'context' => 'side',
249 'priority' => 'low',
250 'view' => 'metaboxes/donation/donation-donor-history',
251 'help' => ''
252 ),
253 );
254
255 /* Get rid of the donation actions meta box if it doesn't apply to this donation. */
256 if ( ! charitable_get_donation_actions()->has_available_actions( $post->ID ) ) {
257 unset( $meta_boxes['donation-actions'] );
258 }
259
260 /**
261 * Filter the meta boxes to be displayed on a donation overview page.
262 *
263 * @since 1.5.0
264 *
265 * @param array $meta_boxes The array of meta boxes and their details.
266 */
267 return apply_filters( 'charitable_donation_view_meta_boxes', $meta_boxes );
268 }
269
270 /**
271 * Create donation actions instance, with some initial defaults.
272 *
273 * @since 1.6.0
274 *
275 * @return void
276 */
277 public function register_donation_actions() {
278 $donation_actions = charitable_get_donation_actions();
279
280 foreach ( charitable_get_valid_donation_statuses() as $status => $label ) {
281 $donation_actions->register(
282 'change_status_to_' . $status,
283 array(
284 'label' => $label,
285 'callback' => array( $this, 'change_donation_status' ),
286 'button_text' => __( 'Update Status', 'charitable' ),
287 'active_callback' => array( $this, 'can_change_donation_status' ),
288 'success_message' => 13,
289 'failed_message' => 14,
290 'fields' => array( $this, 'get_donation_status_change_fields' ),
291 ),
292 __( 'Change Status', 'charitable' )
293 );
294 }
295 }
296
297 /**
298 * Check whether a particular status change works for the given donation.
299 *
300 * @since 1.6.0
301 *
302 * @param int $object_id The donation's ID.
303 * @param array $args Mixed action arguments.
304 * @return boolean
305 */
306 public function can_change_donation_status( $object_id, $args = array() ) {
307 $donation = charitable_get_donation( $object_id );
308
309 return $donation && $args['action_args']['label'] !== $donation->get_status_label();
310 }
311
312 /**
313 * Change a donation's status.
314 *
315 * @since 1.6.0
316 *
317 * @param boolean $success Whether the action has been run.
318 * @param int $object_id The donation's ID.
319 * @param array $args Mixed action arguments.
320 * @param string $action The action id.
321 * @return boolean Whether the status was changed.
322 */
323 public function change_donation_status( $success, $object_id, $args, $action ) {
324 $donation = charitable_get_donation( $object_id );
325
326 if ( ! $donation ) {
327 return false;
328 }
329
330 $status = str_replace( 'change_status_to_', '', $action );
331 $success = $donation->update_status( $status );
332
333 if ( array_key_exists( 'gateway_refund', $_POST ) && $_POST['gateway_refund'] ) { // phpcs:ignore
334 $gateway = $donation->get_gateway();
335
336 /**
337 * Perform a refund in the donation's gateway.
338 *
339 * @since 1.6.0
340 *
341 * @param int $donation_id The donation's ID.
342 */
343 do_action( 'charitable_process_refund_' . $gateway, $object_id );
344 }
345
346 return 0 !== $success;
347 }
348
349 /**
350 * Additional fields to display for a status change.
351 *
352 * @since 1.6.0
353 *
354 * @param int $object_id The donation's ID.
355 * @param array $action Mixed action arguments.
356 * @return void
357 */
358 public function get_donation_status_change_fields( $object_id, $action ) {
359 $statuses = charitable_get_valid_donation_statuses();
360
361 if ( $statuses['charitable-refunded'] != $action['label'] ) {
362 return;
363 }
364
365 $donation = charitable_get_donation( $object_id );
366
367 if ( ! $donation || ! $donation->is_refundable_in_gateway() ) {
368 return;
369 }
370
371 printf(
372 /* translators: %s: gateway name */
373 '%s' . esc_html__( 'Refund in %s automatically.', 'charitable' ),
374 '<input type="checkbox" name="gateway_refund" value="1" />',
375 esc_html( $donation->get_gateway_object()->get_name() )
376 );
377 }
378
379 /**
380 * Save meta for the donation.
381 *
382 * @since 1.5.0
383 *
384 * @param int $donation_id
385 * @param WP_Post $post
386 * @return void
387 */
388 public function save_donation( $donation_id, WP_Post $post ) {
389 if ( ! $this->meta_box_helper->user_can_save( $donation_id ) ) {
390 return;
391 }
392
393 $this->maybe_save_form_submission( $donation_id );
394
395 /* Handle any fired actions */
396 if ( ! empty( $_POST['charitable_donation_action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
397 charitable_get_donation_actions()->do_action( sanitize_text_field( $_POST['charitable_donation_action'] ), $donation_id ); // phpcs:ignore
398 }
399
400 /**
401 * Hook for plugins to do something else with the posted data.
402 *
403 * @since 1.0.0
404 *
405 * @param int $donation_id The donation ID.
406 * @param WP_Post $post Instance of `WP_Post`.
407 */
408 do_action( 'charitable_donation_save', $donation_id, $post );
409 }
410
411 /**
412 * Save a donation after the admin donation form has been submitted.
413 *
414 * @since 1.5.0
415 *
416 * @param int $donation_id The donation ID.
417 * @return boolean True if this was a form submission. False otherwise.
418 */
419 public function maybe_save_form_submission( $donation_id ) {
420 if ( ! $this->is_admin_donation_save() || did_action( 'charitable_before_save_donation' ) ) {
421 return false;
422 }
423
424 $form = new Charitable_Admin_Donation_Form( charitable_get_donation( $donation_id ) );
425
426 if ( ! $form->validate_submission() ) {
427 wp_safe_redirect( admin_url( 'post-new.php?post_type=donation&show_form=1' ) );
428 exit();
429 }
430
431 charitable_create_donation( $form->get_donation_values() );
432
433 update_post_meta( $donation_id, '_donation_manually_edited', true );
434
435 return true;
436 }
437
438 /**
439 * Change messages when a post type is updated.
440 *
441 * @since 1.5.0
442 * @version 1.8.1.15
443 *
444 * @param array $messages The post messages.
445 * @return array
446 */
447 public function post_messages( $messages ) {
448 global $post, $post_ID;
449
450 $messages[ Charitable::DONATION_POST_TYPE ] = array(
451 0 => '', // Unused. Messages start at index 1.
452 1 => sprintf(
453 /* translators: %s: link */
454 __( 'Donation updated. <a href="%s">View Donation</a>', 'charitable' ),
455 esc_url( get_permalink( $post_ID ) )
456 ),
457 2 => __( 'Custom field updated.', 'charitable' ),
458 3 => __( 'Custom field deleted.', 'charitable' ),
459 4 => __( 'Donation updated.', 'charitable' ),
460 5 => // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display only, no action
461 isset( $_GET['revision'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
462 ? sprintf(
463 /* translators: %s: revision title */
464 __( 'Donation restored to revision from %s', 'charitable' ),
465 wp_post_revision_title( (int) sanitize_text_field( wp_unslash( $_GET['revision'] ) ), false ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
466 )
467 : false,
468 6 => sprintf(
469 /* translators: %s: link */
470 __( 'Donation published. <a href="%s">View Donation</a>', 'charitable' ),
471 esc_url( get_permalink( $post_ID ) )
472 ),
473 7 => __( 'Donation saved.', 'charitable' ),
474 8 => sprintf(
475 /* translators: %s: link */
476 __( 'Donation submitted. <a target="_blank" href="%s">Preview Donation</a>', 'charitable' ),
477 esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) )
478 ),
479 9 => sprintf(
480 /* translators: %1$s: date and time; %2$s: link */
481 __( 'Donation scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview Donation</a>', 'charitable' ),
482 date_i18n( 'M j, Y @ G:i', strtotime( $post->post_date ) ),
483 esc_url( get_permalink( $post_ID ) )
484 ),
485 10 => sprintf(
486 /* translators: %s: link */
487 __( 'Donation draft updated. <a target="_blank" href="%s">Preview Donation</a>', 'charitable' ),
488 esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) )
489 ),
490 11 => __( 'Email resent.', 'charitable' ),
491 12 => __( 'Email could not be resent.', 'charitable' ),
492 13 => __( 'Donation status changed.', 'charitable' ),
493 14 => __( 'Donation status could not be changed.', 'charitable' ),
494 );
495
496 return $messages;
497 }
498
499 /**
500 * Prevent email from sending if we are saving the donation via the admin.
501 *
502 * @since 1.6.15
503 *
504 * @param boolean $send_email Whether to send the email.
505 * @param Charitable_Donation $donation The donation object.
506 * @return boolean
507 */
508 public function maybe_block_new_donation_email( $send_email, Charitable_Donation $donation ) {
509 if ( ! $send_email ) {
510 return $send_email;
511 }
512
513 /* Don't block sending it from donation actions. */
514 if ( $this->is_donation_action() ) {
515 return $send_email;
516 }
517
518 /* If we're not saving the donation, send the email. */
519 if ( ! $this->is_admin_donation_save() ) {
520 return $send_email;
521 }
522
523 /* If this isn't the `charitable_after_save_donation` hook, don't send the email. */
524 if ( ! doing_action( 'charitable_after_save_donation' ) ) {
525 return false;
526 }
527
528 /* If this isn't a manually created donation, send the email. */
529 if ( 'manual' !== $donation->get_gateway() ) {
530 return $send_email;
531 }
532
533 /* Do not send admin notifications for manually created donations. */
534 return false;
535 }
536
537 /**
538 * Prevent email from sending if we are saving the donation via the admin.
539 *
540 * @since 1.6.15
541 *
542 * @param boolean $send_email Whether to send the email.
543 * @param Charitable_Donation $donation The donation object.
544 * @return boolean
545 */
546 public function maybe_block_donation_receipt_email( $send_email, Charitable_Donation $donation ) {
547 if ( ! $send_email ) {
548 return $send_email;
549 }
550
551 /* Don't block sending it from donation actions. */
552 if ( $this->is_donation_action() ) {
553 return $send_email;
554 }
555
556 /* If we're not saving the donation, send the email. */
557 if ( ! $this->is_admin_donation_save() ) {
558 return $send_email;
559 }
560
561 /* If this isn't the `charitable_after_save_donation` hook, don't send the email. */
562 if ( ! doing_action( 'charitable_after_save_donation' ) ) {
563 return false;
564 }
565
566 /* If this isn't a manually created donation, send the email. */
567 if ( 'manual' !== $donation->get_gateway() ) {
568 return $send_email;
569 }
570
571 /**
572 * Finally, if we're saving a manually created donation, only
573 * send the email if that option was checked in the admin.
574 */
575 // phpcs:disable WordPress.Security.NonceVerification.Missing
576 return array_key_exists( 'send_donation_receipt', $_POST ) && ! empty( sanitize_text_field( wp_unslash( $_POST['send_donation_receipt'] ) ) );
577 // phpcs:enable WordPress.Security.NonceVerification.Missing
578 }
579
580 /**
581 * Checks whether we are saving the admin donation form.
582 *
583 * @since 1.6.15
584 * @version 1.8.9.1
585 *
586 * @return boolean
587 */
588 public function is_admin_donation_save() {
589 // phpcs:ignore WordPress.Security.NonceVerification.Missing
590 return array_key_exists( 'charitable_action', $_POST );
591 }
592
593 /**
594 * Checks whether we are doing a donation action.
595 *
596 * @since 1.6.15
597 * @version 1.8.9.1
598 *
599 * @return boolean
600 */
601 public function is_donation_action() {
602 // phpcs:ignore WordPress.Security.NonceVerification.Missing
603 return array_key_exists( 'charitable_donation_action', $_POST );
604 }
605 }
606
607 endif;
608