PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.7
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.7
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 / abstracts / abstract-class-charitable-email.php

abstract-class-charitable-email.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.7.0.7, at includes/abstracts/abstract-class-charitable-email.php

910 lines 20.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Email model.
4 *
5 * @package Charitable/Classes/Charitable_Email
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 if ( ! class_exists( 'Charitable_Email' ) ) :
19
20 /**
21 * Charitable_Email
22 *
23 * @since 1.0.0
24 */
25 abstract class Charitable_Email implements Charitable_Email_Interface {
26
27 /** Email ID */
28 const ID = '';
29
30 /**
31 * Descriptive name of the email.
32 *
33 * @since 1.0.0
34 *
35 * @var string
36 */
37 protected $name;
38
39 /**
40 * Array of supported object types (campaigns, donations, donors, etc).
41 *
42 * @since 1.0.0
43 *
44 * @var string[]
45 */
46 protected $object_types = array();
47
48 /**
49 * Whether the email allows you to define the email recipients.
50 *
51 * @since 1.0.0
52 *
53 * @var boolean
54 */
55 protected $has_recipient_field = false;
56
57 /**
58 * Whether the email is required.
59 *
60 * @since 1.4.0
61 *
62 * @var boolean
63 */
64 protected $required = false;
65
66 /**
67 * The Donation object, if relevant.
68 *
69 * @since 1.0.0
70 *
71 * @var Charitable_Donation
72 */
73 protected $donation;
74
75 /**
76 * The Campaign object, if relevant.
77 *
78 * @since 1.0.0
79 *
80 * @var Charitable_Campaign
81 */
82 protected $campaign;
83
84 /**
85 * Email recipient.
86 *
87 * @since 1.0.0
88 *
89 * @var string
90 */
91 protected $recipients;
92
93 /**
94 * Email headers.
95 *
96 * @since 1.0.0
97 *
98 * @var string
99 */
100 protected $headers;
101
102 /**
103 * Email attachments.
104 *
105 * @since 1.6.59
106 *
107 * @var string
108 */
109 protected $attachments;
110
111 /**
112 * Create a class instance.
113 *
114 * @since 1.0.0
115 *
116 * @param mixed[] $objects Objects for the email.
117 */
118 public function __construct( $objects = array() ) {
119 $this->donation = isset( $objects['donation'] ) ? $objects['donation'] : null;
120 $this->campaign = isset( $objects['campaign'] ) ? $objects['campaign'] : null;
121 }
122
123 /**
124 * Return an instance property.
125 *
126 * @since 1.5.0
127 *
128 * @param key $property The property to return.
129 * @return mixed
130 */
131 public function get( $property ) {
132 if ( property_exists( $this, $property ) ) {
133 return $this->$property;
134 }
135
136 return '';
137 }
138
139 /**
140 * Return the email name.
141 *
142 * @since 1.0.0
143 *
144 * @return string
145 */
146 public function get_name() {
147 return $this->name;
148 }
149
150 /**
151 * Return whether the email is required.
152 *
153 * If an email is required, it cannot be disabled/enabled, but it can still be edited.
154 *
155 * @since 1.4.0
156 *
157 * @return boolean
158 */
159 public function is_required() {
160 return $this->required;
161 }
162
163 /**
164 * Return the types of objects.
165 *
166 * @since 1.3.0
167 *
168 * @return string[]
169 */
170 public function get_object_types() {
171 return $this->object_types;
172 }
173
174 /**
175 * Return the donation object.
176 *
177 * @since 1.3.0
178 *
179 * @return null|Charitable_Donation
180 */
181 public function get_donation() {
182 return $this->donation;
183 }
184
185 /**
186 * Return the campaign object.
187 *
188 * @since 1.3.0
189 *
190 * @return null|Charitable_Campaign
191 */
192 public function get_campaign() {
193 return $this->campaign;
194 }
195
196 /**
197 * Get from name for email.
198 *
199 * @since 1.0.0
200 *
201 * @return string
202 */
203 public function get_from_name() {
204 return wp_specialchars_decode( charitable_get_option( 'email_from_name', get_option( 'blogname' ) ) );
205 }
206
207 /**
208 * Get from address for email.
209 *
210 * @since 1.0.0
211 *
212 * @return string
213 */
214 public function get_from_address() {
215 return charitable_get_option( 'email_from_email', get_option( 'admin_email' ) );
216 }
217
218 /**
219 * Return the email recipients.
220 *
221 * @since 1.0.0
222 *
223 * @return string
224 */
225 public function get_recipient() {
226 return $this->get_option( 'recipient', $this->get_default_recipient() );
227 }
228
229 /**
230 * Return the email subject line.
231 *
232 * @since 1.0.0
233 *
234 * @return string
235 */
236 public function get_subject() {
237 /**
238 * Allow the email subject to be filtered.
239 *
240 * @since 1.6.60
241 *
242 * @param string $subject The email subject.
243 * @param \Charitable_Email $email The email object.
244 */
245 return apply_filters(
246 'charitable_email_subject',
247 $this->get_option( 'subject', $this->get_default_subject() ),
248 $this
249 );
250 }
251
252 /**
253 * Get the email content type
254 *
255 * @since 1.0.0
256 *
257 * @return string
258 */
259 public function get_content_type() {
260 /**
261 * Filter the content type for the email.
262 *
263 * @since 1.0.0
264 *
265 * @param string $content_type The content type. Defaults to 'text/html'.
266 * @param \Charitable_Email $email This instance of `Charitable_Email`.
267 */
268 return apply_filters( 'charitable_email_content_type', 'text/html', $this );
269 }
270
271 /**
272 * Get the email headers.
273 *
274 * @since 1.0.0
275 *
276 * @return string
277 */
278 public function get_headers() {
279 if ( ! isset( $this->headers ) ) {
280 $this->headers = "From: {$this->get_from_name()} <{$this->get_from_address()}>\r\n";
281 $this->headers .= "Reply-To: {$this->get_from_address()}\r\n";
282 $this->headers .= "Content-Type: {$this->get_content_type()}; charset=utf-8\r\n";
283 }
284
285 /**
286 * Filter the email headers.
287 *
288 * @since 1.0.0
289 *
290 * @param string $headers The default email headers.
291 * @param \Charitable_Email $email The email object.
292 */
293 return apply_filters( 'charitable_email_headers', $this->headers, $this );
294 }
295
296 /**
297 * Get the email attachments.
298 *
299 * @since 1.6.59
300 *
301 * @return array
302 */
303 public function get_attachments() {
304 if ( ! isset( $this->attachments ) ) {
305 $this->attachments = array();
306 }
307
308 /**
309 * Filter the email attachments.
310 *
311 * @since 1.6.59
312 *
313 * @param array $attachments The default email attachments.
314 * @param \Charitable_Email $email The email object.
315 */
316 return apply_filters( 'charitable_email_attachments', $this->attachments, $this );
317 }
318
319 /**
320 * Checks whether we are currently previewing the email.
321 *
322 * @since 1.3.5
323 *
324 * @return boolean
325 */
326 public function is_preview() {
327 return isset( $_GET['charitable_action'] ) && 'preview_email' == $_GET['charitable_action'];
328 }
329
330 /**
331 * Register email settings.
332 *
333 * @since 1.0.0
334 * @since 1.5.0 $settings argument is now deprecated.
335 * @since 1.5.7 $settings argument removed from function definition.
336 *
337 * @return array
338 */
339 public function email_settings() {
340 if ( func_num_args() ) {
341 charitable_get_deprecated()->deprecated_argument(
342 __METHOD__,
343 '1.5.0',
344 __( 'The `$settings` parameter is no longer used.', 'charitable' )
345 );
346 }
347
348 $email_settings = array(
349 'section_email' => array(
350 'type' => 'heading',
351 'title' => $this->get_name(),
352 'priority' => 2,
353 ),
354 'subject' => array(
355 'type' => 'text',
356 'title' => __( 'Email Subject Line', 'charitable' ),
357 'help' => __( 'The email subject line when it is delivered to recipients.', 'charitable' ),
358 'priority' => 6,
359 'class' => 'wide',
360 'default' => $this->get_default_subject(),
361 ),
362 'headline' => array(
363 'type' => 'text',
364 'title' => __( 'Email Headline', 'charitable' ),
365 'help' => __( 'The headline displayed at the top of the email.', 'charitable' ),
366 'priority' => 10,
367 'class' => 'wide',
368 'default' => $this->get_default_headline(),
369 ),
370 'body' => array(
371 'type' => 'editor',
372 'title' => __( 'Email Body', 'charitable' ),
373 'help' => sprintf(
374 '%s <div class="charitable-shortcode-options">%s</div>',
375 __( 'The content of the email that will be delivered to recipients. HTML is accepted.', 'charitable' ),
376 $this->get_shortcode_options()
377 ),
378 'priority' => 14,
379 'default' => $this->get_default_body(),
380 ),
381 'preview' => array(
382 'type' => 'content',
383 'title' => __( 'Preview', 'charitable' ),
384 'content' => sprintf(
385 '<a href="%s" target="_blank" class="button">%s</a>',
386 esc_url(
387 add_query_arg(
388 array(
389 'charitable_action' => 'preview_email',
390 'email_id' => $this->get_email_id(),
391 ),
392 home_url()
393 )
394 ),
395 __( 'Preview email', 'charitable' )
396 ),
397 'priority' => 18,
398 'save' => false,
399 ),
400 );
401
402 /* Add the recipients field if applicable to this email. */
403 $email_settings = $this->add_recipients_field( $email_settings );
404
405 /**
406 * Filter the settings available for this email.
407 *
408 * This filter is primarily useful for adding settings to specific email types.
409 * If you only want to add fields to all email types, use this hook instead:
410 *
411 * charitable_settings_fields_emails_email
412 *
413 * @see Charitable_Email_Settings::add_individual_email_fields
414 *
415 * @since 1.0.0
416 *
417 * @param array $email_settings Email settings.
418 */
419 return apply_filters( 'charitable_settings_fields_emails_email_' . $this->get_email_id(), $email_settings );
420 }
421
422 /**
423 * Add recipient field
424 *
425 * @since 1.0.0
426 *
427 * @param array $settings Existing array of email settings.
428 * @return array
429 */
430 public function add_recipients_field( $settings = array() ) {
431 if ( ! $this->has_recipient_field ) {
432 return $settings;
433 }
434
435 $settings['recipient'] = array(
436 'type' => 'text',
437 'title' => __( 'Recipients', 'charitable' ),
438 'help' => __( 'A comma-separated list of email address that will receive this email.', 'charitable' ),
439 'priority' => 4,
440 'class' => 'wide',
441 'default' => $this->get_default_recipient(),
442 );
443
444 return $settings;
445 }
446
447 /**
448 * Sends the email.
449 *
450 * @since 1.0.0
451 *
452 * @return boolean
453 */
454 public function send() {
455 /**
456 * Do something before sending the email.
457 *
458 * @since 1.0.0
459 *
460 * @param \Charitable_Email $email The email object.
461 */
462 do_action( 'charitable_before_send_email', $this );
463
464 $sent = wp_mail(
465 $this->get_recipient(),
466 do_shortcode( $this->get_subject() ),
467 $this->build_email(),
468 $this->get_headers(),
469 $this->get_attachments()
470 );
471
472 /**
473 * Do something after sending the email.
474 *
475 * @since 1.0.0
476 *
477 * @param \Charitable_Email $email The email object.
478 */
479 do_action( 'charitable_after_send_email', $this, $sent );
480
481 return $sent;
482 }
483
484 /**
485 * Resend an email.
486 *
487 * @since 1.5.0
488 *
489 * @param int $object_id An object ID.
490 * @param array $args Mixed set of arguments.
491 * @return boolean
492 */
493 public static function resend( $object_id, $args = array() ) {
494 charitable_get_deprecated()->doing_it_wrong(
495 __METHOD__,
496 __( 'A `resend` method has not been defined for this class.', 'charitable' ),
497 '1.5.0'
498 );
499
500 return false;
501 }
502
503 /**
504 * Checks whether an email can be resent.
505 *
506 * @since 1.5.0
507 *
508 * @param int $object_id An object ID.
509 * @param array $args Mixed set of arguments.
510 * @return boolean
511 */
512 public static function can_be_resent( $object_id, $args = array() ) {
513 charitable_get_deprecated()->doing_it_wrong(
514 __METHOD__,
515 __( 'A `can_be_resent` method has not been defined for this class.', 'charitable' ),
516 '1.5.0'
517 );
518
519 return false;
520 }
521
522 /**
523 * Checks whether the email has already been sent.
524 *
525 * @since 1.3.2
526 * @since 1.5.2 Added the $data_type parameter.
527 *
528 * @param int $object_id The ID of the object related to this email. May be a campaign ID, a donation ID or a user ID.
529 * @param string $data_type Optional. The type of meta we are saving. Defaults to 'post'.
530 * @return boolean
531 */
532 public function is_sent_already( $object_id, $data_type = 'post' ) {
533 $log = get_metadata( $data_type, $object_id, $this->get_log_key(), true );
534
535 if ( is_array( $log ) ) {
536 foreach ( $log as $time => $sent ) {
537 if ( $sent ) {
538 return true;
539 }
540 }
541 }
542
543 return false;
544 }
545
546 /**
547 * Log that the email was sent.
548 *
549 * @since 1.3.2
550 * @since 1.5.2 Added the $data_type parameter.
551 *
552 * @param int $object_id The ID of the object related to this email. May be a campaign ID, a donation ID, or a user ID.
553 * @param boolean $sent Whether the email was sent.
554 * @param string $data_type Optional. The type of meta we are saving. Defaults to 'post'.
555 * @return void
556 */
557 public function log( $object_id, $sent, $data_type = 'post' ) {
558 $log = get_metadata( $data_type, $object_id, $this->get_log_key(), true );
559
560 if ( ! $log ) {
561 $log = array();
562 }
563
564 $log[ time() ] = $sent;
565
566 update_metadata( $data_type, $object_id, $this->get_log_key(), $log );
567 }
568
569 /**
570 * Preview the email. This will display a sample email within the browser.
571 *
572 * @since 1.0.0
573 *
574 * @return string
575 */
576 public function preview() {
577 /**
578 * Do something before building the preview output.
579 *
580 * @since 1.0.0
581 *
582 * @param \Charitable_Email $this Email object.
583 */
584 do_action( 'charitable_before_preview_email', $this );
585
586 $output = $this->build_email();
587
588 /**
589 * Do something after building the preview output.
590 *
591 * @since 1.5.0
592 *
593 * @param \Charitable_Email $this Email object.
594 */
595 do_action( 'charitable_after_preview_email', $this );
596
597 return $output;
598 }
599
600 /**
601 * Returns the body content of the email, formatted as HTML.
602 *
603 * @since 1.0.0
604 *
605 * @return string
606 */
607 public function get_body() {
608 $body = $this->get_option( 'body', $this->get_default_body() );
609 $body = do_shortcode( $body );
610 $body = wpautop( $body );
611
612 /**
613 * Filter the email body before it is sent.
614 *
615 * @since 1.0.0
616 *
617 * @param string $body Body content.
618 * @param \Charitable_Email $email Instance of `Charitable_Email`.
619 */
620 return apply_filters( 'charitable_email_body', $body, $this );
621 }
622
623 /**
624 * Returns the email headline.
625 *
626 * @since 1.0.0
627 *
628 * @return string
629 */
630 public function get_headline() {
631 $headline = $this->get_option( 'headline', $this->get_default_headline() );
632 $headline = do_shortcode( $headline );
633
634 /**
635 * Filter the email headline.
636 *
637 * @since 1.0.0
638 *
639 * @param string $headline Headline.
640 * @param \Charitable_Email $email Instance of `Charitable_Email`.
641 */
642 return apply_filters( 'charitable_email_headline', $headline, $this );
643 }
644
645 /**
646 * Return the value of an option specific to this email.
647 *
648 * @since 1.0.0
649 * @since 1.6.59 Access changed to public.
650 *
651 * @param string $key Settings option key.
652 * @param mixed $default Default value to return in case setting is not set.
653 * @return mixed
654 */
655 public function get_option( $key, $default ) {
656 return charitable_get_option( array( 'emails_' . $this->get_email_id(), $key ), $default );
657 }
658
659 /**
660 * Return an array of email fields that are specifically available
661 * for this email.
662 *
663 * @since 1.5.0
664 *
665 * @return array
666 */
667 public function email_fields() {
668 return array();
669 }
670
671 /**
672 * Checks whether the email has a valid donation object set.
673 *
674 * @since 1.0.0
675 *
676 * @return boolean
677 */
678 public function has_valid_donation() {
679 if ( is_null( $this->donation ) || ! is_a( $this->donation, 'Charitable_Donation' ) ) {
680 charitable_get_deprecated()->doing_it_wrong(
681 __METHOD__,
682 __( 'You cannot send this email without a donation!', 'charitable' ),
683 '1.0.0'
684 );
685
686 return false;
687 }
688
689 return true;
690 }
691 /**
692 * Checks whether the email has a valid campaign object set.
693 *
694 * @since 1.0.0
695 *
696 * @return boolean
697 */
698 public function has_valid_campaign() {
699 if ( is_null( $this->campaign ) || ! is_a( $this->campaign, 'Charitable_Campaign' ) ) {
700 charitable_get_deprecated()->doing_it_wrong(
701 __METHOD__,
702 __( 'You cannot send this email without a campaign!', 'charitable' ),
703 '1.0.0'
704 );
705
706 return false;
707 }
708
709 return true;
710 }
711
712 /**
713 * Build the email.
714 *
715 * @since 1.0.0
716 *
717 * @return string
718 */
719 protected function build_email() {
720 ob_start();
721
722 charitable_template( 'emails/header.php', array( 'email' => $this ) );
723
724 charitable_template( 'emails/body.php', array( 'email' => $this ) );
725
726 charitable_template( 'emails/footer.php', array( 'email' => $this ) );
727
728 $message = ob_get_clean();
729
730 /**
731 * Filter the email message before it is sent.
732 *
733 * @since 1.0.0
734 *
735 * @param string $message The full email message output (header, body and footer).
736 * @param \Charitable_Email $email Instance of `Charitable_Email`.
737 */
738 return apply_filters( 'charitable_email_message', $message, $this );
739 }
740
741 /**
742 * Return the meta key used for the log.
743 *
744 * @since 1.3.2
745 *
746 * @return string
747 */
748 protected function get_log_key() {
749 return '_email_' . $this->get_email_id() . '_log';
750 }
751
752 /**
753 * Return the default recipient for the email.
754 *
755 * @since 1.0.0
756 *
757 * @return string
758 */
759 protected function get_default_recipient() {
760 return '';
761 }
762
763 /**
764 * Return the default subject line for the email.
765 *
766 * @since 1.0.0
767 *
768 * @return string
769 */
770 protected function get_default_subject() {
771 return '';
772 }
773
774 /**
775 * Return the default headline for the email.
776 *
777 * @since 1.0.0
778 *
779 * @return string
780 */
781 protected function get_default_headline() {
782 return '';
783 }
784
785 /**
786 * Return the default body for the email.
787 *
788 * @since 1.0.0
789 *
790 * @return string
791 */
792 protected function get_default_body() {
793 return '';
794 }
795
796 /**
797 * Return HTML formatted list of shortcode options that can be used within the body, headline and subject line.
798 *
799 * @since version
800 *
801 * @return string
802 */
803 protected function get_shortcode_options() {
804 $fields = new Charitable_Email_Fields( $this );
805 ob_start();
806 ?>
807 <p><?php _e( 'The following options are available with the <code>[charitable_email]</code> shortcode:', 'charitable' ) ?></p>
808 <ul>
809 <?php foreach ( $fields->get_fields() as $key => $field ) : ?>
810 <li><strong><?php echo $field['description'] ?></strong>: [charitable_email show=<?php echo $key ?>]</li>
811 <?php endforeach ?>
812 </ul>
813
814 <?php
815 $html = ob_get_clean();
816
817 /**
818 * Filter the shortcode options block.
819 *
820 * @since 1.0.0
821 *
822 * @param string $html The content.
823 * @param \Charitable_Email $email This instance of `Charitable_Email`.
824 */
825 return apply_filters( 'charitable_email_shortcode_options_text', $html, $this );
826 }
827
828 /**
829 * This function is deprecated as of 1.5.0. Checks whether the passed email is the
830 * same as the current email object.
831 *
832 * @deprecated 1.8.0
833 *
834 * @since 1.3.2
835 * @since 1.5.0 Deprecated. No notice added to allow extensions to be updated first.
836 *
837 * @param \Charitable_Email $email Email object.
838 * @return boolean
839 */
840 protected function is_current_email( Charitable_Email $email ) {
841 return $email->get_email_id() == $this->get_email_id();
842 }
843
844 /**
845 * Add donation content fields.
846 *
847 * @deprecated 1.8.0
848 *
849 * @since 1.0.0
850 * @since 1.5.0 Deprecated.
851 *
852 * @param array $fields Shortcode fields.
853 * @param Charitable_Email $email Instance of `Charitable_Email`.
854 * @return array[]
855 */
856 public function add_donation_content_fields( $fields, Charitable_Email $email ) {
857 return $fields;
858 }
859
860 /**
861 * Add donation preview fields.
862 *
863 * @deprecated 1.8.0
864 *
865 * @since 1.0.0
866 * @since 1.5.0 Deprecated.
867 *
868 * @param array $fields Shortcode fields.
869 * @param Charitable_Email $email Instance of `Charitable_Email`.
870 * @return array[]
871 */
872 public function add_preview_donation_content_fields( $fields, Charitable_Email $email ) {
873 return $fields;
874 }
875
876 /**
877 * Add campaign content fields.
878 *
879 * @deprecated 1.8.0
880 *
881 * @since 1.0.0
882 * @since 1.5.0 Deprecated.
883 *
884 * @param array $fields Shortcode fields.
885 * @param Charitable_Email $email Instance of `Charitable_Email`.
886 * @return array[]
887 */
888 public function add_campaign_content_fields( $fields, Charitable_Email $email ) {
889 return $fields;
890 }
891
892 /**
893 * Add campaign preview fields.
894 *
895 * @deprecated 1.8.0
896 *
897 * @since 1.0.0
898 * @since 1.5.0 Deprecated.
899 *
900 * @param array $fields Shortcode fields.
901 * @param Charitable_Email $email Instance of `Charitable_Email`.
902 * @return array[]
903 */
904 public function add_preview_campaign_content_fields( $fields, Charitable_Email $email ) {
905 return $fields;
906 }
907 }
908
909 endif;
910